/****************************************************************************
 *
 * Copyright(c) 2007-2009, John Forkosh Associates, Inc. All rights reserved.
 *           http://www.forkosh.com   mailto: john@forkosh.com
 * --------------------------------------------------------------------------
 * This file is part of mathTeX, which is free software. You may redistribute
 * and/or modify it under the terms of the GNU General Public License,
 * version 3 or later, as published by the Free Software Foundation.
 *      MathTeX is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY, not even the implied warranty of MERCHANTABILITY.
 * See the GNU General Public License for specific details.
 *      By using mathTeX, you warrant that you have read, understood and
 * agreed to these terms and conditions, and that you possess the legal
 * right and ability to enter into this agreement and to use mathTeX
 * in accordance with it.
 *      Your mathtex.zip distribution should contain the file COPYING,
 * an ascii text copy of the GNU General Public License, version 3.
 * If not, point your browser to  http://www.gnu.org/licenses/
 * or write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330,  Boston, MA 02111-1307 USA.
 * --------------------------------------------------------------------------
 *
 * Purpose:   o	MathTeX, licensed under the gpl, lets you easily embed
 *		LaTeX math in your html pages or blogs, wikis, bb's, etc.
 *		It submits a LaTeX math expression to latex, and
 *		immediately emits the corresponding gif image, rather than
 *		the usual TeX dvi.
 *		For example,
 *		 <img src="/cgi-bin/mathtex.cgi?\int_{-\infty}^xe^{-t^2}dt"
 *		  alt="" border=0 align=middle>
 *		immediately generates the corresponding gif image,
 *		displaying the rendered expression wherever you put
 *		that <img> tag.
 *		But there's no inherent need to repeatedly write
 *		cumbersome <img> tags as illustrated above.  You can write
 *		your own custom tags, or write a wrapper script around
 *		mathTeX to simplify the notation.
 *		See http://www.forkosh.com/mathtex.html for more information.
 *
 * Functions:	=============================================================
 *		main(argc,argv)     latex's math expression and emits gif/png
 *		mathtex(expression,filename)  create image of math expression
 *		setpaths(method)     set paths for latex,dvipng,dvips,convert
 *		isnotfound(filename)  check "... 2>.err" file for "not found"
 *		validate(expression) remove illegal \commands from expression
 *		advertisement(expression,mode)  wrap expression in ad message
 *		mathlog(expression,filename)          write entry in log file
 *		makepath(oath,name,extension)   construct path/name.extension
 *		isfexists(filename)      check whether or not filename exists
 *		isdexists(dirname)      check whether or not directory exists
 *		whichpath(program,nlocate)         determines path to command
 *		locatepath(program,nlocate) tries locate if whichpath() fails
 *		rrmdir(path)                                       rm -r path
 *		emitcache(cachefile,maxage,isbuffer) dump cachefile to stdout
 *		readcachefile(cachefile,buffer)    read cachefile into buffer
 *		crc16(s)                               16-bit crc of string s
 *		md5str(instr)                      md5 hash library functions
 *		unescape_url(url)             xlate all %xx's in url to ascii
 *		x2c(what)    xlate a single hex "xx" to equivalent ascii char
 *		timelimit(command,killtime)   throttle command after killtime
 *		getdirective(string,directive,iscase,isvalid,nargs,args) \dir
 *		mathprep(expression)           preprocessor for mathTeX input
 *		strwstr(string,substr,white,sublen)     find substr in string
 *		strreplace(string,from,to,iscase,nreplace)  change from to to
 *		strchange(nfirst,from,to)   change nfirst chars of from to to
 *		isstrstr(string,snippets,iscase)    is any snippet in string?
 *		nomath(s)          removes/replaces any LaTeX math chars in s
 *		strwrap(s,linelen,tablen)insert \n's and spaces to wrap lines
 *		strpspn(s,reject,segment) non-{[()]} chars of s not in reject
 *		strqspn(s,q,isunescape) find matching " or ' in quoted string
 *		timestamp(tzdelta,ifmt)       returns current date:time stamp
 *		tzadjust(tzdelta,year,month,day,hour)   adjust time for tzone
 *		daynumber(year,month,day)     #calendar days from Jan 1, 1973
 *		emitembedded(imagenum,isquery)  emit embedded image to stdout
 *		embeddedimages(imagenum,nbytes,imgtype)   embedded gif or png
 *
 * Source:	mathtex.c
 *
 * --------------------------------------------------------------------------
 * Notes      o	See the comment block above each function
 *		for more information about it.
 *	      o	MathTeX runs only under Unix-like operating systems.
 *		To compile mathTeX
 *		   cc mathtex.c -DLATEX=\"$(which latex)\" \
 *		   -DDVIPNG=\"$(which dvipng)\" \
 *		   -DDVIPS=\"$(which dvips)\" \
 *		   -DCONVERT=\"$(which convert)\" \
 *		   -o mathtex.cgi
 *		And see discussion of optional -D switches below.
 *		To install mathTeX
 *		   (a) mv mathtex.cgi to your cgi-bin/ directory
 *		       and chmod its permissions as necessary
 *		   (b) mkdir cgi-bin/mathtex  which is the cache directory
 *		       and chmod its permissions so mathtex.cgi can rw it.
 *		See http://www.forkosh.com/mathtex.html for more information.
 *	      o	The timelimit() code is adapted from
 *		   http://devel.ringlet.net/sysutils/timelimit/
 *		Compile with -DTIMELIMIT=\"$(which timelimit)\" to use an
 *		installed copy of that program rather than the built-in code.
 *	      o	Some program parameters adjustable by optional -D switches on
 *		mathTeX's compile line are illustrated with default values...
 *		-DLATEX=\"/usr/share/texmf/bin/latex\"  path to LaTeX program
 *		-DDVIPNG=\"/usr/share/texmf/bin/dvipng\"dvipng(same as latex)
 *		-DDVIPS=\"/usr/share/texmf/bin/dvips\"  dvips (same as latex)
 *		-DCONVERT=\"/usr/bin/convert\"     path to convert executable
 *		-DCACHE=\"mathtex/\"     relative path to mathTeX's cache dir
 *		-DTIMELIMIT=\"/usr/local/bin/timelimit\"    path to timelimit
 *		-WARNTIME=10   #secs latex can run using standalone timelimit
 *		-KILLTIME=10   #secs latex can run using built-in timelimit()
 *		-DGIF                                         emit gif images
 *		-DPNG                                         emit png images
 *		-DDISPLAYSTYLE                            \[ \displaystyle \]
 *		-DTEXTSTYLE                                    $ \textstyle $
 *		-DPARSTYLE       paragraph mode, supply your own $ $ or \[ \]
 *		-DFONTSIZE=5           1=\tiny,...,5=\normalsize,...,10=\Huge
 *		-DUSEPACKAGE=\"filename\"       file containing \usepackage's
 *		-DNEWCOMMAND=\"filename\"       file containing \newcommand's
 *		-DDPI=\"120\"        dvipng -D DPI  parameter (as \"string\")
 *		-DGAMMA=\"2.5\"   dvipng --gamma GAMMA  param (as \"string\")
 *		-DNOQUIET     -halt-on-error (default reply q(uiet) to error)
 *		-DTEXTAREANAME=\"formdata\"   <textarea name=...> in a <form>
 *		-DREFERER=\"\"         comma-separated list of valid referers
 *		-DMAXINVALID=0     max length expression from invalid referer
 *		-DADFREQUENCY=0  one request out of n displayed along with ad
 *		-DADVERTISEMENT=\"filename\"      file containing ad template
 *		See http://www.forkosh.com/mathtex.html for more information.
 *
 * --------------------------------------------------------------------------
 * Revision History:
 * See http://www.forkosh.com/mathtexchangelog.html for more information.
 * 10/11/07	J.Forkosh	Installation Version 1.00.
 * 02/17/08	J.Forkosh	Version 1.01
 * 03/06/09	J.Forkosh	Version 1.02
 * 08/14/09	J.Forkosh	Version 1.03
 *
 ****************************************************************************/

/* -------------------------------------------------------------------------
Standard header files
-------------------------------------------------------------------------- */
/* ---
 * standard headers
 * ---------------- */
#include <stdio.h>
#include <stdlib.h>
#define _GNU_SOURCE
#include <string.h>
char	*strcasestr();			/* non-standard extension */
#include <ctype.h>
#include <time.h>
extern	char **environ;			/* for \environment directive */

/* -------------------------------------------------------------------------
Information adjustable by -D switches on compile line
-------------------------------------------------------------------------- */
/* ---
 * executable paths (e.g., path/latex including filename of executable image)
 * ----------------------------------------------------------------------- */
/* --- determine which switches have been explicitly specified --- */
#if defined(LATEX)
  #define ISLATEXSWITCH 1		/* have -DLATEX=\"path/latex\" */
#else
  #define ISLATEXSWITCH 0		/* no -DLATEX switch */
  #define LATEX "/usr/share/texmf/bin/latex" /* default path to latex */
#endif
#if defined(DVIPNG)
  #define ISDVIPNGSWITCH 1		/* have -DDVIPNG=\"path/dvipng\" */
#else
  #define ISDVIPNGSWITCH 0		/* no -DDVIPNG switch */
  #define DVIPNG "/usr/share/texmf/bin/dvipng"/* default path to dvipng */
#endif
#if defined(DVIPS)
  #define ISDVIPSSWITCH 1		/* have -DDVIPS=\"path/dvips\" */
#else
  #define ISDVIPSSWITCH 0		/* no -DDVIPS switch */
  #define DVIPS "/usr/share/texmf/bin/dvips" /* default path to dvips */
#endif
#if defined(CONVERT)
  #define ISCONVERTSWITCH 1		/* have -DCONVERT=\"path/convert\" */
#else
  #define ISCONVERTSWITCH 0		/* no -DCONVERT switch */
  #define CONVERT "/usr/bin/convert"	/* default path to convert */
#endif
#if defined(TIMELIMIT)
  #define ISTIMELIMITSWITCH 1	    /* have -DTIMELIMIT=\"path/timelimit\" */
#else
  #define ISTIMELIMITSWITCH 0		/* no -DTIMELIMIT switch */
  #define TIMELIMIT "/usr/local/bin/timelimit" /* default path to timelimit*/
#endif
/* --- paths, as specified by -D switches, else from whichpath() --- */
static	char latexpath[256] = LATEX,  dvipngpath[256] = DVIPNG,
 	dvipspath[256] = DVIPS,  convertpath[256] = CONVERT,
	timelimitpath[256] = TIMELIMIT;
/* --- source of path info: 0=default, 1=switch, 2=which, 3=locate --- */
static	int  islatexpath=ISLATEXSWITCH, isdvipngpath=ISDVIPNGSWITCH,
	isdvipspath=ISDVIPSSWITCH, isconvertpath=ISCONVERTSWITCH,
	istimelimitpath=ISTIMELIMITSWITCH;
/* ---
 * cache path -DCACHE=\"path/\" specifies directory
 * ------------------------------------------------ */
#if !defined(CACHE)
  #define CACHE "mathtex/"		/* relative to mathtex.cgi */
#endif
#if !defined(CACHELOG)
  #define CACHELOG "mathtex.log"	/* default cache log file */
#endif
#define	MAXAGE 7200			/* maxage in cache is 7200 secs */
static	int  iscaching = 1;		/* true if caching images */
static	char cachepath[256] = CACHE;	/* path to cached image files */
/* ---
 * image method info specifying dvipng or dvips/convert
 * use dvipng if -DDVIPNG supplied (or -DDVIPNGMETHOD specified),
 * else use dvips/convert if -DDVIPS supplied (or -DDVIPSMETHOD specified)
 * ----------------------------------------------------------------------- */
#if    defined(DVIPNGMETHOD) || ISDVIPNGSWITCH==1
  #define IMAGEMETHOD 1
#elif  defined(DVIPSMETHOD)  || (ISDVIPSSWITCH==1 && ISDVIPNGSWITCH==0)
  #define IMAGEMETHOD 2
#elif !defined(IMAGEMETHOD)
  #define IMAGEMETHOD 1
#endif
static	int  imagemethod = IMAGEMETHOD;	/* 1=dvipng, 2=dvips/convert */
/* ---
 * image type info specifying gif, png
 * ----------------------------------- */
#if defined(GIF)
  #define IMAGETYPE 1
#endif
#if defined(PNG)
  #define IMAGETYPE 2
#endif
#if !defined(IMAGETYPE)
  #define IMAGETYPE 1
#endif
static	int  imagetype = IMAGETYPE;	/* 1=gif, 2=png */
static	char *extensions[] = { NULL,	/* image type file .extensions */
  "gif", "png", NULL };
/* ---
 * \[ \displaystyle \]  or  $ \textstyle $  or  \parstyle
 * ------------------------------------------------------ */
#if defined(DISPLAYSTYLE)
  #define MATHMODE 0
#endif
#if defined(TEXTSTYLE)
  #define MATHMODE 1
#endif
#if defined(PARSTYLE)
  #define MATHMODE 2
#endif
#if !defined(MATHMODE)
  #define MATHMODE 0
#endif
static	int  mathmode = MATHMODE; /* 0=display 1=text 2=paragraph */
/* ---
 * font size info 1=\tiny ... 10=\Huge
 * ----------------------------------- */
#if !defined(FONTSIZE)
  #define FONTSIZE 5
#endif
static	int  fontsize = FONTSIZE;	/* 1=tiny ... 10=Huge */
static	char *sizedirectives[] = { NULL, /* fontsize directives */
  "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
  "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge", NULL };
/* ---
 * dpi/density info for dvipng/convert
 * ----------------------------------- */
#if !defined(DPI)
  #define DPI "120"
#endif
static	char density[256] = DPI;	/*-D/-density arg for dvipng/convert*/
/* ---
 * default -gamma for convert is 0.5, or --gamma for dvipng is 2.5
 * --------------------------------------------------------------- */
#define	DVIPNGGAMMA "2.5"		/* default gamma for dvipng */
#define	CONVERTGAMMA "0.5"		/* default gamma for convert */
#if !defined(GAMMA)
  #define ISGAMMA 0			/* no -DGAMMA=\"gamma\" switch */
  #if IMAGEMETHOD == 1			/* for dvipng... */
    #define GAMMA DVIPNGGAMMA		/* ...default gamma is 2.5 */
  #elif IMAGEMETHOD == 2		/* for convert... */
    #define GAMMA CONVERTGAMMA		/* ...default gamma is 0.5 */
  #else					/* otherwise... */
    #define GAMMA "1.0"			/* ...default gamma is 1.0 */
  #endif
#else
  #define ISGAMMA 1			/* -DGAMMA=\"gamma\" supplied */
#endif
static	char gamma[256] = GAMMA;	/* -gamma arg for convert() */
/* ---
 * latex -halt-on-error or quiet
 * ----------------------------- */
#if defined(QUIET)
  #define ISQUIET 99999			/* reply q */
#elif  defined(NOQUIET)
  #define ISQUIET 0			/* reply x (-halt-on-error) */
#elif  defined(NQUIET)
  #define ISQUIET NQUIET		/* reply NQUIET <Enter>'s then x */
#else
  #define ISQUIET 3			/* default reply 3 <Enter>'s then x*/
#endif
static	int  isquiet = ISQUIET;		/* >99=quiet, 0=-halt-on-error */
/* ---
 * timelimit -tWARNTIME -TKILLTIME
 * ------------------------------- */
#if !defined(KILLTIME)			/* no -DKILLTIME given... */
  #define NOKILLTIMESWITCH		/* ...remember that fact below */
  #if ISTIMELIMITSWITCH == 0		/* standalone timelimit disabled */
    #if defined(WARNTIME)		/* have WARNTIME but not KILLTIME */
      #define KILLTIME (WARNTIME)	/* so use WARNTIME for KILLTIME */
    #else				/* neither WARNTIME nor KILLTIME */
      #define KILLTIME (10)		/* default for built-in timelimit()*/
      /*#define KILLTIME (0)*/		/* disable until debugged */
    #endif
  #else					/* using standalone timelimit */
    #define KILLTIME (1)		/* always default -T1 killtime */
  #endif
#endif
#if !defined(WARNTIME)			/*no -DWARNTIME given for timelimit*/
  #if ISTIMELIMITSWITCH == 0		/* and no -DTIMELIMIT path either */
    #define WARNTIME (-1)		/* so standalone timelimit disabled*/
  #else					/*have path to standalone timelimit*/
    #if !defined(NOKILLTIMESWITCH)	/* have KILLTIME but not WARNTIME */
      #define WARNTIME (KILLTIME)	/* so use KILLTIME for WARNTIME */
      #undef  KILLTIME			/* but not for standalone killtime */
      #define KILLTIME (1)		/* default -T1 killtime instead */
    #else				/* neither KILLTIME nor WARNTIME */
      #define WARNTIME (10)		/* so default -t10 warntime */
    #endif
  #endif
#endif
static	int  warntime=WARNTIME, killtime=KILLTIME; /* -twarn -Tkill values */
/* ---
 * compile (or not) built-in timelimit() code
 * ------------------------------------------ */
#if ISTIMELIMITSWITCH==0 && KILLTIME>0	/*no -DTIMELIMIT, but have KILLTIME*/
  #define ISCOMPILETIMELIMIT 1		/* so we need built-in code */
#else
  #define ISCOMPILETIMELIMIT 0		/* else we don't need built-in code*/
#endif
static	int  iscompiletimelimit=ISCOMPILETIMELIMIT; /* 1=use timelimit() */
#if ISCOMPILETIMELIMIT			/*header files, etc for timelimit()*/
  /* --- header files for timelimit() --- */
  #include <sys/signal.h>
  #include <sys/wait.h>
  #include <unistd.h>
  #include <signal.h>
  #include <sysexits.h>
  /*#define EX_OSERR	71*/		/* system error (e.g., can't fork) */
  #define HAVE_SIGACTION
  /* --- global variables for timelimit() --- */
  volatile int	fdone, falarm, fsig, sigcaught;
#endif
/* ---
 * additional latex \usepackage{}'s
 * -------------------------------- */
static	int  npackages = 0;		/* number of additional packages */
static	char packages[9][128];		/* additional package names */
static	char packargs[9][128];		/* optional arg for package */
/* ---
 * <textarea name=TEXTAREANAME ...> in a <form>
 * -------------------------------------------- */
#if !defined(TEXTAREANAME)
  #define TEXTAREANAME "formdata"
#endif
/* ---
 * comma-separated list of HTTP_REFERER's allowed/denied to use mathTeX
 * -------------------------------------------------------------------- */
#if !defined(REFERER)
  #define REFERER "\000"
#endif
#if !defined(DENYREFERER)
  #define DENYREFERER "\000"
#endif
#if !defined(MAXINVALID)		/* longest length expression */
  #define MAXINVALID 0			/* from an invalid referer */
#endif					/* that will be rendered w/o error */
/* ---
 * time zone delta t (in hours)
 * ---------------------------- */
#if !defined(TZDELTA)
  #define TZDELTA 0
#endif
/* ---
 * default uses locatepath() if whichpath() fails
 * ---------------------------------------------- */
#if !defined(NOWHICH)
  #define ISWHICH 1
#else
  #define ISWHICH 0
#endif
#if !defined(NOLOCATE)
  #define ISLOCATE 1
#else
  #define ISLOCATE 0
#endif
/* ---
 * one image in every ADFREQUENCY will be wrapped inside "advertisement"
 * --------------------------------------------------------------------- */
#if !defined(ADFREQUENCY)
  #define ADFREQUENCY 0			/* never show advertisement if 0 */
#endif
static	int  adfrequency = ADFREQUENCY;	/* advertisement frequency */
/* ---
 * debugging and error reporting
 * ----------------------------- */
#if !defined(MSGLEVEL)
  #define MSGLEVEL 1
#endif
#if !defined(MAXMSGLEVEL)
  #define MAXMSGLEVEL 999999
#endif
static	int  msglevel = MSGLEVEL;	/* message level for verbose/debug */
static	FILE *msgfp = NULL;		/* output in command-line mode */
char	*strwrap();			/* help format debugging messages */
#define	showmsg(showlevel,label,data)	/* default message format */ \
	if ( msgfp!=NULL && msglevel>=(showlevel) ) { \
	  fprintf(msgfp,(strlen(label)+strlen(data)<64? \
	  "\nmathTeX> %s: %s\n" : "\nmathTeX> %s:\n         %s\n"), \
	  (label),strwrap((data),64,-9)); fflush(msgfp); } else
static	int  msgnumber = 0;		/* embeddedimages() in query mode */
#define	MAXEMBEDDED 15			/* 1...#embedded images available */
#define	TESTMESSAGE 1			/* msg# for mathTeX test message */
#define	UNKNOWNERROR 2			/* msg# for non-specific error */
#define	CACHEFAILED 3			/* msg# if mkdir cache failed */
#define	MKDIRFAILED 4			/* msg# if mkdir tempdir failed */
#define	CHDIRFAILED 5			/* msg# if chdir tempdir failed */
#define	FOPENFAILED 6			/* msg# if fopen(latex.tex) failed */
#define	SYLTXFAILED 7			/* msg# if system(latex) failed */
#define	LATEXFAILED 8			/* msg# if latex failed */
#define	SYPNGFAILED 9			/* msg# if system(dvipng) failed */
#define	DVIPNGFAILED 10			/* msg# if dvipng failed */
#define	SYPSFAILED 11			/* msg# if system(dvips) failed */
#define	DVIPSFAILED 12			/* msg# if dvips failed */
#define	SYCVTFAILED 13			/* msg# if system(convert) failed */
#define	CONVERTFAILED 14		/* msg# if convert failed */
#define	EMITFAILED 15			/* msg# if emitcache() failed */
static	char *embeddedtext[] = { NULL,	/* text of embedded image messages */
  "(1) mathTeX test message:\\"		/* msg#1 mathTeX "okay" test */
  "cgi program running okay.",
  "(2) mathTeX failed: probably due to\\" /* msg#2 general error message */
  "bad paths, permissions, or installation.",
  "(3) Can't mkdir cgi-bin/mathtex/\\"	/* msg#3 can't create cache dir */
  "cache directory: check permissions.",
  "(4) Can't mkdir cgi-bin/tempnam/\\"	/* msg#4 */
  "work directory: check permissions.",
  "(5) Can't cd cgi-bin/tempnam/\\"	/* msg#5 */
  "work directory: check permissions.",
  "(6) Can't fopen(\"latex.tex\") file:\\" /* msg#6 */
  "check permissions.",
  "(7) Can't run latex program:\\"	/* msg#7 */
  "check -DLATEX=\"path\", etc.",
  "(8) latex ran but failed:\\"		/* msg#8 */
  "check your input expression.",
  "(9) Can't run dvipng program:\\"	/* msg#9 */
  "check -DDVIPNG=\"path\", etc.",
  "(10) dvipng ran but failed:",	/* msg#10 */
  "(11) Can't run dvips program:\\"	/* msg#11 */
  "check -DDVIPS=\"path\", etc.",
  "(12) dvips ran but failed:",		/* msg#12 */
  "(13) Can't run convert program:\\"	/* msg#13 */
  "check -DCONVERT=\"path\", etc.",
  "(14) convert ran but failed:",	/* msg#14 */
  "(15) Can't emit cached image:\\"	/* msg#15 */
  "check permissions.",
  NULL } ; /* --- end-of-*embeddedtext[] --- */
/* ---
 * output file (from shell mode)
 * ----------------------------- */
static	char outfile[256] = "\000";	/* output file, or empty for default*/
/* ---
 * temporary work directory
 * ------------------------ */
static	char tempdir[256] = "\000";	/* temporary work directory */
/* ---
 * internal buffer sizes
 * --------------------- */
#if !defined(MAXEXPRSZ)
  #define MAXEXPRSZ (32767)		/*max #bytes in input tex expression*/
#endif
#if !defined(MAXGIFSZ)
  #define MAXGIFSZ (131072)		/* max #bytes in output GIF image */
#endif

/* -------------------------------------------------------------------------
Unix or Windows header files
-------------------------------------------------------------------------- */
/* ---
 * compiling under Windows if -DWINDOWS explicitly supplied or...
 * -------------------------------------------------------------- */
#if !defined(WINDOWS)		/* -DWINDOWS not explicitly given by user */
  #if defined(_WINDOWS) || defined(_WIN32) || defined(WIN32) \
  ||  defined(DJGPP)		/* try to recognize windows compilers */ \
  ||  defined(_USRDLL)		/* must be WINDOWS if compiling for DLL */
    #define WINDOWS		/* signal windows */
  #endif
#endif
/* ---
 * unix headers
 * ------------ */
#if !defined(WINDOWS)		/* if not compiling under Windows... */
  #include <unistd.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <dirent.h>
#endif
/* ---
 * windows-specific header info
 * ---------------------------- */
#if defined(WINDOWS)		/* Windows opens stdout in char mode, and */
  #include <fcntl.h>		/* precedes every 0x0A with spurious 0x0D.*/
  #include <io.h>		/* So emitcache() issues a Win _setmode() */
				/* call to put stdout in binary mode. */
  #if defined(_O_BINARY) && !defined(O_BINARY)  /* only have _O_BINARY */
    #define O_BINARY _O_BINARY	/* make O_BINARY available, etc... */
    #define setmode  _setmode
    #define fileno   _fileno
  #endif
  #if defined(_O_BINARY) || defined(O_BINARY)  /* setmode() now available */
    #define HAVE_SETMODE	/* so we'll use setmode() */
  #endif
#endif
static	int iswindows =		/* 1 if running under Windows, or 0 if not */
  #ifdef WINDOWS
    1;				/* 1 when program running under Windows */
  #else
    0;				/* 0 when not running under Windows */
  #endif

/* -------------------------------------------------------------------------
application macros
-------------------------------------------------------------------------- */
/* --- check if a string is empty --- */
#define	isempty(s)  ((s)==NULL?1:(*(s)=='\000'?1:0))
/* --- last char of a string --- */
#define	lastchar(s) (isempty(s)?'\000':*((s)+(strlen(s)-1)))
/* --- check for thischar in accept --- */
#define	isthischar(thischar,accept) \
	( (thischar)!='\000' && !isempty(accept) \
	&& strchr((accept),(thischar))!=(char *)NULL )
/* --- skip/find whitespace --- */
#define	WHITESPACE  " \t\n\r\f\v"	/* skipped whitespace chars */
#define	skipwhite(thisstr)  if ( (thisstr) != NULL ) \
	thisstr += strspn(thisstr,WHITESPACE)
#define	findwhite(thisstr)  while ( !isempty(thisstr) ) \
	if ( isthischar(*(thisstr),WHITESPACE) ) break; else (thisstr)++
	/* thisstr += strcspn(thisstr,WHITESPACE) */
/* --- skip \command (i.e., find char past last char of \command) --- */
#define	skipcommand(thisstr)  while ( !isempty(thisstr) ) \
	if ( !isalpha(*(thisstr)) ) break; else (thisstr)++
/* --- strip leading and trailing whitespace --- */
#define	trimwhite(thisstr) if ( (thisstr) != NULL ) { \
	int thislen = strlen(thisstr); \
	while ( --thislen >= 0 ) \
	  if ( isthischar((thisstr)[thislen],WHITESPACE) ) \
	    (thisstr)[thislen] = '\000'; \
	  else break; \
	if ( (thislen = strspn((thisstr),WHITESPACE)) > 0 ) \
	  strcpy((thisstr),(thisstr)+thislen); } else
/* --- strncpy() n bytes and make sure it's null-terminated --- */
#define	strninit(target,source,n) if( (target)!=NULL && (n)>=0 ) { \
	  char *thissource = (source); \
	  (target)[0] = '\000'; \
	  if ( (n)>0 && thissource!=NULL ) { \
	    strncpy((target),thissource,(n)); \
	    (target)[(n)] = '\000'; } }
/* --- min and max of args --- */
#define	max2(x,y)  ((x)>(y)? (x):(y))	/* larger of 2 arguments */
#define	min2(x,y)  ((x)<(y)? (x):(y))	/* smaller of 2 arguments */

/* -------------------------------------------------------------------------
other application global data
-------------------------------------------------------------------------- */
/* --- getdirective() global data --- */
static	int  argformat   = 0;		/* 111... if arg not {}-enclosed */
static	int  optionalpos = 0;		/* # {args} before optional [args] */
static	int  noptional   = 0;		/* # optional [args] found */
static	char optionalargs[8][512] =	/* buffer for optional args */
  { "\000", "\000", "\000", "\000", "\000", "\000", "\000", "\000" };


/* ==========================================================================
 * Function:	main ( argc, argv )
 * Purpose:	driver for mathtex.c
 *		emits, usually to stdout, a gif or png image
 *		of a LaTeX math expression entered either as
 *		    (1)	html query string from a browser (most typical), or
 *		    (2)	a query string from an html <form method="get">
 *			whose <textarea name=TEXTAREANAME>
 *			(usually for demo), or
 *		    (3)	command-line arguments (usually just to test).
 *		If no input supplied, expression defaults to "f(x)=x^2",
 *		treated as test (input method 3).
 * --------------------------------------------------------------------------
 * Command-Line Arguments:
 *		When running mathTeX from the command-line, rather than
 *		from a browser (usually just for testing), syntax is
 *		     ./mathtex	[-m msglevel]	verbosity of debugging output
 *				[-c cachepath ]	name of cache directory
 *				[expression	expression, e.g., x^2+y^2,
 *		-m   0-99, controls verbosity level for debugging output
 *		     >=9 retains all directories and files created
 *		-c   cachepath specifies relative path to cache directory
 * --------------------------------------------------------------------------
 * Exits:	0=success (always exits 0, regardless of success/failure)
 * --------------------------------------------------------------------------
 * Notes:     o For an executable that emits gif images
 *		     cc mathtex.c -o mathtex.cgi
 *		or, alternatively, for an executable that emits png images
 *		     cc -DPNG mathtex.c -o mathtex.cgi
 *		See Notes at top of file for other compile-line -D options.
 *	      o	Move executable to your cgi-bin directory and either
 *		point your browser to it directly in the form
 *		     http://www.yourdomain.com/cgi-bin/mathtex.cgi?f(x)=x^2
 *		or put a tag in your html document of the form
 *		     <img src="/cgi-bin/mathtex.cgi?f(x)=x^2"
 *		       border=0 align=middle>
 *		where f(x)=x^2 (or any other expression) will be displayed
 *		either as a gif or png image (as per -DIMAGETYPE flag).
 * ======================================================================= */
/* --- entry point --- */
int	main ( int argc, char *argv[] )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
/* --- expression to be emitted --- */
static	char exprbuffer[MAXEXPRSZ+1] = "\000"; /* input TeX expression */
char	hashexpr[MAXEXPRSZ+1] = "\000";	/* usually use md5 of original expr*/
char	*expression = exprbuffer;	/* ptr to expression */
char	*query = getenv("QUERY_STRING"); /* getenv("QUERY_STRING") result */
int	isquery = 0;			/* true if input from QUERY_STRING */
/* --- preprocess expression for special mathTeX directives, etc --- */
char	*mathprep();			/* preprocess expression */
int	unescape_url();			/* convert %20 to blank space, etc */
int	strreplace(), irep=0;		/* look for keywords in expression */
char	*strchange();			/* edit expression */
char	*getdirective(), argstring[256]; /* look for \density, \usepackage */
int	validate();			/* remove \input, etc */
int	advertisement(), crc16();	/*wrap expression in advertisement*/
char	*adtemplate = NULL;		/* usually use default message */
char	*nomath();			/* remove math chars from string */
/* --- referer initialization variables --- */
char	*http_referer = getenv("HTTP_REFERER"); /* referer using mathTeX */
int	isvalidreferer = 1;		/* can this referer use mathTeX? */
struct	{ char *deny;			/* http_referer can't contain this */
	int msgnumber; }		/* emit invalid_referer_msg[msg#] */
	htaccess[] = {			/* ".htaccess" table for deny */
	#ifdef HTACCESS			/* eg, -DHTACCESS=\"htaccess.txt\" */
	  #include HTACCESS		/* eg,  {"",1},  for no referer */
	#endif
	{ NULL, -999 } };		/* trailer */
/* --- other initialization variables --- */
char	*whichpath();			/* look for latex,dvipng,etc */
int	setpaths();			/* set paths to latex,dvipng,etc */
int	isstrstr();			/* find any snippet in string */
int	isdexists();			/* check whether cache dir exists */
int	perm_all = (S_IRWXU|S_IRWXG|S_IRWXO); /* 777 permissions */
int	readcachefile(), nbytes=0;	/*read expr for -f command-line arg*/
char	*timestamp();			/*for \time (in addition to \today)*/
int	emitembedded();			/* in case latex can't run */
int	timelimit();			/* just to check stub or built-in */
int	iscolorpackage = 0;		/* true if \usepackage{color} found*/
/* --- image rendering --- */
int	mathtex();			/* generate new image using LaTeX */
/* --- image caching --- */
int	emitcache();			/* emit cached image if it exists */
int	maxage = MAXAGE;		/* max-age is typically two hours */
char	*makepath();			/* construct full path/filename.ext*/
char	*md5str(), *md5hash=NULL;	/* md5 has of expression */
int	mathlog();			/* log requests */
/* --- messages --- */
char	*copyright1 =			/* copyright, gnu/gpl notice */
 "+-----------------------------------------------------------------------+\n"
 "|mathTeX vers 1.03, Copyright(c) 2007-2009, John Forkosh Associates, Inc|\n"
 "+-----------------------------------------------------------------------+\n"
 "| mathTeX is free software, licensed to you under terms of the GNU/GPL  |\n"
 "|           and comes with absolutely no warranty whatsoever.           |\n",
 *copyright2 =				/* second part of copyright */
 "|     See http://www.forkosh.com/mathtex.html for complete details.     |\n"
 "+-----------------------------------------------------------------------+";
char	*usage1 =			/* usage instructions */
 "Command-line Usage:\n"
 "  ./mathtex.cgi \"expression\"     expression, e.g., \"x^2+y^2\"\n"
 "            | -f input_file      or read expression from input_file\n"
 "            [ -o output_file ]   write image to ouput_file\n"
 "            [ -m msglevel ]      verbosity / message level\n"
 "            [ -c cache ]         path to cache directory\n",
 *usage2 =				/* second part of usage */
 "Example:\n"
 "  ./mathtex.cgi \"x^2+y^2\" -o equation1\n"
 "creates equation1.gif containing image of x^2+y^2\n";
char	*versiontemplate =		/* mathTeX version "adtemplate" */
 "\\begin{center}\n"
 "\\fbox{\\footnotesize mathTeX version 1.03}\\\\ \\vspace*{-.2in}"
 "%%beginmath%% %%expression%% %%endmath%%\n"
 "\\end{center}\n";
char	whichtemplate[512] =		/* mathTeX which "adtemplate" */
 "\\begin{center}\n"
 "\\fbox{\\footnotesize %%whichpath%%}\\\\ \\vspace*{-.2in}"
 "%%beginmath%% %%expression%% %%endmath%%\n"
 "\\end{center}\n";
int	maxinvalidmsg = 2;		/* max invalid_referer_msg[] index */
char	*invalid_referer_msg[] = {	/* invalid referer messages */
 /* --- message#0 (default invalid_referer message) --- */
 "\\parstyle\\usepackage{color}\\small\\color{red}\\noindent "
 "\\fbox{$\\mbox{\\textbf{%%referer%%}}\\atop "
 "\\mbox{\\textbf{is not authorized to use mathTeX on this server}}$}",
 /* --- message#1 ("provide http_referer" message) --- */
 "\\parstyle\\usepackage{color}\\small\\color{red}\\noindent "
 "\\fbox{$\\mbox{\\textbf{To use the public math\\TeX{} server,}}\\atop "
 "\\mbox{\\textbf{please provide your HTTP\\_REFERER}}$}",
 /* --- message#2 ("production use" message) --- */
 "\\parstyle\\usepackage{color}\\small\\color{red}\\noindent "
 "\\fbox{$\\mbox{\\textbf{For production use, please install mathtex.cgi on}}\\atop "
 "\\mbox{\\textbf{your own server.  See www.forkosh.com/mathtex.html}}$}",
 /* --- end-of-table trailer --- */
 NULL } ; /* --- end-of-invalid_referer_msg[] --- */
/* -------------------------------------------------------------------------
Initialization
-------------------------------------------------------------------------- */
/* --- set global variables --- */
msgfp = NULL;				/* for query mode output */
msgnumber = 0;				/* no errors to report yet */
if ( imagetype < 1 || imagetype > 2 ) imagetype = 1;   /* keep in bounds */
if ( imagemethod<1 || imagemethod>2 ) imagemethod = 1; /* keep in bounds */
/* ---
 * check QUERY_STRING query for expression
 * --------------------------------------- */
if ( query != NULL )			/* check query string from environ */
  if ( strlen(query) >= 1 )		/* caller gave us a query string */
    { strninit(expression,query,MAXEXPRSZ); /* so use it as expression */
      isquery = 1; }			/* and set isquery flag */
if ( !isquery )				/* empty query string */
  { char *host = getenv("HTTP_HOST"),	/* additional getenv("") results */
    *name = getenv("SERVER_NAME"), *addr = getenv("SERVER_ADDR");
    if ( host!=NULL || name!=NULL || addr!=NULL ) /* assume http query */
      {	isquery = 1;			/* set flag to signal query */
	strcpy(expression,"\\fbox{\\rm No expression supplied}"); }
  } /* --- end-of-if(!isquery) --- */
/* ---
 * process command-line args (only if not a query)
 * ----------------------------------------------- */
if ( !isquery				/* don't have an html query string */
/*&&   argc>1*/ ) {			/* and have command-line args */
  int	argnum = 0;			/*argv[] index for command-line args*/
  int	isendofswitches = 0;		/* -- arg signals no more -switches */
  msglevel = 3;				/*adjust minimum shell message level*/
  msgfp = stdout;			/* for comamnd-line mode output */
  while ( argc > ++argnum ) {		/*check for switches and expression*/
    if ( *argv[argnum] == '-'		/* have some -switch */
    &&   !isendofswitches ) {		/* and haven't seen a -- arg yet*/
      char *field = argv[argnum] + 1;	/* ptr to char(s) following - */
      char flag = tolower((int)(*field)); /* single char following - */
      field++;				/* bump past flag */
      trimwhite(field);			/*remove leading/trailing whitespace*/
      if ( isempty(field) ) {		/* no chars after -flag char, so */
        if ( flag == '-' )		/* have -- arg, so */
          isendofswitches = 1;		/* signal no more -switches */
        else				/* have a single char flag, so */
          field = argv[++argnum]; }	/* arg following flag is its value */
      switch ( flag ) {			/* see what user wants to tell us */
	/* --- unrecognized -switch flag --- */
	default: /*argnum--;*/  break;
	/* --- interpret recognized flags --- */
	case 'c': strcpy(cachepath,field);
		if ( strlen(cachepath) < 1  /* path is an empty string */
		||   strcmp(cachepath,"none") == 0 )  /* or keyword "none" */
		  iscaching = 0;	/* so disable caching */
		break;
	case 'm': msglevel = atoi(field);   break;
	case 'f': nbytes = readcachefile(field,(unsigned char *)exprbuffer);
	        exprbuffer[nbytes] = '\000'; /* null-terminate expression */
		if ( !isempty(outfile) ) break; /* default to same outfile */
	case 'o': strcpy(outfile,field); /* output file for image */
	        trimwhite(outfile);	/*remove leading/trailing whitespace*/
	        break;
	} /* --- end-of-switch(flag) --- */
      } /* --- end-of-if(*argv[argnum]=='-') --- */
    else				/* expression if arg not a -flag */
      strcpy(exprbuffer,argv[argnum]);	/* take last unswitched arg */
    } /* --- end-of-while(argc>++argnum) --- */
  if ( isempty(expression) ) {		/*no expression, show usage and quit*/
    if ( msgfp!=NULL && msglevel>=3 )	/* user needs usage instructions */
      fprintf(msgfp,"%s%s\n%s%s\n",copyright1,copyright2, /*show copyright*/
      usage1,usage2);			/* and show usage */
    goto end_of_job; }			/* quit */
  } /* --- end-of-if(!isquery) --- */
/* ---
 * pre-process expression
 * ---------------------- */
if ( !isempty(TEXTAREANAME) )		/* if <form>'s are allowed */
 if ( isquery )				/*check for <form> on query strings*/
  if(memcmp(expression,TEXTAREANAME,strlen(TEXTAREANAME))==0) { /*have form*/
    char *delim = strchr(expression,'='); /* find = following TEXTAREANAME */
    if ( delim != (char *)NULL )	/* found unescaped equal sign */
      strcpy(expression,delim+1);	/* shift name= out of expression */
    while ( (delim=strchr(expression,'+')) != NULL ) /*unescaped plus sign*/
      *delim = ' ';			/* is "shorthand" for blank space */
    unescape_url(expression);		/*convert %20, etc (twice for form)*/
    } /* --- end-of-if(memcmp()==0) --- */
unescape_url(expression);		/* convert %20 to blank space, etc */
mathprep(expression);			/* convert &lt; to <, etc */
validate(expression);			/* remove \input, etc */
/* ---
 * check if this http_referer is allowed to use mathTeX
 * ---------------------------------------------------- */
msgnumber = 0;				/* default invalid message number */
/* --- see if user fails to match -DREFERER list of valid domains --- */
if ( isquery )				/* not relevant if in command mode */
  if ( !isempty(REFERER) )		/* nor if compiled w/o -DREFERER= */
    if ( !isstrstr(http_referer,REFERER,0) ) /* invalid http_referer */
      isvalidreferer = 0;		/* signal invalid referer */
/* --- see if user matches -DDENYREFERER list of invalid domains --- */
if ( isquery )				/* not relevant if in command mode */
  if ( isvalidreferer )			/* or if alteady invalid */
    if ( !isempty(DENYREFERER) )	/*nor if compiled w/o -DDENYREFERER*/
      if ( isstrstr(http_referer,DENYREFERER,0) ) /* invalid http_referer */
        isvalidreferer = 0;		/* signal invalid referer */
/* --- see if user matches -DHTACCESS list of invalid domains --- */
if ( isquery )				/* not relevant if in command mode */
  if ( isvalidreferer ) {		/* or if alteady invalid */
    int	iaccess=0;			/* htaccess[] index */
    msgnumber = (-999);			/* 0 or positive if match found */
    for ( iaccess=0; msgnumber<0; iaccess++ ) { /*run thru htaccess[] table*/
      char *deny = htaccess[iaccess].deny; /* referer to be denied */
      if ( deny == NULL ) break;	/* null signals end-of-table */
      if ( isempty(deny) )		/* signal to check for no referer */
	{ if ( isempty(http_referer) )	/* http_referer not supplied */
	   msgnumber = htaccess[iaccess].msgnumber; } /* so set message# */
      else				/* have referer to check for */
       if ( !isempty(http_referer) )	/* and have referer to be checked */
	if ( isstrstr(http_referer,deny,0) ) /* invalid http_referer */
	 msgnumber = htaccess[iaccess].msgnumber; /* so set message# */
      } /* --- end-of-for(iaccess) --- */
    if ( msgnumber >= 0 )		/* deny access to this referer */
      isvalidreferer = 0; }		/* signal invalid referer */
/* --- render short expressions even for invalid referers --- */
if ( !isvalidreferer )			/* have an invalied referer */
  if ( MAXINVALID > 0 )			/* but short expressions allowed */
    if ( strlen(expression) <= MAXINVALID ) /* and this one is short enough*/
      isvalidreferer = 1;		/* so let it through */
/* --- check for invalidreferer directive (user wants to see message)  --- */
if ( getdirective(expression,"\\invalidreferer",1,0,1,argstring)
!=   NULL ) {				/* found \invalidreferer directive */
  isvalidreferer = 0;			/* signal invalid referer */
  msgnumber = atoi(argstring); }	/* requested message number */
/* --- substitute invalid referer message if referer is indeed invalid --- */
if ( !isvalidreferer ) {		/* invalid referer detected */
  if ( msgnumber<0 || msgnumber>maxinvalidmsg ) /* check message range */
    msgnumber = 0;			/* default if out-of-bounds */
  strcpy(expression,invalid_referer_msg[msgnumber]); /* choose message */
  strreplace(expression,"%%referer%%",	/* replace actual referer */
    (isempty(http_referer)?"your domain":nomath(http_referer)),0,0); }
msgnumber = 0;				/* reset global message number */
/* ---
 * check for embedded image \message directive (which supercedes everything)
 * ----------------------------------------------------------------------- */
if ( getdirective(expression,"\\message",1,0,1,argstring)
!=   NULL ) {				/* found \message directive */
  if ( msgfp!=NULL && msglevel>=1 )	/* copyright notice */
    fprintf(msgfp,"%s%s\n",copyright1,copyright2); /* always show copyright*/
  msgnumber = atoi(argstring);		/* requested message number */
  emitembedded(msgnumber,(isquery?2:0)); /* emit image, suppress msgfp */
  goto end_of_job; }			/*nothing to do after emitting image*/
/* ---
 * check for \switches directive (which supercedes everything else)
 * ---------------------------------------------------------------- */
if ( strreplace(expression,"\\switches","",0,0) /* remove \switches */
>=   1 ) {				/* found \switches */
  char	*pathsource[] = { "default", "switch", "which", "locate" };
  /*iscaching = 0;*/			/* don't cache \switches image */
  *expression = '\000';			/* reset expression */
  setpaths(imagemethod);		/* set paths */
  strcat(expression,"\\parstyle");	/* set paragraph mode */
  strcat(expression,"\\small\\tt");	/* set font,size */
  strcat(expression,"\\fparbox{");	/* emit -Dswitches in framed box */
  strcat(expression,"Program image...\\\\\n"); /* image */
  sprintf(expression+strlen(expression),"%s\\\\",argv[0]);
  strcat(expression,"Paths...\\\\\n");	/* paths */
  sprintf(expression+strlen(expression), /* latex path */
    "-DLATEX=$\\backslash$\"%s$\\backslash$\" \\ (%s)\\\\ \n",
    latexpath,pathsource[islatexpath]);
  sprintf(expression+strlen(expression), /* dvipng path */
    "-DDVIPNG=$\\backslash$\"%s$\\backslash$\" \\ (%s)\\\\ \n",
    dvipngpath,pathsource[isdvipngpath]);
  sprintf(expression+strlen(expression), /* dvips path */
    "-DDVIPS=$\\backslash$\"%s$\\backslash$\" \\ (%s)\\\\ \n",
    dvipspath,pathsource[isdvipspath]);
  sprintf(expression+strlen(expression), /* convert path */
    "-DCONVERT=$\\backslash$\"%s$\\backslash$\" \\ (%s)\\\\ \n",
    convertpath,pathsource[isconvertpath]);
  strcat(expression,"}");		/* end-of-\fparbox{} */
  } /* --- end-of-if(strreplace("\\switches")>=1) --- */
else					/* no \switches in expression */
 /* ---
  * check for \environment directive (which supercedes everything else)
  * ------------------------------------------------------------------- */
 if ( strreplace(expression,"\\environment","",0,0) /* remove \environment */
 >=   1 ) {				/* found \environment */
  int	ienv = 0;			/* environ[] index */
  /*iscaching = 0;*/			/* don't cache \environment image */
  *expression = '\000';			/* reset expression */
  setpaths(imagemethod);		/* set paths */
  strcat(expression,"\\parstyle");	/* set paragraph mode */
  strcat(expression,"\\scriptsize\\tt"); /* set font,size */
  strcat(expression,"\\noindent");	/* don't indent first line */
  strcat(expression,"\\begin{verbatim}"); /* begin verbatim environment */
  for ( ienv=0; ; ienv++ ) {		/* loop over environ[] strings */
    if ( environ[ienv] == (char *)NULL ) break; /* null terminates list */
    if ( *(environ[ienv]) == '\000' ) break; /* double-check empty string */
    sprintf(expression+strlen(expression), /* display environment string */
    "  %2d. %s \n", ienv+1,strwrap(environ[ienv],50,-6));
    /* "%2d.\\ \\ %s\\ \\\\ \n", ienv+1,nomath(environ[ienv])); */
    } /* --- end-of-for(ienv) --- */
  strcat(expression,"\\end{verbatim}");	/* end verbatim environment */
  } /* --- end-of-if(strreplace("\\environment")>=1) --- */
/* ---
 * save copy of expression before further preprocessing for MD5 hash
 * ------------------------------------------------------------------ */
strcpy(hashexpr,expression);		/* save unmodified expr for hash */
/* ---
 * check for \which directive (supercedes everything not above)
 * ------------------------------------------------------------ */
if ( getdirective(expression,"\\which",1,0,1,argstring)
!=   NULL ) {				/* found \which directive */
  int	ispermitted = 1;		/* true if a legitimate request */
  int	nlocate = 1;			/* use locate if which fails */
  char	*path = NULL;			/* whichpath() to argstring program*/
  char	whichmsg[512];			/* displayed message */
  trimwhite(argstring);			/*remove leading/trailing whitespace*/
  if ( isempty(argstring) ) ispermitted = 0; /* arg is an empty string */
  else {				/* have non-empty argstring */
    int	arglen = strlen(argstring);	/* #chars in argstring */
    if ( strcspn(argstring,WHITESPACE) < arglen /* embedded whitespace */
    ||   strcspn(argstring,"{}[]()<>") < arglen /* illegal char */
    ||   strcspn(argstring,"|/\"\'\\") < arglen /* illegal char */
    ||   strcspn(argstring,"`!@%&*+=^")< arglen /* illegal char */
    ) ispermitted = 0;			/*probably not a legitimate request*/
    } /* --- end-of-if/else(isempty(argstring)) --- */
  if ( ispermitted ) {			/* legitimate request */
    path = whichpath(argstring,&nlocate); /* path to argstring program */
    sprintf(whichmsg,			/* display path or "not found" */
      "%s(%s) = %s", (path==NULL||nlocate<1?"which":"locate"),
       argstring,(path!=NULL?path:"not found")); }
  else					/* display "not permitted" message */
    sprintf(whichmsg,"which(%s) = not permitted", argstring);
  strreplace(whichtemplate,"%%whichpath%%",whichmsg,0,0); /*insert message*/
  adtemplate = whichtemplate;		/* set which message */
  adfrequency = 1;			/* force its display */
  /*iscaching = 0;*/			/* don't cache it */
  if ( path != NULL )			/* change \ to $\backslash$ */
    /*strreplace(path,"\\","$\\backslash$",0,0)*/; /* make \ displayable */
  /*strcpy(expression,"\\parstyle\\small\\tt ");*/ /* re-init expression */
  /*strcat(expression,"\\fparbox{");*/	/* emit path in framed box */
  /*sprintf(expression+strlen(expression),*/ /* display path or "not found" */
    /*"which(%s) = %s",argstring,(path!=NULL?path:"not found"));*/
  /*strcat(expression,"}");*/		/* end-of-\fparbox{} */
  } /* --- end-of-if(getdirective("\\which")!=NULL) --- */
/* ---
 * check for embedded directives, remove them and set corresponding values
 * ----------------------------------------------------------------------- */
/* --- check for displaystyle/textstyle/parstyle directives --- */
if ( strreplace(expression,"\\displaystyle","",0,0) /*remove \displaystyle*/
>=   1 ) mathmode = 0;			/* found \displaystyle so set flag*/
if ( strreplace(expression,"\\textstyle","",0,0) /* remove \textstyle */
>=   1 ) mathmode = 1;			/* found \textstyle so reset flag */
if ( strreplace(expression,"\\parstyle","",0,0) /* remove \parstyle */
>=   1 ) mathmode = 2;			/* found \parstyle so reset flag */
if ( strreplace(expression,"\\parmode","",0,0) /*\parmode same as \parstyle*/
>=   1 ) mathmode = 2;			/* found \parmode so reset flag */
/* --- check for quiet/halt directives (\quiet or \halt) --- */
if ( strreplace(expression,"\\quiet","",0,0) /*remove occurrences of \quiet*/
>=   1 ) isquiet = 64;			/* found \quiet so set isquiet flag*/
if ( strreplace(expression,"\\noquiet","",0,0) /* remove \noquiet */
>=   1 ) isquiet = 0;			/* found \noquiet so reset flag */
if ( getdirective(expression,"\\nquiet",1,0,1,argstring) /*\nquiet{#Enters}*/
!=   NULL ) {				/* found \nquiet{#<Enter>'s} */
  isquiet = atoi(argstring); }		/* interpret arg as isquiet value */
/* --- replace \time directive with timestamp (similar to \today) --- */
if ( strstr(expression,"\\time") != NULL ) { /* user wants a timestamp */
  strreplace(expression,"\\time",timestamp(TZDELTA,3),0,0); /* insert time */
  maxage = 5;				/* re-render after 5 secs */
  iscaching = 0; }			/* don't cache \time */
if ( strstr(expression,"\\today") != NULL ) { /* user has a datestamp */
  iscaching = 0; }			/* don't cache \today either */
/* --- check for fontsize directives (\tiny ... \Huge) --- */
if ( mathmode != 2 )			/*latex sets font size in \parstyle*/
  for (irep=1; !isempty(sizedirectives[irep]); irep++) /*1=\tiny...10=\Huge*/
    if ( strreplace(expression,sizedirectives[irep],"",1,0) /*remove \size*/
    >=   1 ) fontsize = irep;		/* found \size so set fontsize */
/* --- check for usepackage directives --- */
while ( npackages < 9 )			/* no more than 9 extra packages */
  if ( getdirective(expression,"\\usepackage",1,0,-1,packages[npackages])
  ==   NULL )  break;			/* no more \usepackage directives */
  else {				/* found another \usepackage */
    /* --- check for optional \usepackage [args] --- */
    *(packargs[npackages]) = '\000';	/* init for no optional args */
    if ( noptional > 0 ) {		/* but we found an optional arg */
      strninit(packargs[npackages],optionalargs[0],255); } /*copy the first*/
    /* --- check for particular packages --- */
    if ( strstr(packages[npackages],"color") != NULL ) /*\usepackage{color}*/
      iscolorpackage = 1;		/* set color package flag */
    npackages++; }			/* bump package count */
/* --- see if we need any packages not already \usepackage'd by user --- */
if ( npackages < 9			/* have room for one more package */
&&   !iscolorpackage )			/* \usepackage{color} not specified*/
  if ( strstr(expression,"\\color") != NULL ) { /* but \color is used */
    strcpy(packages[npackages],"color"); /* so \usepackage{color} is needed*/
    *(packargs[npackages]) = '\000';	/* no optional args */
    npackages++; }			/* bump package count */
/* --- check for advertisement directive (\advertisement) --- */
if ( strreplace(expression,"\\advertisement","",0,0) /*remove \advertisement*/
>=   1 ) adfrequency = 1;		/* force advertisement display */
/* --- check for version directive (\version) --- */
if ( strreplace(expression,"\\version","",0,0) /* remove \version */
>=   1 ) { adtemplate = versiontemplate; /* set version message */
  adfrequency = 1; }			/* and force its display */
/* --- check for image type directives (\gif or \png) --- */
if ( strreplace(expression,"\\png","",0,0) /* remove occurrences of \png */
>=   1 ) imagetype = 2;			/* found -png so set png imagetype */
if ( strreplace(expression,"\\gif","",0,0) /* remove occurrences of \gif */
>=   1 ) imagetype = 1;			/* found -gif so set gif imagetype */
/* --- check for image method directives (\dvips or \dvipng) --- */
if ( strreplace(expression,"\\dvipng","",0,0) /*remove occurrences of \dvipng*/
>=   1 ) {				/* found -dvipng in expression */
  imagemethod = 1;			/* set dvipng imagemethod */
  if ( !ISGAMMA ) strcpy(gamma,DVIPNGGAMMA); } /* default dvipng gamma */
if ( strreplace(expression,"\\dvips","",0,0) /* remove occurrences of -dvips*/
>=   1 ) {				/* found -dvips in expression */
  imagemethod = 2;			/* set dvips/convert imagemethod */
  if ( !ISGAMMA ) strcpy(gamma,CONVERTGAMMA); } /* default convert gamma */
/* --- check for convert/dvipng command's -density/-D parameter --- */
if ( getdirective(expression,"\\density",1,1,1,density) /*look for \density*/
==   NULL )				/* no \density directive */
  getdirective(expression,"\\dpi",1,1,1,density); /* so try \dpi instead */
/* --- check for convert command's \gammacorrection parameter --- */
getdirective(expression,"\\gammacorrection",1,1,1,gamma); /*look for \gamma*/
/* --- check for \cache or \nocache directive --- */
if ( strreplace(expression,"\\cache","",0,0) /* remove \cache */
>=   1 ) iscaching = 1;			/* cache this image */
if ( strreplace(expression,"\\nocache","",0,0) /* remove \nocache */
>=   1 ) iscaching = 0;			/* don't cache this image */
/* ---
 * check for empty expression
 * -------------------------- */
trimwhite(expression);			/*remove leading/trailing whitespace*/
if ( isempty(expression) )		/* no expression supplied */
  if ( adfrequency != 1 )		/* and not a forced message */
    strcpy(expression,"\\fbox{\\rm No expression supplied}"); /* error msg */
/* ---
 * check for "advertisement"
 * ------------------------- */
if ( adfrequency > 0 ) {		/* advertising enabled */
  int	npump = crc16(expression)%16;	/* #times, 0-15, to pump rand() */
  srand(atoi(timestamp(TZDELTA,4)));	/* init rand() with mmddhhmmss */
  while ( npump-- >= 0 ) rand();	/* pre-pump rand() before use */
  if ( rand()%adfrequency == 0 ) {	/* once every adfrequency calls */
    advertisement(expression,adtemplate); /*wrap expression in advertisement*/
    if ( strcasestr(hashexpr,"\\advertisement") == NULL ) /* random ad */
      strchange(0,hashexpr,"\\advertisement "); } } /* signal ad in expr */
/* ---
 * hash the expression for name of cached image file
 * ------------------------------------------------- */
md5hash = md5str(hashexpr);		/* md5 hash of original expression */
/* ---
 * check for \msglevel{msglevel} for debugging
 * ------------------------------------------- */
if ( getdirective(expression,"\\msglevel",1,0,1,argstring)/*look for \msglvl*/
!=   NULL )				/* found \msglevel directive */
  if ( (msglevel = min2(atoi(argstring),MAXMSGLEVEL)) /*assign new msglevel*/
  >    0 )				/* user wants messages */
  if ( isquery )			/* can't write messages to stdout */
    msgfp = fopen(makepath(NULL,md5hash,".out"),"w"); /* file md5hash.out */
/* ---
 * emit initial messages
 * --------------------- */
if ( msgfp!=NULL && msglevel>=1 ) {	/*copyright notice and path to image*/
  fprintf(msgfp,"%s%s\n",copyright1,copyright2); /* always show copyright */
  showmsg(3,"running image",argv[0]);	/* and executable image if verbose */
  showmsg(2,"input expression",hashexpr); /* and input expression */
  if ( msglevel >= 8 ) {		/* and if very verbose */
    fprintf(msgfp,			/* timelimit info */
      "\nmathTeX> %s timelimit: warn/killtime=%d/%d, path=%s\n",
      (timelimit("",-99)==992?"Built-in":"Stub"), warntime, killtime,
      (istimelimitpath?timelimitpath:"none"));
    fflush(msgfp); }			/* flush message buffer */
  } /* --- end-of-if(msgfp!=NULL&&msglevel>=1) --- */
/* -------------------------------------------------------------------------
Emit cached image or render the expression
-------------------------------------------------------------------------- */
if ( md5hash != NULL ) {		/* md5str() almost surely succeeded*/
  /* ---
   * check for cache directory, and create it if it doesn't already exist
   * -------------------------------------------------------------------- */
  if ( isempty(outfile) )		/* no explicit output file given */
    if ( !isdexists(makepath(NULL,NULL,NULL)) ) /* and no cache directory */
      if ( mkdir(makepath(NULL,NULL,NULL),perm_all) /* so make cache dir */
      !=   0 ) {			/* failed, emit embedded error image*/
        emitembedded(CACHEFAILED,isquery); /* emit CACHEFAILED message */
        goto end_of_job; }		/* quit if failed to mkdir cache */
  /* ---
   * emit cached image if it already exists
   * -------------------------------------- */
  if ( isquery )			/* re-render if running from shell */
    if ( iscaching )			/* or if not caching image */
      if(emitcache(makepath(NULL,md5hash,extensions[imagetype]),maxage,0) > 0)
        goto end_of_job;		/* done if cached image emitted */
  /* ---
   * first log caching request for new image
   * --------------------------------------- */
  if ( msglevel >= 1 )			/* check if logging */
    if ( iscaching )			/* only log images being cached */
      if ( isempty(outfile) )		/* and not saved to explicit outfile*/
        mathlog(hashexpr,md5hash);	/* log request for new image */
  /* ---
   * now generate the new image and emit it
   * -------------------------------------- */
  /* --- set up name for temporary work directory --- */
  /*strninit(tempdir,tmpnam(NULL),255);*/ /* maximum name length is 255 */
  strninit(tempdir,md5hash,255);	/* maximum name length is 255 */
  /* --- additional message --- */
  showmsg(9,"working directory",tempdir); /* working directory */
  /* --- mathtex() generates the image and saves it to file --- */
  if ( mathtex(expression,md5hash)	/* generate new image */
  ==   imagetype ) {			/* and emit cache if succeeded */
    /* --- succeeded, so emit the newly-generated image --- */
    if ( isquery )			/* don't emit cache to shell stdout*/
      emitcache(makepath(NULL,md5hash,extensions[imagetype]),maxage,0); }
  else {				/* latex failed to run */
    /* --- failed, so emit the embedded image of an error message --- */
    if ( msgnumber < 1 ) msgnumber = 2;	/* general failure message */
    emitembedded(msgnumber,isquery); }	/* emit message image */
  /* ---
   * remove images not being cached
   * ------------------------------ */
  if ( !iscaching )			/* don't want this image cached */
    if ( isempty(outfile) )		/* unless explicit outfile provided*/
      remove(makepath(NULL,md5hash,extensions[imagetype])); /* remove file */
  } /* --- end-of-if(md5hash!=NULL) --- */
end_of_job:
  if ( msgfp!=NULL && msgfp!=stdout )	/* have an open message file */
    fclose(msgfp);			/* so close it at eoj */
  exit ( 0 );
} /* --- end-of-function main() --- */


/* ==========================================================================
 * Function:	mathtex ( expression, filename )
 * Purpose:	create image of latex math expression
 * --------------------------------------------------------------------------
 * Arguments:	expression (I)	pointer to null-terminated char string
 *				containing latex math expression
 *		filename (I)	pointer to null-terminated char string
 *				containing filename but not .extension
 *				of output file (should be the md5 hash
 *				of expression)
 * --------------------------------------------------------------------------
 * Returns:	( int )		imagetype if successful, 0=error
 * --------------------------------------------------------------------------
 * Notes:     o	created file will be filename.gif if imagetype=1
 *		or filename.png if imagetype=2.
 * ======================================================================= */
/* --- entry point --- */
int	mathtex ( char *expression, char *filename )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
/* --- latex wrapper document template --- */
char  latexwrapper[MAXEXPRSZ+16384] =
	"\\documentclass[10pt]{article}\n"
	"\\usepackage[latin1]{inputenc}\n"
	"\\usepackage{amsmath}\n"
	"\\usepackage{amsfonts}\n"
	"\\usepackage{amssymb}\n"
	/*"\\usepackage{bm}\n"*/	/* bold math */
	#if defined(USEPACKAGE)		/* cc -DUSEPACKAGE=\"filename\" */
	  #include USEPACKAGE		/* filename with \usepackage{}'s */
	#endif				/* or anything for the preamble */
	"%%usepackage%%\n"
      #if 0
        "\\def\\stackboxes#1{\\vbox{\\def\\\\{\\egroup\\hbox\\bgroup}"
        "\\hbox\\bgroup#1\\egroup}}\n"
        "\\def\\fparbox#1{\\fbox{\\stackboxes{#1}}}\n"
      #endif
	"\\pagestyle{empty}\n"
	"\\begin{document}\n"
	"%%%\\renewcommand{\\input}[1]"	/* don't let users \input{} */
	"{\\mbox{[[$\\backslash$input\\{#1\\} illegal]]}}\n"
	#if defined(NEWCOMMAND)		/* cc -DNEWCOMMAND=\"filename\" */
	  #include NEWCOMMAND		/* filename with \newcommand{}'s */
	#endif				/* or anything for the document */
	"%%fontsize%%\n"
	"%%beginmath%% "
	"%%expression%% \n"		/* \n in case expression contains %*/
	" %%endmath%%\n"
	"\\end{document}\n";
char  errormsg[1024] =			/* latex runs but can't make .dvi */
	"\\fbox{\\footnotesize $\\mbox{Latex failed, probably due to} "
	"\\atop \\mbox{an error in your expression.}$}";
char  usepackage[1024] = "\000";	/* additional \usepackage{}'s */
char  convertargs[1024] =		/* args/switches for convert */
	" -density %%dpi%% -gamma %%gamma%%"
	/*" -border 0% -fuzz 2%"*/
	" -trim -transparent \"#FFFFFF\" ";
char  dvipngargs[1024] =		/* args/switches for dvipng */
	" --%%imagetype%% -D %%dpi%% --gamma %%gamma%%"
	" -bg Transparent -T tight -v"	/* -q for quiet, -v for verbose */
	" -o %%giffile%% ";		/* output filename supplied as -o */
/* --- other variables --- */
static	int iserror = 0;		/* true if procesing error message */
int	setpaths();			/* set paths for latex,dvipng,etc */
char	*makepath(), latexfile[256],giffile[256]="\000"; /*path/filename.ext*/
FILE	*latexfp = NULL;		/* latex wrapper file for expression*/
char	command[2048], subcommand[1024]; /* system(command) runs latex, etc */
char	*beginmath[] = { "\\[", "$", " " }, /* start math mode */
	*endmath[] =   { "\\]", "$", " " }; /* end math mode */
int	perm_all = (S_IRWXU|S_IRWXG|S_IRWXO); /* 777 permissions */
int	dir_stat = 0;			/* 1=mkdir okay, 2=chdir okay */
int	sys_stat = 0;			/* system() return status */
int	isdexists(), isfexists(),	/* check if dir, .dvi file created */
	isnotfound();			/* check .err file for "not found" */
int	strreplace();			/* replace template directives */
int	ipackage = 0;			/* packages[] index 0...npackages-1*/
int	rrmdir();			/* rm -r */
int	gifpathlen = 0;			/* ../ or ../../ prefix of giffile */
int	status = 0;			/* imagetype or 0=error */
int	timelimit();			/* and using built-in timelimit() */
/* -------------------------------------------------------------------------
Make temporary work directory and change to it
-------------------------------------------------------------------------- */
msgnumber = 0;				/* no error to report yet */
if ( !isdexists(tempdir/*filename*/) )	/* if temp directory doesn't exist */
  if ( mkdir(tempdir/*filename*/,perm_all) /* make temp dirextory */
  !=   0 ) {				/* mkdir failed */
    msgnumber = MKDIRFAILED;		/* set corresponding message number*/
    goto end_of_job; }			/* and quit */
dir_stat++;				/* signal mkdir successful */
if ( chdir(tempdir/*filename*/)		/* cd to temp directory */
!=   0 ) {				/* cd  failed */
    msgnumber = CHDIRFAILED;		/* set corresponding message number*/
    goto end_of_job; }			/* and quit */
dir_stat++;				/* signal chdir successful */
/* -------------------------------------------------------------------------
set up latex directives for user-specified additional \usepackage{}'s
-------------------------------------------------------------------------- */
if ( !iserror )				/* don't \usepackage for error */
 if ( npackages > 0 )			/* have additional packages */
  for ( ipackage=0; ipackage<npackages; ipackage++ ) { /*make \usepackage{}*/
    strcat(usepackage,"\\usepackage");	/* start with a directive */
    if ( !isempty(packargs[ipackage]) ) { /* have an optional arg */
      strcat(usepackage,"[");		/* begin optional argument */
      strcat(usepackage,packargs[ipackage]); /* add optional arg */
      strcat(usepackage,"]"); }		/* finish optional arg */
    strcat(usepackage,"{");		/* begin package name argument */
    strcat(usepackage,packages[ipackage]); /* add package name */
    strcat(usepackage,"}\n"); }		/* finish constructing directive */
/* -------------------------------------------------------------------------
Replace "keywords" in latex template with expression and other directives
-------------------------------------------------------------------------- */
/* --- replace %%beginmath%%...%%endmath%% with \[...\] or with $...$ --- */
  if ( mathmode<0 || mathmode>2 ) mathmode=0; /* mathmode validity check */
  strreplace(latexwrapper,"%%beginmath%%",beginmath[mathmode],1,0);
  strreplace(latexwrapper,"%%endmath%%",endmath[mathmode],1,0);
/* --- replace %%fontsize%% in template with \tiny...\Huge --- */
  strreplace(latexwrapper,"%%fontsize%%",sizedirectives[fontsize],1,0);
/* --- replace %%usepackage%% in template with extra \usepackage{}'s --- */
  strreplace(latexwrapper,"%%usepackage%%",usepackage,1,0);
/* --- replace %%expression%% in template with expression --- */
  strreplace(latexwrapper,"%%expression%%",expression,1,0);
/* -------------------------------------------------------------------------
Create latex document wrapper file containing expression
-------------------------------------------------------------------------- */
strcpy(latexfile,makepath("","latex",".tex")); /* latex filename latex.tex */
latexfp = fopen(latexfile,"w");		/* open latex file for write */
if ( latexfp == NULL ) {		/* couldn't open latex file */
  msgnumber = FOPENFAILED;		/* set corresponding message number*/
  goto end_of_job; }			/* and quit */
fprintf(latexfp,"%s",latexwrapper);	/* write file */
fclose(latexfp);			/* close file after writing it */
/* -------------------------------------------------------------------------
Set paths to programs we'll need to run
-------------------------------------------------------------------------- */
setpaths(imagemethod);
/* -------------------------------------------------------------------------
Execute the latex file
-------------------------------------------------------------------------- */
/* --- initialize system(command); to execute the latex file --- */
*command = '\000';			/* init command as empty string */
/* --- run latex under timelimit if explicitly given -DTIMELIMIT switch --- */
if ( istimelimitpath			/* given explict -DTIMELIMIT path */
&&   warntime > 0			/* and positive warntime, and... */
&&   !iscompiletimelimit ) {		/* not using built-in timelimit() */
  if ( killtime < 1 ) killtime=1;	/* don't make trouble for timelimit*/
  strcat(command,makepath("",timelimitpath,NULL)); /* timelimit program */
  if ( isempty(command) )		/* no path to timelimit */
    warntime = (-1);			/*reset flag to signal no timelimit*/
  else {				/* have path to timelimit program */
    sprintf(command+strlen(command),	/* add timelimit args after path */
      " -t%d -T%d ",warntime,killtime); }
  } /* --- end-of-if(warntime>0) --- */
/* --- path to latex executable image followed by args --- */
strcpy(subcommand,makepath("",latexpath,NULL)); /* running latex program */
if ( isempty(subcommand) ) {		/* no program path to latex */
  msgnumber = SYLTXFAILED;		/* set corresponding error message */
  goto end_of_job; }			/* signal failure and emit error */
strcat(command,subcommand);		/* add latex path (after timelimit)*/
strcat(command," ");			/* add a blank before latex args */
strcat(command,latexfile);		/* run on latexfile we just wrote */
if ( isquiet > 0 ) {			/* to continue after latex error */
    if ( isquiet > 99 )			/* explicit q requested */
      system("echo \"q\" > reply.txt");	/* reply  q  to latex error prompt */
    else {				/* reply <Enter>'s followed by x */
      int  nquiet = isquiet;		/* this many <Enter>'s before x */
      FILE *freply =fopen("reply.txt","w"); /* open reply.txt for write */
      if ( freply != NULL ) {		/* opened successfully */
	while ( --nquiet >= 0 )		/* nquiet times... */
	  fputs("\n",freply);		/* ...write <Enter> to reply.txt */
	fputs("x",freply);		/* finally followed by an x */
	fclose(freply); } }		/* close reply.txt */
    strcat(command," < reply.txt"); }	/*by redirecting stdin to reply.txt*/
  else strcat(command," < /dev/null");	/* or redirect stdin to /dev/null */
strcat(command," >latex.out 2>latex.err"); /* redirect stdout and stderr */
showmsg(5,"latex command executed",command); /* show latex command executed*/
/* --- execute the latex file --- */
sys_stat = timelimit(command,killtime);	/* throttle the latex command */
if ( msgfp!=NULL && msglevel>=3 )	/* and show command's return status*/
  fprintf(msgfp,"\nmathTeX> system() return status: %d\n", sys_stat);
if ( sys_stat == (-1)			/* system(latex) failed */
||   !isfexists(makepath("","latex",".dvi")) ) { /*latex didn't create .dvi*/
  if ( !iserror ) {			/* don't recurse if errormsg fails */
    iserror = 1;			/* set error flag */
    status = mathtex(errormsg,filename); /* recurse just once for error msg*/
    goto end_of_job; }			/* ignore original expression */
  else {				/* ignore 2nd try to recurse */
    msgnumber =				/* set corresponding message number*/
      (sys_stat==(-1)?SYLTXFAILED:	/* system() failed */
      (isnotfound("latex")?SYLTXFAILED:	/* latex program not found */
      LATEXFAILED));			/* latex ran but failed */
    goto end_of_job; }			/* and quit */
  } /* --- end-of-if(system()==-1||!isfexists()) --- */
/* -------------------------------------------------------------------------
Construct the output path/filename.[gif,png] for the image file
-------------------------------------------------------------------------- */
if ( isempty(outfile)			/* using default cache directory */
||   !isthischar(*outfile,"/\\") ) {	/* or just given a relative path */
  strcpy(giffile,"../");		/* output file will be in cache */
  if ( iserror ) strcat(giffile,"../");	/* we're in error subdirectory */
  gifpathlen = strlen(giffile); }	/* #chars in ../ or ../../ prefix */
if ( isempty(outfile) )			/* using default output filename */
  strcat(giffile,makepath(NULL,filename,extensions[imagetype]));
else					/* have an explicit output file */
  strcat(giffile,makepath("",outfile,extensions[imagetype]));
showmsg(3,"output image file",giffile+gifpathlen); /* show output filename */
/* -------------------------------------------------------------------------
Run dvipng for .dvi-to-gif/png
-------------------------------------------------------------------------- */
if ( imagemethod == 1 ) {		/*dvipng method requested (default)*/
  /* ---
   * First replace "keywords" in dvipngargs template with actual values
   *------------------------------------------------------------------- */
  /* --- replace %%imagetype%% in dvipng arg template with gif or png --- */
  strreplace(dvipngargs,"%%imagetype%%",extensions[imagetype],1,0);
  /* --- replace %%dpi%% in dvipng arg template with actual dpi --- */
  strreplace(dvipngargs,"%%dpi%%",density,1,0);
  /* --- replace %%gamma%% in dvipng arg template with actual gamma --- */
  strreplace(dvipngargs,"%%gamma%%",gamma,1,0);
  /* --- replace %%giffile%% in dvipng arg template with actual giffile --- */
  strreplace(dvipngargs,"%%giffile%%",giffile,1,0);
  /* ---
   * And run dvipng to convert .dvi file directly to .gif/.png
   *---------------------------------------------------------- */
  strcpy(command,makepath("",dvipngpath,NULL)); /* running dvipng program */
  if ( isempty(command) ) {		/* no program path to dvipng */
    msgnumber = SYPNGFAILED;		/* set corresponding error message */
    goto end_of_job; }			/* signal failure and emit error */
  strcat(command,dvipngargs);		/* add dvipng switches */
  strcat(command,makepath("","latex",".dvi")); /* run dvipng on latex.dvi */
  strcat(command," >dvipng.out 2>dvipng.err"); /* redirect stdout, stderr */
  showmsg(5,"dvipng command executed",command); /* dvipng command executed */
  sys_stat = system(command);		/* execute the dvipng command */
  if ( sys_stat == (-1)			/* system(dvipng) failed */
  ||   !isfexists(giffile) ) {		/*or dvipng failed to create giffile*/
    msgnumber =				/* set corresponding message number*/
      (sys_stat==(-1)?SYPNGFAILED:	/* system() failed */
      (isnotfound("dvipng")?SYPNGFAILED: /* dvipng program not found */
      DVIPNGFAILED));			/* dvipng ran but failed */
    goto end_of_job; }			/* and quit */
  } /* --- end-of-if(imagemethod==1) --- */
/* -------------------------------------------------------------------------
Run dvips for .dvi-to-postscript and convert for postscript-to-gif/png
-------------------------------------------------------------------------- */
if ( imagemethod == 2 ) {		/* dvips/convert method requested */
  /* ---
   * First run dvips to convert .dvi file to .ps postscript
   *------------------------------------------------------- */
  strcpy(command,makepath("",dvipspath,NULL)); /* running dvips program */
  if ( isempty(command) ) {		/* no program path to dvips */
    msgnumber = SYPSFAILED;		/* set corresponding error message */
    goto end_of_job; }			/* signal failure and emit error */
  strcat(command," -E ");		/* add -E switch and a blank */
  strcat(command,makepath("","latex",".dvi")); /* run dvips on latex.dvi */
  strcat(command," -o ");		/* to produce output in */
  strcat(command,makepath("","dvips",".ps")); /* dvips.ps postscript file */
  strcat(command," >dvips.out 2>dvips.err"); /* redirect stdout, stderr */
  showmsg(5,"dvips command executed",command); /* dvips command executed */
  sys_stat = system(command);		/* execute system(dvips) */
  if ( sys_stat == (-1)			/* system(dvips) failed */
  ||   !isfexists(makepath("","dvips",".ps")) ) { /*dvips didn't create .ps*/
    msgnumber =				/* set corresponding message number*/
      (sys_stat==(-1)?SYPSFAILED:	/* system() failed */
      (isnotfound("dvips")?SYPSFAILED:	/* dvips program not found */
      DVIPSFAILED));			/* dvips ran but failed */
    goto end_of_job; }			/* and quit */
  /* ---
   * Then replace "keywords" in convertargs template with actual values
   *------------------------------------------------------------------- */
  /* --- replace %%dpi%% in convert arg template with actual density --- */
  strreplace(convertargs,"%%dpi%%",density,1,0);
  /* --- replace %%gamma%% in convert arg template with actual gamma --- */
  strreplace(convertargs,"%%gamma%%",gamma,1,0);
  /* ---
   * And run convert to convert .ps file to .gif/.png
   *-------------------------------------------------- */
  strcpy(command,makepath("",convertpath,NULL)); /*running convert program*/
  if ( isempty(command) ) {		/* no program path to convert */
    msgnumber = SYCVTFAILED;		/* set corresponding error message */
    goto end_of_job; }			/* signal failure and emit error */
  strcat(command,convertargs);		/* add convert switches */
  strcat(command,makepath("","dvips",".ps")); /* convert from postscript */
  strcat(command," ");			/* field separator */
  strcat(command,giffile);		/* followed by ../cache/filename */
  strcat(command," >convert.out 2>convert.err"); /*redirect stdout, stderr*/
  showmsg(5,"convert command executed",command); /*convert command executed*/
  sys_stat = system(command);		/* execute system(convert) command */
  if ( sys_stat == (-1)			/* system(convert) failed */
  ||   !isfexists(giffile) ) {		/* or convert didn't create giffile*/
    msgnumber =				/* set corresponding message number*/
      (sys_stat==(-1)?SYCVTFAILED:	/* system() failed */
      (isnotfound("convert")?SYCVTFAILED: /* convert program not found */
      CONVERTFAILED));			/* convert ran but failed */
    goto end_of_job; }			/* and quit */
  } /* --- end-of-if(imagemethod==2) --- */
status = imagetype;			/* signal success */
/* -------------------------------------------------------------------------
Back to caller
-------------------------------------------------------------------------- */
end_of_job:
  if ( dir_stat >= 2 ) chdir("..");	/* return up to original dir */
  if ( dir_stat >= 1 ) rrmdir(tempdir/*filename*/); /*rm -r temp working dir*/
  iserror = 0;				/* always reset error flag */
  return ( status );
} /* --- end-of-function mathtex() --- */


/* ==========================================================================
 * Function:	setpaths ( method )
 * Purpose:	try to set accurate paths for latex,dvipng,dvips,convert
 * --------------------------------------------------------------------------
 * Arguments:	method (I)	1 for dvipng, 2 for dvips/convert, 0 for both
 * --------------------------------------------------------------------------
 * Returns:	( int )		1
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	setpaths ( int method )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
char	*programpath=NULL, *whichpath(); /* look for latex,dvipng,etc */
int	nlocate = 0;			/*if which fails, #locate|grep hits*/
static	int islatexwhich=0, isdvipngwhich=0, /* set true after we try */
	isdvipswhich=0, isconvertwhich=0,    /*whichpath() for that program*/
	istimelimitwhich=0;
/* ---
 * set paths, either from -DLATEX=\"path/latex\", etc, or call whichpath()
 * ----------------------------------------------------------------------- */
/* --- path for latex program --- */
if ( !ISLATEXSWITCH && !islatexwhich ) { /* no -DLATEX=\"path/latex\" */
  islatexwhich = 1;			/* signal that which already tried */
  nlocate = ISLOCATE;			/* use locate if which fails??? */
  if ( (programpath=whichpath("latex",&nlocate)) /* try to find latex path */
  !=   NULL ) {				/* succeeded */
    islatexpath = (nlocate==0?2:3);	/* set flag signalling which() */
    strninit(latexpath,programpath,255); } }/*so copy path from whichpath()*/
/* --- path for timelimit program --- */
if ( 0 )				/* only use explicit -DTIMELIMIT */
 if ( warntime > 0 )			/* have -DWARNTIME or -DTIMELIMIT */
  if ( !ISTIMELIMITSWITCH		/*no -DTIMELIMIT=\"path/timelimit\"*/
  &&   !istimelimitwhich ) {
    istimelimitwhich = 1;		/* signal that which already tried */
    nlocate = ISLOCATE;			/* use locate if which fails??? */
    if ( (programpath=whichpath("timelimit",&nlocate)) /* try to find path */
    !=   NULL ) {			/* succeeded */
      istimelimitpath = (nlocate==0?2:3); /* set flag signalling which() */
      strninit(timelimitpath,programpath,255); } } /* copy from whichpath()*/
/* --- path for dvipng program --- */
if ( method != 2 )			/* not needed for dvips/convert */
 if ( !ISDVIPNGSWITCH && !isdvipngwhich ) { /* no -DDVIPNG=\"path/dvipng\" */
  isdvipngwhich = 1;			/* signal that which already tried */
  nlocate = ISLOCATE;			/* use locate if which fails??? */
  if ( (programpath=whichpath("dvipng",&nlocate)) /* try to find dvipng */
  !=   NULL ) {				/* succeeded */
    isdvipngpath = (nlocate==0?2:3);	/* set flag signalling which() */
    strninit(dvipngpath,programpath,255); } }/*so copy path from whichpath()*/
/* --- path for dvips program --- */
if ( method != 1 )			/* not needed for dvipng */
 if ( !ISDVIPSSWITCH && !isdvipswhich ) { /* no -DDVIPS=\"path/dvips\" */
  isdvipswhich = 1;			/* signal that which already tried */
  nlocate = ISLOCATE;			/* use locate if which fails??? */
  if ( (programpath=whichpath("dvips",&nlocate)) /* try to find dvips path */
  !=   NULL ) {				/* succeeded */
    isdvipspath = (nlocate==0?2:3);	/* set flag signalling which() */
    strninit(dvipspath,programpath,255); } }/* so copy path from whichpath()*/
/* --- path for convert program --- */
if ( method != 1 )			/* not needed for dvipng */
 if ( !ISCONVERTSWITCH && !isconvertwhich ){/*no -DCONVERT=\"path/convert\"*/
  isconvertwhich = 1;			/* signal that which already tried */
  nlocate = ISLOCATE;			/* use locate if which fails??? */
  if ( (programpath=whichpath("convert",&nlocate)) /* try to find convert */
  !=   NULL ) {				/* succeeded */
    isconvertpath = (nlocate==0?2:3);	/* set flag signalling which() */
    strninit(convertpath,programpath,255); } } /*copy path from whichpath()*/
/* --- adjust imagemethod to comply with available programs --- */
if ( method != imagemethod		/* ignore recursive call */
&&   method != 0 ) goto end_of_job;	/* but 0 is a call for both methods*/
if ( imagemethod == 1 )			/* dvipng wanted */
  if ( !isdvipngpath ) {		/* but we have no real path to it */
    if ( method == 1 ) setpaths(2);	/* try to set dvips/convert paths */
    if ( isdvipspath && isconvertpath )	{ /* and we do have dvips, convert */
      imagemethod = 2;			/* so flip default to use them */
      if ( !ISGAMMA ) strcpy(gamma,CONVERTGAMMA); } }/*default convert gamma*/
if ( imagemethod == 2 )			/* dvips, convert wanted */
  if ( !isdvipspath || !isconvertpath ) {/*but we have no real paths to them*/
    if ( method == 2 ) setpaths(1);	/* try to set dvipng path */
    if ( isdvipngpath ) {		/* and we do have dvipng path */
      imagemethod = 1;			/* so flip default to use it */
      if ( !ISGAMMA ) strcpy(gamma,DVIPNGGAMMA); } }/* default dvipng gamma */
/* --- back to caller --- */
end_of_job:
  return ( 1 );
} /* --- end-of-function setpaths() --- */


/* ==========================================================================
 * Function:	isnotfound ( filename )
 * Purpose:	check a  "... 2>filename.err" file for a "not found" message,
 *		indicating the corresponding program path is incorrect
 * --------------------------------------------------------------------------
 * Arguments:	filename (I)	pointer to null-terminated char string
 *				containing filename (an .err extension
 *				is tacked on, just pass the filename)
 *				to be checked for "not found" message
 * --------------------------------------------------------------------------
 * Returns:	( int )		1 if filename.err contains "not found",
 *				0 otherwise (or for any error)
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	isnotfound ( char *filename )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	status = 0;			/* set 1 if "not found" found */
int	isfexists();			/* check if filename exists */
char	command[256];			/* grep program */
FILE    *grepout = NULL;		/* grep's stdout */
char	grepline[256];			/* line from grep's stdout */
int	strreplace();			/* make sure "not found" was found */
int	nlines = 0;			/* #lines read */
/* -------------------------------------------------------------------------
grep filename.err for filename (i.e., the program name), then check each
such line for "not found", "no such", etc.
-------------------------------------------------------------------------- */
/* --- initialization --- */
if ( isempty(filename) ) goto end_of_job; /* no input filename supplied */
sprintf(command,"%s.err",filename);	/* look for filename.err */
if ( !isfexists(command) ) {		/* filename.err doesn't exist */
  status = 1;				/* assume this means "not found" */
  goto end_of_job; }			/* and return that to caller */
/* --- grep filename.err for filename (i.e., for the program name) --- */
sprintf(command,"grep -i \"%s\" %s.err",filename,filename); /*construct cmd*/
/* --- use popen() to invoke grep --- */
grepout = popen( command, "r" );	/* issue grep and capture stdout */
if( grepout == NULL ) goto end_of_job;	/* failed */
/* --- read the pipe one line at a time --- */
while ( fgets(grepline,255,grepout)	/* get next line */
!= NULL ) {				/* not at eof yet */
  if ( strreplace(grepline,"not found","",0,0) /* check for "not found" */
  >    0 ) nlines++;			/* count another "not found" line */
  if ( strreplace(grepline,"no such","",0,0) /* check for "no such" */
  >    0 ) nlines++;			/* count another "no such" line */
  } /* --- end-of-while(fgets()!=NULL) -- */
if ( nlines > 0 ) status = 1;		/* "not found" found */
/* --- pclose() waits for command to terminate --- */
pclose( grepout );			/* finish */
end_of_job:				/* back to caller */
  return ( status );			/*1 if filename contains "not found"*/
} /* --- end-of-function isnotfound() --- */


/* ==========================================================================
 * Function:	validate ( expression )
 * Purpose:	remove/replace illegal \commands from expression
 * --------------------------------------------------------------------------
 * Arguments:	expression (I/O) pointer to null-terminated char string
 *				containing latex expression to be validated.
 *				Upon return, invalid \commands have been
 *				removed or replaced
 * --------------------------------------------------------------------------
 * Returns:	( int )		#illegal \commands found (hopefully 0)
 * --------------------------------------------------------------------------
 * Notes:     o	Ignore this note and see the one below it instead...
 *		  This routine is currently "stubbed out",
 *		  i.e., the invalid[] list of invalid \commands is empty.
 *		  Instead, \renewcommand's are embedded in the LaTeX wrapper.
 *		  So the user's -DNEWCOMMAND=\"filename\" can contain
 *		  additional \renewcomand's for any desired validity checks.
 *	      o	Because some \renewcommand's appear to occasionally cause
 *		latex to go into a loop after encountering syntax errors,
 *		I'm now using validate() to disable \input, etc.
 *		For example, the following short document...
 *		  \documentclass[10pt]{article}
 *		  \begin{document}
 *		  \renewcommand{\input}[1]{dummy renewcommand}
 *		  %%\renewcommand{\sqrt}[1]{dummy renewcommand}
 *		  %%\renewcommand{\beta}{dummy renewcommand}
 *		  \[ \left( \begin{array}{cccc} 1 & 0 & 0 &0
 *		  \\ 0 & 1  %%% \end{array}\right)
 *		  \]
 *		  \end{document}
 *		reports a  "! LaTeX Error:"  and then goes into
 *		a loop if you reply q.  But if you comment out the
 *		\renewcommand{\input} and uncomment either or both
 *		of the other \renewcommand's, then latex runs to
 *		completion (with the same syntax error, of course,
 *		but without hanging).
 *
 * ======================================================================= */
/* --- entry point --- */
int	validate ( char *expression )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
/* --- list of invalid \commands --- */
static	struct {
	  int  action;			/* 0=ignore, 1=apply, 2=abort */
	  char *command;		/* invalid \command */
	  int  nargs;			/* #args, \command{arg1}...{nargs} */
	  int  optionalpos;		/* #{args} before optional [arg] */
	  int  argformat;		/* 0=LaTeX {arg} or [arg], 1=arg */
	  char *displaystring; }	/* display this instead */
	invalid[] = {			/* list of invalid commands */
	  #if defined(INVALID)		/* cc -DINVALID=\"filename\" */
	    #include INVALID		/* filename with invalid \commands */
	  #endif			/* as illustrated below... */
	/* actn  "command"        #args pos fmt "replacement string" or NULL
	 * ---- ----------------- ----- --- --- -------------------------- */
	  { 1,  "\\newcommand",      2,  1,  0,  NULL },
	  { 1,  "\\providecommand",  2,  1,  0,  NULL },
	  { 1,  "\\renewcommand",    2,  1,  0,  NULL },
	  { 1,  "\\input",           1, -1,  0,  NULL },
	/* --plain TeX commands with non-{}-enclosed args we can't parse-- */
	  { 1,  "\\def",             2, -1, 20,  NULL },
	  { 1,  "\\edef",            2, -1, 20,  NULL },
	  { 1,  "\\gdef",            2, -1, 20,  NULL },
	  { 1,  "\\xdef",            2, -1, 20,  NULL },
	  { 1,  "\\loop",            0, -1,  0,  NULL },
	  { 1,  "\\csname",          0, -1,  0,  NULL },
	  { 1,  "\\catcode",         0, -1,  0,  NULL },
	  { 1,  "\\output",          0, -1,  0,  NULL },
	  { 1,  "\\everycr",         0, -1,  0,  NULL },
	  { 1,  "\\everypar",        0, -1,  0,  NULL },
	  { 1,  "\\everymath",       0, -1,  0,  NULL },
	  { 1,  "\\everyhbox",       0, -1,  0,  NULL },
	  { 1,  "\\everyvbox",       0, -1,  0,  NULL },
	  { 1,  "\\everyjob",        0, -1,  0,  NULL },
	  { 1,  "\\openin",          0, -1,  0,  NULL },
	  { 1,  "\\read",            0, -1,  0,  NULL },
	  { 1,  "\\openout",         0, -1,  0,  NULL },
	  { 1,  "\\write",           0, -1,  0,  NULL },
	/* --- other dangerous notation --- */
	  { 1,  "^^",                0, -1,  0,  NULL },
#if 0
	/* --- test cases --- */
	/*{ 1,  "\\input",      1,  -1,  0,
		"{\\mbox{$\\backslash$input\\{#1\\}}}" },*/
	  { 1,  "\\input",      1,  -1,  0,
		"{\\mbox{~$\\backslash$input\\{#1\\}~not~permitted~}}" },
	  { 1,  "\\newcommand", 2,   1,  0, NULL},
		 /*"{\\mbox{~$\\backslash$newcommand\\{#1\\}[#0]\\{#2\\}"
		 "~not~permitted~}}" },*/
#endif
	  { 0, NULL, 0, -1, 0, NULL } } ; /* end-of-list */
/* --- other variables --- */
int	ninvalid = 0,			/* #invalid =commands found */
	ivalid = 0;			/* invalid[ivalid] list index */
char	*getdirective(), *pcommand=NULL; /* find and remove invalid command */
static	char args[10][512]= {"","","","","","","","","",""}; /*\cmd{arg}'s*/
char	*pargs[11] = { args[0],args[1],args[2],args[3], /* ptrs to them */
	args[4],args[5],args[6],args[7],args[8],args[9], NULL };
char	display[2048], argstr[256], optstr[1024]; /*displaystring with args*/
char	*strchange();			/* place display where command was */
int	strreplace();			/* replace #1 with args[0], etc */
char	*nomath();			/* change \ to \\, { to \{, etc */
int	iarg=0, iopt=0;			/* args[], optionalargs[] indexes */
/* -------------------------------------------------------------------------
Initialization
-------------------------------------------------------------------------- */
if ( isempty(expression) )		/* no input to validate */
  goto end_of_job;			/* so quit */
/* -------------------------------------------------------------------------
Check each invalid command in list
-------------------------------------------------------------------------- */
for ( ivalid=0; !isempty(invalid[ivalid].command); ivalid++ ) { /*run list*/
  /* --- extract local copy of invalid command list elements --- */
  int	action        = invalid[ivalid].action; /* 0=ignore,1=apply,2=abort*/
  char	*command      = invalid[ivalid].command; /* invalid \command */
  int	nargs         = invalid[ivalid].nargs; /*number of \command {arg}'s*/
  int	myoptionalpos = invalid[ivalid].optionalpos; /*#{args} before [arg]*/
  int	myargformat   = invalid[ivalid].argformat; /* 0={arg},1=arg*/
  char	*displaystring= invalid[ivalid].displaystring; /*display template*/
  /* --- arg format info --- */
  int	nfmt=0,isnegfmt=0,argfmt[9]={0,0,0,0,0,0,0,0,0}; /*argformat digits*/
  /* --- args returned as (char *) if nargs=1 or (char **) if nargs>1 --- */
  void	*argptr = (nargs<2?(void *)args[0]:(void *)pargs); /*(char * or **)*/
  /* --- find and remove/replace all invalid command occurrences --- */
  if ( action < 1 ) continue;		/* ignore this invalid \command */
  optionalpos = myoptionalpos;		/* set global arg for getdirective */
  argformat = myargformat;		/* set global arg for getdirective */
  /* --- interpret argformat digits --- */
  if ( argformat != 0 ) {		/* have argformat */
    int	myfmt = argformat;		/* local copy */
    if ( myfmt < 0 ) { isnegfmt=1; myfmt=(-myfmt); } /* check sign */
    while ( myfmt>0 && nfmt<9 ) {	/* have more format digits */
      argfmt[nfmt] = myfmt%10;		/* store low-order decimal digit */
      myfmt /= 10;			/* and shift it out */
      nfmt++; }				/* count another format digit */
    } /* --- end-of-if(argformat!=0) --- */
  /* --- remove/replace each occurrence of invalid \command --- */
  while ( (pcommand = getdirective(expression,command,1,0,nargs,argptr))
  != NULL ) {				/* found and removed an occurrence */
    ninvalid++;				/* count another invalid \command */
    if ( noptional >= 8 ) noptional=7;	/* don't overflow our buffers */
    /* --- construct optional [arg]...[arg] for display --- */
    *optstr = '\000';			/*init optional [arg]...[arg] string*/
    if ( noptional > 0 )		/* have optional [args] */
      for ( iopt=0; iopt<noptional; iopt++ ) /* construct "[arg]...[arg]" */
	if ( !isempty(optionalargs[iopt]) ) { /* have an optional arg */
	  strcat(optstr,"[");		/* leading [ for optional arg */
	  strcat(optstr,nomath(optionalargs[iopt])); /*optional arg string*/
	  strcat(optstr,"]"); }		/* trailing ] */
    /* --- construct error message display or use supplied template --- */
    if ( isempty(displaystring) ) {	/*replace \command by not~permitted*/
      strcpy(display,"\\mbox{~\\underline{"); /* underline error in \mbox{}*/
      strcat(display,nomath(command));	/* command without \ */
      for ( iarg=0; iarg<nargs; iarg++ ) { /* add {args} and any [args] */
	int ifmt = (nfmt<=iarg?0:argfmt[nfmt-iarg-1]); /* arg format digit */
	if ( iarg==myoptionalpos && noptional>0 ) /* [args] belong here */
	  strcat(display,optstr);	/* insert them before next {arg} */
	if ( isempty(args[iarg]) ) break; /* no more args */
	if(ifmt==0) strcat(display,"\\{"); /* insert leading \{ for arg */
	strcat(display,nomath(args[iarg])); /* arg */
	if(ifmt==0) strcat(display,"\\}"); } /* trailing \} for arg */
      strcat(display,"~not~permitted}~}"); } /* finish error, close \mbox{}*/
    else {				/*replace \command by displaystring*/
      strcpy(display,displaystring);	/* local copy of display template */
      if ( noptional < 1 )		/* no optional args */
	strreplace(display,"[#0]","",0,0); /* so remove tag from template */
      for ( iarg=0; iarg<nargs; iarg++ ) { /* replace #1 with args[0], etc */
	if ( iarg==myoptionalpos && noptional>0 ) /* [args] belong here */
	  strreplace(display,"[#0]",optstr,0,0); /*insert them before {arg}*/
	if ( isempty(args[iarg]) ) break; /* no more args */
	else {				/* have an arg */
	  sprintf(argstr,"#%d",iarg+1);	/* #1 in template displays args[0] */
	  strreplace(display,argstr,nomath(args[iarg]),0,0); } /* replace */
        } /* --- end-of-for(iarg) --- */
      } /* --- end-of-if/else(isempty(displaystring)) --- */
    strchange(0,pcommand,display);	/* place display where command was */
    for ( iarg=0; iarg<10; iarg++ ) *args[iarg] = '\000'; /* reset args */
    } /* --- end-of-while(getdirective()!=NULL) --- */
  } /* --- end-of-for(ivalid) --- */
end_of_job:
  return ( ninvalid );			/* back to caller with #invalid */
} /* --- end-of-function validate() --- */


/* ==========================================================================
 * Function:	advertisement ( expression, message )
 * Purpose:	wrap expression in advertisement message
 * --------------------------------------------------------------------------
 * Arguments:	expression (I/O) pointer to null-terminated char string
 *				containing expression to be "wrapped",
 *				and returning wrapped expression
 *		message (I)	pointer to null-terminated char string
 *				containing template for advertisement
 *				message, or NULL to use default message
 * --------------------------------------------------------------------------
 * Returns:	( int )		1 if successful, 0=error
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	advertisement ( char *expression, char *message )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
/* --- advertisement template --- */
char  *adtemplate =
	#if defined(ADVERTISEMENT)	/* cc -DADVERTISEMENT=\"filename\" */
	  #include ADVERTISEMENT	/* filename with advertisement */
	#else				/* formatted as illustrated below */
	"\\begin{center}\n"
	"\\fbox{$\\mbox{\\footnotesize\\LaTeX{} rendering courtesy of}\\atop\n"
	"\\mbox{\\scriptsize http://www.forkosh.com/mathtex.html}$}\\\\ \n"
	"\\vspace*{-4mm}\n"
	" %%beginmath%% %%expression%% %%endmath%% \n"
	"\\end{center}\n"
	#endif
	;				/* terminating semicolon */
/* --- other variables --- */
char	adbuffer[MAXEXPRSZ+2048];	/*construct wrapped expression here*/
char	*beginmath[] = { "\\[", "$", " " }, /* start math mode */
	*endmath[] =   { "\\]", "$", " " }; /* end math mode */
int	strreplace();			/* replace %%keywords%% with values*/
/* -------------------------------------------------------------------------
wrap expression in advertisement
-------------------------------------------------------------------------- */
/* --- start with template --- */
if ( isempty(message) )			/* caller didn't supply message */
  message = adtemplate;			/* so use default message */
strcpy(adbuffer,message);		/* copy message template to buffer */
/* --- replace %%beginmath%%...%%endmath%% with \[...\] or with $...$ --- */
  if ( mathmode<0 || mathmode>2 ) mathmode=0; /* out-of-bounds sanity check*/
  if ( isempty(expression) ) mathmode = 2; /*ad only, no need for math mode*/
  strreplace(adbuffer,"%%beginmath%%",beginmath[mathmode],1,0);
  strreplace(adbuffer,"%%endmath%%",endmath[mathmode],1,0);
/* --- replace %%expression%% in template with expression --- */
  strreplace(adbuffer,"%%expression%%",expression,1,0);
/* --- replace original expression --- */
strcpy(expression,adbuffer);		/* expression mow wrapped in ad */
mathmode = 2;				/* \[...\] already in expression */
return ( 1 );				/* always just return 1 */
} /* --- end-of-function advertisement() --- */


/* ==========================================================================
 * Function:	mathlog ( expression, filename )
 * Purpose:	write entry in log file
 * --------------------------------------------------------------------------
 * Arguments:	expression (I)	pointer to null-terminated char string
 *				containing latex math expression
 *		filename (I)	pointer to null-terminated char string
 *				containing filename but not .extension
 *				of output file
 * --------------------------------------------------------------------------
 * Returns:	( int )		1 if successful, 0=error
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	mathlog ( char *expression, char *filename )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
FILE	*filefp = NULL;			/* fopen(filename) for logfile */
char	*timestamp();			/* time stamp for logged messages */
char	*makepath();			/* construct full path/filename.ext*/
char	*http_referer = getenv("HTTP_REFERER"); /* referer using mathTeX */
char	*dashes =			/* separates logfile entries */
 "--------------------------------------------------------------------------";
/* -------------------------------------------------------------------------
write message to cache log file
-------------------------------------------------------------------------- */
if ( !isempty(CACHELOG) ) {		/* if a logfile is given */
  if ( (filefp=fopen(makepath(NULL,CACHELOG,NULL),"a")) /*open logfile*/
  !=   NULL ) {				/* ignore logging if can't open */
    int isreflogged = 0;		/* set true if http_referer logged */
    fprintf(filefp,"%s                 %s\n", /* timestamp, md5 file */
    timestamp(TZDELTA,0),		/* timestamp */
    makepath("",filename,extensions[imagetype])); /* hashed filename */
    fprintf(filefp,"%s\n",expression);	/* expression in filename */
    if ( !isempty(http_referer) ) {	/* show referer if we have one */
      int loglen = strlen(dashes);	/* #chars on line in log file*/
      char *refp = http_referer;	/* line to be printed */
      isreflogged = 1;			/* signal http_referer logged*/
      while ( 1 ) {			/* printed in parts if needed*/
	fprintf(filefp,"%.*s\n",loglen,refp); /* print a part */
	if ( strlen(refp) <= loglen ) break;  /* no more parts */
	refp += loglen; }		/* bump ptr to next part */
      } /* --- end-of-if(!isempty(http_referer)) --- */
    if ( !isreflogged )			/* http_referer not logged */
      fprintf(filefp,"http://none\n");	/* so log dummy referer line */
    fprintf(filefp,"%s\n",dashes);	/* separator line */
    fclose(filefp);			/* close logfile immediately */
    } /* --- end-of-if(filefp!=NULL) --- */
  } /* --- end-of-if(!isempty(CACHELOG)) --- */
return ( 1 );
} /* --- end-of-function mathlog() --- */


/* ==========================================================================
 * Function:	makepath ( path, name, extension )
 * Purpose:	return string containing path/name.extension
 * --------------------------------------------------------------------------
 * Arguments:	path (I)	pointer to null-terminated char string
 *				containing "" path or path/ or NULL to
 *				use cachepath if caching enabled
 *		name (I)	pointer to null-terminated char string
 *				containing filename but not .extension
 *				of output file or NULL
 *		extension (I)	pointer to null-terminated char string
 *				containing extension or NULL
 * --------------------------------------------------------------------------
 * Returns:	( char * )	"cachepath/filename.extension" or NULL=error
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
char	*makepath ( char *path, char *name, char *extension )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static	char namebuff[512];		/* buffer for constructed filename */
char	*filename = NULL;		/*ptr to filename returned to caller*/
/* -------------------------------------------------------------------------
construct filename
-------------------------------------------------------------------------- */
/* --- validity checks --- */
/*if ( isempty(name) ) goto end_of_job;*/ /* no name supplied by caller */
/* --- start with caller's path/ or default path to cache directory --- */
*namebuff = '\000';			/* re-init namebuff */
if ( path == NULL ) {			/* use default path to cache */
  if ( !isempty(cachepath) )		/* have a cache path */
    strcpy(namebuff,cachepath); }	/* begin filename with path */
else					/* or use caller's supplied path */
  if ( *path != '\000' )		/* if it's not an empty string */
    strcpy(namebuff,path);		/* begin filename with path */
if ( !isempty(namebuff) )		/* have a leading path */
  if ( !isthischar(lastchar(namebuff),"\\/") ) /* no \ or / at end of path */
    strcat(namebuff,(iswindows?"\\":"/")); /* so add windows\ or unix/ */
/* --- add name after path/ (name arg might just be a blank space) --- */
if ( !isempty(name) ) {			/* name supplied by caller */
  if ( !isempty(namebuff) )		/* and if we already have a path */
    if ( isthischar(*name,"\\/") ) name++; /* skip leading \ or / in name */
  strcat(namebuff,name); }		/* name concatanated after path/ */
/* --- add extension after path/name */
if ( !isempty(extension) ) {		/* have a filename extension */
  if ( !isthischar(lastchar(namebuff),".") ) { /* no . at end of name */
    if ( !isthischar(*extension,".") )	/* and extension has no leading . */
      strcat(namebuff,".");		/* so we need to add our own . */
    strcat(namebuff,extension); }	/* add extension after path/name. */
  else					/* . already at end of name */
    strcat(namebuff,			/* add extension without . */
    (!isthischar(*extension,".")?extension:extension+1)); /*skip leading . */
  } /* --- end-of-if(!isempty(extension)) --- */
filename = namebuff;			/* successful name back to caller */
/*end_of_job:*/
  return ( filename );			/* back with name or NULL=error */
} /* --- end-of-function makepath() --- */


/* ==========================================================================
 * Function:	isfexists ( filename )
 * Purpose:	check whether or not filename exists
 * --------------------------------------------------------------------------
 * Arguments:	filename (I)	pointer to null-terminated char string
 *				containing filename to check for
 * --------------------------------------------------------------------------
 * Returns:	( int )		1 = filename exists, 0 = not
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	isfexists ( char *filename )
{
FILE	*fp = (isempty(filename)?NULL:fopen(filename,"r")); /* try to fopen*/
int	status = 0;			/* init for non-existant filename */
if ( fp != NULL ) {			/* but filename does exist */
  status = 1;				/* so flip status */
  fclose(fp); }				/* and close the file */
return ( status );			/* tell caller if we found filename*/
} /* --- end-of-function isfexists() --- */


/* ==========================================================================
 * Function:	isdexists ( dirname )
 * Purpose:	check whether or not directory exists
 * --------------------------------------------------------------------------
 * Arguments:	dirname (I)	pointer to null-terminated char string
 *				containing directory name to check for
 * --------------------------------------------------------------------------
 * Returns:	( int )		1 = directory exists, 0 = not
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	isdexists ( char *dirname )
{
int	status = 0;			/* init for non-existant dirname */
if ( !isempty(dirname) ) {		/* must have directory name */
  char	directory[512];			/* local copy of dirname */
  DIR	*dp = NULL;			/* dp=opendir() opens directory */
  strcpy(directory,dirname);		/* start with name given by caller */
  if ( !isthischar(lastchar(directory),"/") ) /* no / at end of directory */
    strcat(directory,"/");		/* so add one ourselves */
  if ( (dp=opendir(directory)) != NULL ) { /* dirname exists */
    status = 1;				/* so flip status */
    closedir(dp); }			/* and close the directory */
  } /* --- end-of-if(!isempty(dirname)) --- */
return ( status );			/* tell caller if we found dirname */
} /* --- end-of-function isdexists() --- */


/* ==========================================================================
 * Function:	whichpath ( program, nlocate )
 * Purpose:	determines the path to program with popen("which 'program'")
 * --------------------------------------------------------------------------
 * Arguments:	program (I)	pointer to null-terminated char string
 *				containing program whose path is desired
 *		nlocate (I/0)	addr of int containing NULL to ignore,
 *				or (addr of int containing) 0 to *not*
 *				use locate if which fails.  If non-zero,
 *				use locate if which fails, and return
 *				number of locate lines (if locate succeeds)
 * --------------------------------------------------------------------------
 * Returns:	( char * )	path to program, or NULL for any error
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
char	*whichpath ( char *program, int *nlocate )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static	char pathbuff[256];		/* buffer for returned path */
char	command[256];			/* which program */
FILE    *whichout = NULL;		/* which's stdout */
int	nchars = 0,			/* read whichout one char at a time*/
	pathchar;			/* fgetc(whichout) */
char	*path = NULL;			/* either pathbuff or NULL=error */
char	*locatepath();			/* try locate if which fails */
int	islocate = (nlocate==NULL? 1 : (*nlocate!=0?1:0)); /* 1=use locate*/
/* -------------------------------------------------------------------------
Issue which command and read its output
-------------------------------------------------------------------------- */
/* --- check if which() suppressed --- */
if ( !ISWHICH ) return ( NULL );	/*not running which, return failure*/
/* --- first construct the command --- */
if ( isempty(program) ) goto end_of_job; /* no input */
sprintf(command,"which %s",program);	/* construct command */
/* --- use popen() to invoke which --- */
whichout = popen( command, "r" );	/* issue which and capture stdout */
if( whichout == NULL ) goto end_of_job;	/* failed */
/* --- read the pipe one char at a time --- */
while ( (pathchar=fgetc(whichout))	/* get one more char */
!= EOF ) {				/* not at eof yet */
  pathbuff[nchars] = (char)pathchar;	/* store the char */
  if ( ++nchars >= 255 ) break; }	/* don't overflow buffer */
pathbuff[nchars] = '\000';		/* null-terminate path */
trimwhite(pathbuff);			/*remove leading/trailing whitespace*/
/* --- pclose() waits for command to terminate --- */
pclose( whichout );			/* finish */
if ( nchars > 0 ) {			/* found path with which */
  path = pathbuff;			/* give user successful path */
  if ( islocate && nlocate!=NULL ) *nlocate = 0; } /* signal we used which */
end_of_job:
  if ( path == NULL )			/* which failed to find program */
    if ( islocate )			/* and we're using locate */
      path = locatepath(program,nlocate); /* try locate instead */
  return ( path );			/* give caller path to command */
} /* --- end-of-function whichpath() --- */


/* ==========================================================================
 * Function:	locatepath ( program, nlocate )
 * Purpose:	determines the path to program with popen("locate 'program'")
 * --------------------------------------------------------------------------
 * Arguments:	program (I)	pointer to null-terminated char string
 *				containing program whose path is desired
 *		nlocate (O)	addr to int returning #lines locate|grep
 *				found, or NULL to ignore
 * --------------------------------------------------------------------------
 * Returns:	( char * )	path to program, or NULL for any error
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
char	*locatepath ( char *program, int *nlocate )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static	char pathbuff[256];		/* buffer for returned path */
char	command[256];			/* locate program | grep /program$ */
FILE    *locateout = NULL;		/* locate's stdout */
char	pathline[256];			/* read locateout one line at a time*/
int	nlines = 0;			/* #lines read */
int	linelen=0, pathlen = 9999;	/* choose shortest path */
char	*path = NULL;			/* either pathbuff or NULL=error */
/* -------------------------------------------------------------------------
Issue locate|grep command and read its output
-------------------------------------------------------------------------- */
/* --- first construct the command --- */
if ( isempty(program) ) goto end_of_job; /* no input */
/*if ( strlen(program) < 2 ) goto end_of_job; */ /* might run forever */
sprintf(command,"locate -q -r \"/%s$\" | grep \"bin\"",program);
/* --- use popen() to invoke locate|grep --- */
locateout = popen( command, "r" );	/* issue locate and capture stdout */
if( locateout == NULL ) goto end_of_job; /* failed */
/* --- read the pipe one line at a time --- */
while ( fgets(pathline,255,locateout)	/* get next line */
!= NULL ) {				/* not at eof yet */
  trimwhite(pathline);			/*remove leading/trailing whitespace*/
  if ( (linelen=strlen(pathline)) > 0 ) { /* ignore empty lines */
    if ( linelen < pathlen ) {		/* new shortest path */
      strcpy(pathbuff,pathline);	/* store shortest for caller */
      pathlen = linelen; }		/* and reset new shortest length */
    nlines++; } }			/* count another non-empty line */
/* --- pclose() waits for command to terminate --- */
pclose( locateout );			/* finish */
if ( pathlen>0 && pathlen<256 ) path = pathbuff; /*give user successful path*/
if ( nlocate != NULL ) *nlocate = nlines; /* and number of locate|grep hits*/
end_of_job:
  return ( path );			/* give caller path to command */
} /* --- end-of-function locatepath() --- */


/* ==========================================================================
 * Function:	rrmdir ( path )
 * Purpose:	rm -r path
 * --------------------------------------------------------------------------
 * Arguments:	path (I)	pointer to null-terminated char string
 *				containing path to be rm'ed,
 *				relative to cwd.
 * --------------------------------------------------------------------------
 * Returns:	( int )		0 = success, -1 = error
 * --------------------------------------------------------------------------
 * Notes:     o	Based on Program 4.7, pages 108-111, in
 *		Advanced Programming in the UNIX Environment,
 *		W. Richard Stevens, Addison-Wesley 1992, ISBN 0-201-56317-7
 * ======================================================================= */
/* --- entry point --- */
int	rrmdir ( char *path )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
DIR	*directory = NULL;		/* opendir() opens path directory */
struct	dirent	*entry = NULL;		/* readdir() gives directory entry */
struct	stat	st_info;		/* lstat() gives info about entry */
char	nextpath[512], *pnext=NULL;	/* recurse path/filename in dir */
int	status = (-1);			/* init in case of any error */
/* -------------------------------------------------------------------------
Check file type at path
-------------------------------------------------------------------------- */
if ( path != NULL )			/* have path argument */
  if ( *path != '\000' )		/* and it's not an empty string */
    if ( strcmp(path,".") != 0		/* and it's not "." */
    &&   strcmp(path,"..") != 0 )	/* and also not ".." */
      status = lstat(path,&st_info);	/* what kind of file is at path? */
if ( status < 0 ) goto end_of_job;	/* no kind of file found at path */
/* -------------------------------------------------------------------------
Recurse level if file is a directory
-------------------------------------------------------------------------- */
if ( S_ISDIR(st_info.st_mode) ) {	/* have a directory */
  /* ---
   * Initialization
   * -------------- */
  /* --- init path for each file in directory --- */
  strcpy(nextpath,path);		/* start with path from caller */
  pnext = nextpath + strlen(path);	/* ptr to '\000' at end of path */
  if ( *(pnext-1) != '/' )		/* no trailing / at end of path */
    *pnext++ = '/';			/* so add one */
  *pnext = '\000';			/* null-terminate nextpath */
  /* --- open the directory at caller's path (with trailing /) --- */
  directory = opendir(nextpath);	/* open the directory */
  /* ---
   * Run through all files in directory
   * ---------------------------------- */
  if ( directory != NULL ) {		/* directory successfully opened */
    while ( (entry = readdir(directory)) /* next entry in directory */
    != NULL )				/* NULL signals end-of-directory */
      if ( strcmp(entry->d_name,".") != 0      /* filename not "." */
      &&   strcmp(entry->d_name,"..") != 0 ) { /* and also not ".." */
        strcpy(pnext,entry->d_name);	/* add filename to path */
        status = rrmdir(nextpath); }	/* recurse */
    closedir(directory);		/* close directory after last file */
    showmsg(29,"rrmdir removing directory",path); /* show directory removed*/
    } /* --- end-of-if(directory!=NULL) --- */
  } /* --- end-of-if(S_ISDIR(st_info.st_mode)) --- */
else					/* file isn't a directory */
  showmsg(29,"     rrmdir removing file",path); /* show file removed */
/* -------------------------------------------------------------------------
Remove file or directory (keep it for debugging if msglevel>=9)
-------------------------------------------------------------------------- */
if ( msglevel < 9 ) status = remove(path); /* remove file or directory */
end_of_job:
  return ( status );
} /* --- end-of-function rrmdir() --- */


/* ==========================================================================
 * Function:	emitcache ( cachefile, maxage, isbuffer )
 * Purpose:	dumps bytes from cachefile to stdout
 * --------------------------------------------------------------------------
 * Arguments:	cachefile (I)	pointer to null-terminated char string
 *				containing full path to file to be dumped,
 *				or contains buffer of bytes to be dumped
 *		maxage (I)	int containing maxage. in seconds, for
 *				http header, or -1 to not emit headers
 *		isbuffer (I)	>=1 if cachefile is buffer of bytes to be
 *				dumped, and if isbuffer>=9 it's the #bytes
 *				in buffer to be dumped.  Otherwise,
 *				strlen(cachefile) determines #bytes.
 * --------------------------------------------------------------------------
 * Returns:	( int )		#bytes dumped (0 signals error)
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	emitcache ( char *cachefile, int maxage, int isbuffer )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	nbytes=0, readcachefile();	/* read cache file */
FILE	*emitptr = stdout;		/* emit cachefile to stdout */
unsigned char buffer[MAXGIFSZ+1];	/* bytes from cachefile */
unsigned char *buffptr = buffer;	/* ptr to buffer */
/* -------------------------------------------------------------------------
initialization
-------------------------------------------------------------------------- */
/* --- check that files opened okay --- */
if ( emitptr == (FILE *)NULL )		/* failed to open emit file */
  goto end_of_job;			/* so return 0 bytes to caller */
/* --- read the file if necessary --- */
if ( isbuffer ) {			/* cachefile is buffer */
 buffptr = (unsigned char *)cachefile;	/* so reset buffer pointer */
 nbytes = (isbuffer<9?strlen((char *)buffptr):isbuffer); }/*determine #bytes*/
else					/* cachefile is file name */
 if ( (nbytes = readcachefile(cachefile,buffer)) /* read the file */
 < 1 ) {				/* file not read */
   msgnumber = EMITFAILED;		/* signal error */
   goto end_of_job; }			/* quit if file not read */
/* --- first emit http headers if requested --- */
if ( /*isemitcontenttype*/		/* content-type lines enabled */
/*&&*/ maxage >= 0 )			/* caller wants http headers */
 { /* --- emit mime content-type line --- */
   fprintf( emitptr, "Cache-Control: max-age=%d\n",maxage );
   fprintf( emitptr, "Content-Length: %d\n",nbytes );
   fprintf( emitptr, "Content-type: image/%s\n\n",extensions[imagetype] ); }
/* -------------------------------------------------------------------------
set stdout to binary mode (for Windows)
-------------------------------------------------------------------------- */
/* emitptr = fdopen(STDOUT_FILENO,"wb"); */  /* doesn't work portably, */
#ifdef WINDOWS				/* so instead... */
  #ifdef HAVE_SETMODE			/* prefer (non-portable) setmode() */
    if ( setmode ( fileno (stdout), O_BINARY) /* windows specific call */
    == -1 ) ; /* handle error */	/* sets stdout to binary mode */
  #else					/* setmode() not available */
    #if 1
      freopen ("CON", "wb", stdout);	/* freopen() stdout binary */
    #else
      stdout = fdopen (STDOUT_FILENO, "wb"); /* fdopen() stdout binary */
    #endif
  #endif
#endif
/* -------------------------------------------------------------------------
emit bytes from cachefile
-------------------------------------------------------------------------- */
/* --- write bytes to stdout --- */
if ( fwrite(buffptr,sizeof(unsigned char),nbytes,emitptr) /* write buffer */
<    nbytes )				/* failed to write all bytes */
  nbytes = 0;				/* reset total count to 0 */
end_of_job:
  return ( nbytes );			/* back with #bytes emitted */
} /* --- end-of-function emitcache() --- */


/* ==========================================================================
 * Function:	readcachefile ( cachefile, buffer )
 * Purpose:	read cachefile into buffer
 * --------------------------------------------------------------------------
 * Arguments:	cachefile (I)	pointer to null-terminated char string
 *				containing full path to file to be read
 *		buffer (O)	pointer to unsigned char string
 *				returning contents of cachefile
 * --------------------------------------------------------------------------
 * Returns:	( int )		#bytes read (0 signals error)
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	readcachefile ( char *cachefile, unsigned char *buffer )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
FILE	*cacheptr = fopen(cachefile,"rb"); /*open cachefile for binary read*/
unsigned char cachebuff[512];		/* bytes from cachefile */
int	buflen = 256,			/* #bytes we try to read from file */
	nread = 0,			/* #bytes actually read from file */
	maxbytes = MAXGIFSZ,		/* max #bytes returned in buffer */
	nbytes = 0;			/* total #bytes read */
/* -------------------------------------------------------------------------
initialization
-------------------------------------------------------------------------- */
/* --- check that files opened okay --- */
if ( cacheptr == (FILE *)NULL ) goto end_of_job; /*failed to open cachefile*/
/* --- check that output buffer provided --- */
if ( buffer == (unsigned char *)NULL ) goto end_of_job; /* no buffer */
/* -------------------------------------------------------------------------
read bytes from cachefile
-------------------------------------------------------------------------- */
while ( 1 )
  {
  /* --- read bytes from cachefile --- */
  nread = fread(cachebuff,sizeof(unsigned char),buflen,cacheptr); /* read */
  if ( nbytes + nread > maxbytes )	/* block too big for buffer */
    nread = maxbytes - nbytes;		/* so truncate it */
  if ( nread < 1 ) break;		/* no bytes left in cachefile */
  /* --- store bytes in buffer --- */
  memcpy(buffer+nbytes,cachebuff,nread); /* copy current block to buffer */
  /* --- ready to read next block --- */
  nbytes += nread;			/* bump total #bytes emitted */
  if ( nread < buflen ) break;		/* no bytes left in cachefile */
  if ( nbytes >= maxbytes ) break;	/* avoid buffer overflow */
  } /* --- end-of-while(1) --- */
end_of_job:
  if ( cacheptr != NULL ) fclose(cacheptr); /* close file if opened */
  return ( nbytes );			/* back with #bytes emitted */
} /* --- end-of-function readcachefile() --- */


/* ==========================================================================
 * Function:	crc16 ( s )
 * Purpose:	16-bit crc of string s
 * --------------------------------------------------------------------------
 * Arguments:	s (I)		pointer to null-terminated char string
 *				whose crc is desired
 * --------------------------------------------------------------------------
 * Returns:	( int )		16-bit crc of s
 * --------------------------------------------------------------------------
 * Notes:     o	From Numerical Recipes in C, 2nd ed, page 900.
 * ======================================================================= */
/* --- entry point --- */
int	crc16 ( char *s )
{
/* -------------------------------------------------------------------------
Compute the crc
-------------------------------------------------------------------------- */
unsigned short crc = 0;			/* returned crc */
int	ibit;				/* for(ibit) eight one-bit shifts */
while ( !isempty(s) ) {			/* while there are still more chars*/
  crc = (crc ^ (*s)<<8);		/* add next char */
  for ( ibit=0; ibit<8; ibit++ )	/* generator polynomial */
    if ( crc & 0x8000 ) { crc<<=1; crc=crc^4129; }
    else crc <<= 1;
  s++;					/* next xhar */
  } /* --- end-of-while(!isempty(s)) --- */
return ( (int)crc );			/* back to caller with crc */
} /* --- end-of-function crc16() --- */


/* ==========================================================================
 * Function:	md5str ( instr )
 * Purpose:	returns null-terminated character string containing
 *		md5 hash of instr (input string)
 * --------------------------------------------------------------------------
 * Arguments:	instr (I)	pointer to null-terminated char string
 *				containing input string whose md5 hash
 *				is desired
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to null-terminated 32-character
 *				md5 hash of instr
 * --------------------------------------------------------------------------
 * Notes:     o	Other md5 library functions are included below.
 *		They're all taken from Christophe Devine's code,
 *		which (as of 04-Aug-2004) is available from
 *		     http://www.cr0.net:8040/code/crypto/md5/
 *	      o	The P,F,S macros in the original code are replaced
 *		by four functions P1()...P4() to accommodate a problem
 *		with Compaq's vax/vms C compiler.
 * ======================================================================= */
/* --- #include "md5.h" --- */
#ifndef uint8
  #define uint8  unsigned char
#endif
#ifndef uint32
  #define uint32 unsigned long int
#endif
typedef struct
  { uint32 total[2];
    uint32 state[4];
    uint8 buffer[64];
  } md5_context;
void md5_starts( md5_context *ctx );
void md5_update( md5_context *ctx, uint8 *input, uint32 length );
void md5_finish( md5_context *ctx, uint8 digest[16] );
/* --- md5.h --- */
#define GET_UINT32(n,b,i)                       \
  { (n) = ( (uint32) (b)[(i)    ]       )       \
        | ( (uint32) (b)[(i) + 1] <<  8 )       \
        | ( (uint32) (b)[(i) + 2] << 16 )       \
        | ( (uint32) (b)[(i) + 3] << 24 ); }
#define PUT_UINT32(n,b,i)                       \
  { (b)[(i)    ] = (uint8) ( (n)       );       \
    (b)[(i) + 1] = (uint8) ( (n) >>  8 );       \
    (b)[(i) + 2] = (uint8) ( (n) >> 16 );       \
    (b)[(i) + 3] = (uint8) ( (n) >> 24 ); }
/* --- P,S,F macros defined as functions --- */
void P1(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
  { *a += (uint32)(d ^ (b & (c ^ d))) + X[k] + t;
    *a  = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
    return; }
void P2(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
  { *a += (uint32)(c ^ (d & (b ^ c))) + X[k] + t;
    *a  = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
    return; }
void P3(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
  { *a += (uint32)(b ^ c ^ d) + X[k] + t;
    *a  = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
    return; }
void P4(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
  { *a += (uint32)(c ^ (b | ~d)) + X[k] + t;
    *a  = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
    return; }

/* --- entry point (this one little stub written by me)--- */
char *md5str( char *instr )
  { static char outstr[64];
    unsigned char md5sum[16];
    md5_context ctx;
    int j;
    md5_starts( &ctx );
    md5_update( &ctx, (uint8 *)instr, strlen(instr) );
    md5_finish( &ctx, md5sum );
    for( j=0; j<16; j++ )
      sprintf( outstr + j*2, "%02x", md5sum[j] );
    outstr[32] = '\000';
    return ( outstr ); }

/* --- entry point (all md5 functions below by Christophe Devine) --- */
void md5_starts( md5_context *ctx )
  { ctx->total[0] = 0;
    ctx->total[1] = 0;
    ctx->state[0] = 0x67452301;
    ctx->state[1] = 0xEFCDAB89;
    ctx->state[2] = 0x98BADCFE;
    ctx->state[3] = 0x10325476; }

void md5_process( md5_context *ctx, uint8 data[64] )
  { uint32 X[16], A, B, C, D;
    GET_UINT32( X[0],  data,  0 );
    GET_UINT32( X[1],  data,  4 );
    GET_UINT32( X[2],  data,  8 );
    GET_UINT32( X[3],  data, 12 );
    GET_UINT32( X[4],  data, 16 );
    GET_UINT32( X[5],  data, 20 );
    GET_UINT32( X[6],  data, 24 );
    GET_UINT32( X[7],  data, 28 );
    GET_UINT32( X[8],  data, 32 );
    GET_UINT32( X[9],  data, 36 );
    GET_UINT32( X[10], data, 40 );
    GET_UINT32( X[11], data, 44 );
    GET_UINT32( X[12], data, 48 );
    GET_UINT32( X[13], data, 52 );
    GET_UINT32( X[14], data, 56 );
    GET_UINT32( X[15], data, 60 );
    A = ctx->state[0];
    B = ctx->state[1];
    C = ctx->state[2];
    D = ctx->state[3];
    P1( X, &A, B, C, D,  0,  7, 0xD76AA478 );
    P1( X, &D, A, B, C,  1, 12, 0xE8C7B756 );
    P1( X, &C, D, A, B,  2, 17, 0x242070DB );
    P1( X, &B, C, D, A,  3, 22, 0xC1BDCEEE );
    P1( X, &A, B, C, D,  4,  7, 0xF57C0FAF );
    P1( X, &D, A, B, C,  5, 12, 0x4787C62A );
    P1( X, &C, D, A, B,  6, 17, 0xA8304613 );
    P1( X, &B, C, D, A,  7, 22, 0xFD469501 );
    P1( X, &A, B, C, D,  8,  7, 0x698098D8 );
    P1( X, &D, A, B, C,  9, 12, 0x8B44F7AF );
    P1( X, &C, D, A, B, 10, 17, 0xFFFF5BB1 );
    P1( X, &B, C, D, A, 11, 22, 0x895CD7BE );
    P1( X, &A, B, C, D, 12,  7, 0x6B901122 );
    P1( X, &D, A, B, C, 13, 12, 0xFD987193 );
    P1( X, &C, D, A, B, 14, 17, 0xA679438E );
    P1( X, &B, C, D, A, 15, 22, 0x49B40821 );
    P2( X, &A, B, C, D,  1,  5, 0xF61E2562 );
    P2( X, &D, A, B, C,  6,  9, 0xC040B340 );
    P2( X, &C, D, A, B, 11, 14, 0x265E5A51 );
    P2( X, &B, C, D, A,  0, 20, 0xE9B6C7AA );
    P2( X, &A, B, C, D,  5,  5, 0xD62F105D );
    P2( X, &D, A, B, C, 10,  9, 0x02441453 );
    P2( X, &C, D, A, B, 15, 14, 0xD8A1E681 );
    P2( X, &B, C, D, A,  4, 20, 0xE7D3FBC8 );
    P2( X, &A, B, C, D,  9,  5, 0x21E1CDE6 );
    P2( X, &D, A, B, C, 14,  9, 0xC33707D6 );
    P2( X, &C, D, A, B,  3, 14, 0xF4D50D87 );
    P2( X, &B, C, D, A,  8, 20, 0x455A14ED );
    P2( X, &A, B, C, D, 13,  5, 0xA9E3E905 );
    P2( X, &D, A, B, C,  2,  9, 0xFCEFA3F8 );
    P2( X, &C, D, A, B,  7, 14, 0x676F02D9 );
    P2( X, &B, C, D, A, 12, 20, 0x8D2A4C8A );
    P3( X, &A, B, C, D,  5,  4, 0xFFFA3942 );
    P3( X, &D, A, B, C,  8, 11, 0x8771F681 );
    P3( X, &C, D, A, B, 11, 16, 0x6D9D6122 );
    P3( X, &B, C, D, A, 14, 23, 0xFDE5380C );
    P3( X, &A, B, C, D,  1,  4, 0xA4BEEA44 );
    P3( X, &D, A, B, C,  4, 11, 0x4BDECFA9 );
    P3( X, &C, D, A, B,  7, 16, 0xF6BB4B60 );
    P3( X, &B, C, D, A, 10, 23, 0xBEBFBC70 );
    P3( X, &A, B, C, D, 13,  4, 0x289B7EC6 );
    P3( X, &D, A, B, C,  0, 11, 0xEAA127FA );
    P3( X, &C, D, A, B,  3, 16, 0xD4EF3085 );
    P3( X, &B, C, D, A,  6, 23, 0x04881D05 );
    P3( X, &A, B, C, D,  9,  4, 0xD9D4D039 );
    P3( X, &D, A, B, C, 12, 11, 0xE6DB99E5 );
    P3( X, &C, D, A, B, 15, 16, 0x1FA27CF8 );
    P3( X, &B, C, D, A,  2, 23, 0xC4AC5665 );
    P4( X, &A, B, C, D,  0,  6, 0xF4292244 );
    P4( X, &D, A, B, C,  7, 10, 0x432AFF97 );
    P4( X, &C, D, A, B, 14, 15, 0xAB9423A7 );
    P4( X, &B, C, D, A,  5, 21, 0xFC93A039 );
    P4( X, &A, B, C, D, 12,  6, 0x655B59C3 );
    P4( X, &D, A, B, C,  3, 10, 0x8F0CCC92 );
    P4( X, &C, D, A, B, 10, 15, 0xFFEFF47D );
    P4( X, &B, C, D, A,  1, 21, 0x85845DD1 );
    P4( X, &A, B, C, D,  8,  6, 0x6FA87E4F );
    P4( X, &D, A, B, C, 15, 10, 0xFE2CE6E0 );
    P4( X, &C, D, A, B,  6, 15, 0xA3014314 );
    P4( X, &B, C, D, A, 13, 21, 0x4E0811A1 );
    P4( X, &A, B, C, D,  4,  6, 0xF7537E82 );
    P4( X, &D, A, B, C, 11, 10, 0xBD3AF235 );
    P4( X, &C, D, A, B,  2, 15, 0x2AD7D2BB );
    P4( X, &B, C, D, A,  9, 21, 0xEB86D391 );
    ctx->state[0] += A;
    ctx->state[1] += B;
    ctx->state[2] += C;
    ctx->state[3] += D; }

void md5_update( md5_context *ctx, uint8 *input, uint32 length )
  { uint32 left, fill;
    if( length < 1 ) return;
    left = ctx->total[0] & 0x3F;
    fill = 64 - left;
    ctx->total[0] += length;
    ctx->total[0] &= 0xFFFFFFFF;
    if( ctx->total[0] < length )
        ctx->total[1]++;
    if( left && length >= fill )
      { memcpy( (void *) (ctx->buffer + left),
                (void *) input, fill );
        md5_process( ctx, ctx->buffer );
        length -= fill;
        input  += fill;
        left = 0; }
    while( length >= 64 )
      { md5_process( ctx, input );
        length -= 64;
        input  += 64; }
    if( length >= 1 )
      memcpy( (void *) (ctx->buffer + left),
              (void *) input, length ); }

void md5_finish( md5_context *ctx, uint8 digest[16] )
  { static uint8 md5_padding[64] =
     { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    uint32 last, padn;
    uint32 high, low;
    uint8 msglen[8];
    high = ( ctx->total[0] >> 29 )
         | ( ctx->total[1] <<  3 );
    low  = ( ctx->total[0] <<  3 );
    PUT_UINT32( low,  msglen, 0 );
    PUT_UINT32( high, msglen, 4 );
    last = ctx->total[0] & 0x3F;
    padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
    md5_update( ctx, md5_padding, padn );
    md5_update( ctx, msglen, 8 );
    PUT_UINT32( ctx->state[0], digest,  0 );
    PUT_UINT32( ctx->state[1], digest,  4 );
    PUT_UINT32( ctx->state[2], digest,  8 );
    PUT_UINT32( ctx->state[3], digest, 12 ); }
/* --- end-of-function md5str() and "friends" --- */


/* ==========================================================================
 * Functions:	int  unescape_url ( char *url )
 *		char x2c ( char *what )
 * Purpose:	unescape_url replaces 3-character sequences %xx in url
 *		    with the single character represented by hex xx.
 *		x2c returns the single character represented by hex xx
 *		    passed as a 2-character sequence in what.
 * --------------------------------------------------------------------------
 * Arguments:	url (I)		char * containing null-terminated
 *				string with embedded %xx sequences
 *				to be converted.
 *		what (I)	char * whose first 2 characters are
 *				interpreted as ascii representations
 *				of hex digits.
 * --------------------------------------------------------------------------
 * Returns:	( int )		length of url string after replacements.
 *		( char )	x2c returns the single char
 *				corresponding to hex xx passed in what.
 * --------------------------------------------------------------------------
 * Notes:     o	These two functions were taken from util.c in
 *   ftp://ftp.ncsa.uiuc.edu/Web/httpd/Unix/ncsa_httpd/cgi/ncsa-default.tar.Z
 *	      o	Added ^M,^F,etc, and +'s to blank xlation 0n 01-Oct-06
 * ======================================================================= */
/* --- entry point --- */
int unescape_url ( char *url ) {
    int x=0, y=0;
    char x2c();
    static char *hex="0123456789ABCDEFabcdef";
    int xlatectrl=1, xlateblank=0/*1*/;
    /* ---
     * first xlate ctrl chars and +'s to blanks
     * ---------------------------------------- */
    if ( xlatectrl || xlateblank ) {	/*xlate ctrl chars and +'s to blanks*/
      char *ctrlchars = (!xlateblank? "\n\t\v\b\r\f\a\015" :
           (!xlatectrl? "+" : "+\n\t\v\b\r\f\a\015" ));
      int  urllen = strlen(url);	/* total length of url string */
      /* --- replace ctrlchars with blanks --- */
      while ( (x=strcspn(url,ctrlchars)) < urllen ) /* found a ctrlchar */
	url[x] = ' ';			/*replace ctrl char or + with blank*/
      /* --- get rid of leading/trailing ctrlchars (now whitespace) --- */
      trimwhite(url);			/*remove leading/trailing whitespace*/
      } /* --- end-of-if(xlatectrl||xlateblank) --- */
    /* ---
     * now xlate %nn to corresponding char (original ncsa code)
     * -------------------------------------------------------- */
    for(x=y=0;url[y];++x,++y)
      if((url[x] = url[y]) == '%')
	if(isthischar(url[y+1],hex)
	&& isthischar(url[y+2],hex))
	  { url[x] = x2c(&url[y+1]);
	    y+=2; }
    url[x] = '\000';
    return x;
} /* --- end-of-function unescape_url() --- */
/* --- entry point --- */
char x2c(char *what) {
    char digit;
    digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
    digit *= 16;
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
    return(digit);
} /* --- end-of-function x2c() --- */


/* ==========================================================================
 * Function:	timelimit ( char *command, int killtime )
 * Purpose:	Issues a system(command) call, but throttles command
 *		after killtime seconds if it hasn't already completed.
 * --------------------------------------------------------------------------
 * Arguments:	command (I)	char * to null-terminated string
 *				containing system(command) to be executed
 *		killtime (I)	int containing maximum #seconds
 *				to allow command to run
 *				to array of returned arg strings
 * --------------------------------------------------------------------------
 * Returns:	( int )		return status from command,
 *				or -1 for any error.
 * --------------------------------------------------------------------------
 * Notes:     o	The timelimit() code is adapted from
 *		   http://devel.ringlet.net/sysutils/timelimit/
 *		Compile with -DTIMELIMIT=\"$(which timelimit)\" to use an
 *		installed copy of timelimit rather than this built-in code.
 *	      o if symbol ISCOMPILETIMELIMIT is false, a stub function
 *		that just issues system(command) is compiled instead.
 * ======================================================================= */
#if !ISCOMPILETIMELIMIT
/* --- entry point for stub timelimit() function --- */
int	timelimit(char *command, int killtime) {
  if ( isempty(command) )		/* no command given */
    return( (killtime==(-99)?991:(-1)) ); /* return -1 or stub identifier */
  return ( system(command) ); }		/* just issue system(command) */
#else
/* --- entry points for signal handlers --- */
void	sigchld(int sig)    { fdone  = 1; }
void	sigalrm(int sig)    { falarm = 1; }
void	sighandler(int sig) { sigcaught = sig; fsig = 1; }

/* --- entry point --- */
int	timelimit(char *command, int killtime)
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
pid_t	pid = 0;
int	killsig = (int)(SIGKILL);
int	setsignal();
int	status = (-1);
/* -------------------------------------------------------------------------
check args
-------------------------------------------------------------------------- */
if ( isempty(command) )			/* no command given */
  return( (killtime==(-99)?992:(-1)) );	/* return -1 or built-in identifier*/
if ( killtime < 1   ) return ( system(command) ); /* throttling disabled */
if ( killtime > 999 ) killtime = 999;	/* default maximum to 999 seconds */
/* -------------------------------------------------------------------------
install signal handlers
-------------------------------------------------------------------------- */
fdone = falarm = fsig = sigcaught = 0;
if ( setsignal(SIGALRM, sigalrm)    < 0 ) return(-1);
if ( setsignal(SIGCHLD, sigchld)    < 0 ) return(-1);
if ( setsignal(SIGTERM, sighandler) < 0 ) return(-1);
if ( setsignal(SIGHUP,  sighandler) < 0 ) return(-1);
if ( setsignal(SIGINT,  sighandler) < 0 ) return(-1);
if ( setsignal(SIGQUIT, sighandler) < 0 ) return(-1);
/* -------------------------------------------------------------------------
fork off the child process
-------------------------------------------------------------------------- */
fflush(NULL);				/* flush all buffers before fork */
if ( (pid=fork()) < 0 ) return(-1);	/* failed to fork */
if ( pid == 0 ) {			/* child process... */
  status = system(command);		/* ...submits command */
  _exit(status); }			/* and _exits without user cleanup */
/* -------------------------------------------------------------------------
parent process sleeps for allowed time
-------------------------------------------------------------------------- */
alarm(killtime);
while ( !(fdone||falarm||fsig) ) pause();
alarm(0);
/* -------------------------------------------------------------------------
send kill signal if child hasn't completed command
-------------------------------------------------------------------------- */
if ( fsig )  return(-1);		/* some other signal stopped child */
if ( !fdone ) kill(pid, killsig);	/* not done, so kill it */
/* -------------------------------------------------------------------------
return status of child pid
-------------------------------------------------------------------------- */
if ( waitpid(pid, &status, 0) == -1 ) return(-1); /* can't get status */
if ( 1 ) return(status);		/* return status to caller */
#if 0					/* interpret status */
  if ( WIFEXITED(status) )
	return (WEXITSTATUS(status));
  else if ( WIFSIGNALED(status) )
	return (WTERMSIG(status) + 128);
  else
	return (EX_OSERR);
#endif
} /* --- end-of-function timelimit() --- */

/* --- entry point --- */
int	setsignal ( int sig, void (*handler)(int) )
{
 #ifdef HAVE_SIGACTION
    struct  sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = handler;
    act.sa_flags = 0;
    #ifdef SA_NOCLDSTOP
      act.sa_flags |= SA_NOCLDSTOP;
    #endif
    if (sigaction(sig, &act, NULL) < 0) return(-1);
 #else
    if (signal(sig, handler) == SIG_ERR) return(-1);
 #endif
    return(0);
} /* --- end-of-function setsignal() --- */
#endif /* ISCOMPILETIMELIMIT */


/* ==========================================================================
 * Function:	getdirective(string, directive, iscase, isvalid, nargs, args)
 * Purpose:	Locates the first \directive{arg1}...{nargs} in string,
 *		returns arg1...nargs in args[],
 *		and removes \directive and its args from string.
 * --------------------------------------------------------------------------
 * Arguments:	string (I/0)	char * to null-terminated string from which
 *				the first occurrence of \directive will be
 *				interpreted and removed
 *		directive (I)	char * to null-terminated string containing
 *				the \directive to be interpreted in string
 *		iscase (I)	int containing 1 if match of \directive
 *				in string should be case-sensitive,
 *				or 0 if match is case-insensitive.
 *		isvalid (I)	int containing validity check option:
 *				0=no checks, 1=must be numeric
 *		nargs (I)	int containing (maximum) number of
 *				{args} following \directive, or 0 if none.
 *		args (O)	void * interpreted as (char *) if nargs=1
 *				to return the one and only arg,
 *				or interpreted as (char **) if nargs>1
 *				to array of returned arg strings
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to first char after removed \directive, or
 *				NULL if \directive not found, or any error.
 * --------------------------------------------------------------------------
 * Notes:     o	If optional [arg]'s are found, they're stored in the global
 *		optionalargs[] buffer, and the noptional counter is bumped.
 *	      o	set global argformat's decimal digits for each arg,
 *		e.g., 1357... means 1 for 1st arg, 3 for 2nd, 5 for 3rd, etc.
 *		0 for an arg is the default format (i.e., argformat=0),
 *		and means it's formatted as a LaTeX {arg} or [arg].
 *		1 for an arg means arg terminated by first non-alpha char
 *		2 means arg terminated by {   (e.g., as for /def)
 *		8 means arg terminated by first whitespace char
 * ======================================================================= */
/* --- entry point --- */
char	*getdirective ( char *string, char *directive,
	int iscase, int isvalid, int nargs, void *args )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	iarg = (-1);			/* init to signal error */
char	*pfirst = NULL,			/* ptr to 1st char of directive */
	*plast = NULL,			/* ptr past last char of last arg */
	*plbrace=NULL, *prbrace=NULL;	/* ptr to left,right brace of arg */
int	fldlen = 0;			/* #chars between { and } delims */
char	argfld[512];			/* {arg} characters */
int	nfmt=0,isnegfmt=0,argfmt[9]={0,0,0,0,0,0,0,0,0}; /*argformat digits*/
int	gotargs = (args==NULL?0:1);	/* true if args array supplied */
int	isdalpha = 1;			/* true if directive ends with alpha*/
char	*strpspn(char *s,char *reject,char *segment); /*non-() not in rej*/
/* -------------------------------------------------------------------------
Find first \directive in string
-------------------------------------------------------------------------- */
noptional = 0;				/* no optional [args] yet */
for ( iarg=0; iarg<8; iarg++ )		/* for each one... */
  *optionalargs[iarg] = '\000';		/* re-init optional [arg] buffer */
if ( argformat != 0 ) {			/* have argformat */
  int	myfmt = argformat;		/* local copy */
  if ( myfmt < 0 ) { isnegfmt=1; myfmt=(-myfmt); } /* check sign */
  while ( myfmt>0 && nfmt<9 ) {		/* have more format digits */
    argfmt[nfmt] = myfmt%10;		/* store low-order decimal digit */
    myfmt /= 10;			/* and shift it out */
    nfmt++; }				/* count another format digit */
  } /* --- end-of-if(argformat!=0) --- */
if ( isempty(directive) ) goto end_of_job; /* no input \directive given */
if ( !isalpha((int)(directive[strlen(directive)-1])) )isdalpha=0;/*not alpha*/
pfirst = string;			/* start at beginning of string */
while ( 1 ) {				/* until we find \directive */
  if ( !isempty(pfirst) )		/* still have string from caller */
    pfirst =				/* ptr to 1st char of directive */
     (iscase>0? strstr(pfirst,directive): /* case-sensistive match */
      strcasestr(pfirst,directive));	/* case-insensistive match */
  if ( isempty(pfirst) ) {		/* \directive not found in string */
    pfirst = NULL;			/* signal \directive not found */
    goto end_of_job; }			/* quit, signalling error to caller*/
  plast = pfirst + strlen(directive);	/*ptr to fist char past directive*/
  if ( !isdalpha || !isalpha((int)(*plast)) ) break; /* found \directive */
  pfirst = plast;			/* keep looking */
  plast = NULL;				/* reset plast */
  } /* --- end-of-while(1) --- */
if ( nargs < 0 ) {			/* optional [arg] may be present */
  nargs = -nargs;			/* flip sign back to positive */
  /*noptional = 1;*/ }			/* and set optional flag */
/* -------------------------------------------------------------------------
Get arguments
-------------------------------------------------------------------------- */
iarg = 0;				/* no args yet */
if ( nargs > 0 )			/* \directive has {args} */
  while ( iarg < nargs+noptional ) {	/* get each arg */
    int karg = iarg-noptional;		/* non-optional arg index */
    int kfmt = (nfmt<=karg?0:argfmt[nfmt-karg-1]); /* arg format digit */
    /* --- find left { and right } arg delimiters --- */
    plbrace = plast;			/*ptr to fist char past previous arg*/
    skipwhite(plbrace);			/* push it to first non-white char */
    if ( isempty(plbrace) ) break;	/* reached end-of-string */
    /* --- check LaTeX for single-char arg or {arg} or optional [arg] --- */
    if ( kfmt == 0 ) {			/* interpret LaTeX {arg} format */
     if ( !isthischar(*plbrace,(iarg==optionalpos+noptional?"{[":"{")) ) {
      /* --- single char argument --- */
      plast = plbrace + 1;		/* first char after single-char arg*/
      argfld[0] = *plbrace;		/* arg field is this one char */
      argfld[1] = '\000'; }		/* null-terminate field */
     else {				/* have {arg} or optional [arg] */
      /* note: to use for validation, need robust {} match like strpspn() */
      if ( (prbrace = strchr(plbrace,(*plbrace=='{'?'}':']'))) /*right }or]*/
      ==   NULL ) break;		/*and no more args if no right brace*/
      if ( 1 )				/* true to use strpspn() */
	prbrace = strpspn(plbrace,NULL,NULL); /* push to matching } or ] */
      plast = prbrace + 1;		/* first char after right brace */
      /* --- extract arg field between { and } delimiters --- */
      fldlen = (int)(prbrace-plbrace) - 1; /* #chars between { and } delims*/
      if ( fldlen >= 256 ) fldlen=255;	/* don't overflow argfld[] buffer */
      if ( fldlen > 0 )			/* have chars in field */
        memcpy(argfld,plbrace+1,fldlen); /*copy field chars to local buffer*/
      argfld[fldlen] = '\000';		/* and null-terminate field */
      trimwhite(argfld);		/* trim whitespace from argfld */
      } /* --- end-of-if/else(!isthischar(*plbrace,...)) --- */
     } /* --- end-of-if(kfmt==0) --- */
    /* --- check plain TeX for arg terminated by whitespace --- */
    if ( kfmt != 0 ) {			/* interpret plain TeX arg format */
     char *parg = NULL;			/* ptr into arg, used as per kfmt */
     plast = plbrace;			/* start at first char of arg */
     if ( *plast == '\\' ) plast++;	/* skip leading \command backslash */
     /* --- interpret arg according to its format --- */
     switch ( kfmt ) {
       case 1:
       default: skipcommand(plast); break; /* push ptr to non-alpha char */
       case 2: parg = strchr(plast,'{'); /* next arg always starts with { */
	if ( parg != NULL ) plast=parg; else plast++; /* up to { or 1 char */
	break;
       case 8: findwhite(plast); break;	/*ptr to whitespace after last char*/
       } /* --- end-of-switch(kfmt) --- */
     /* --- extract arg field --- */
     fldlen = (int)(plast-plbrace);	/* #chars between in field */
     if ( fldlen >= 256 ) fldlen=255;	/* don't overflow argfld[] buffer */
     if ( fldlen > 0 )			/* have chars in field */
       memcpy(argfld,plbrace,fldlen);	/*copy field chars to local buffer*/
     argfld[fldlen] = '\000';		/* and null-terminate field */
     if ( 1 ) { trimwhite(argfld); }	/* trim whitespace from argfld */
     } /* --- end-of-if(kfmt!=0) --- */
    if ( isvalid != 0 ) {		/* argfld[] validity check desired */
     if ( isvalid == 1 ) {		/* numeric check wanted */
       int validlen = strspn(argfld," +-.0123456789"); /*very simple check*/
       argfld[validlen] = '\000'; }	/* truncate invalid chars */
     } /* --- end-of-if(isvalid!=0) --- */
    /* --- store argument field in caller's array --- */
    if ( kfmt==0 && *plbrace=='[' ) {	/*store [arg] as optionalarg instead*/
     if ( noptional < 8 ) {		/* don't overflow our buffer */
       strninit(optionalargs[noptional],argfld,254); } /*copy to optionalarg*/
     noptional++; }			/* count another optional [arg] */
    else				/*{args} returned in caller's array*/
     if ( gotargs ) {			/*caller supplied address or array*/
      if ( nargs < 2 )			/*just one arg, so it's an address*/ 
        strcpy((char *)args,argfld);	/* so copy arg field there */
      else {				/* >1 arg, so it's a ptr array */
	char *argptr = ((char **)args)[karg]; /* arg ptr in array of ptrs */
	if ( argptr != NULL )		/* array has iarg-th address */
	  strcpy(argptr,argfld);	/* so copy arg field there */
	else gotargs = 0; } }		/* no more addresses in array */
    /* --- completed this arg --- */
    iarg++;				/* bump arg count */
    } /* --- end-of-while(iarg<nargs) --- */
/* -------------------------------------------------------------------------
Back to caller
-------------------------------------------------------------------------- */
end_of_job:
  if ( 1 ) argformat = 0;		/* always/never reset global arg */
  if ( 1 ) optionalpos = 0;		/* always/never reset global arg */
  if ( pfirst!=NULL && plast!=NULL )	/* have directive field delims */
    strcpy(pfirst,plast);		/*squeeze directive out of string*/
  return ( pfirst );			/* ptr to 1st char after directive */
} /* --- end-of-function getdirective() --- */


/* ==========================================================================
 * Function:	mathprep ( expression )
 * Purpose:	preprocessor for mathTeX input, e.g.,
 *		(a) removes leading/trailing $'s from $$expression$$
 *		(b) xlates &html; special chars to equivalent latex
 *		(c) xlates &#nnn; special chars to equivalent latex
 *		Should only be called once (after unescape_url())
 * --------------------------------------------------------------------------
 * Arguments:	expression (I/O) char * to first char of null-terminated
 *				string containing mathTeX/LaTeX expression,
 *				and returning preprocessed string
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to input expression,
 *				or NULL for any parsing error.
 * --------------------------------------------------------------------------
 * Notes:     o	The ten special symbols  $ & % # _ { } ~ ^ \  are reserved
 *		for use in LaTeX commands.  The corresponding directives
 *		\$ \& \% \# \_ \{ \}  display the first seven, respectively,
 *		and \backslash displays \.  It's not clear to me whether
 *		or not mathprep() should substitute the displayed symbols,
 *		e.g., whether &#36; better xlates to \$ or to $.
 *		Right now, it's the latter.
 * ======================================================================= */
/* --- entry point --- */
char	*mathprep ( char *expression )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	isym=0, inum=0;			/* symbols[], numbers[] indexes */
char	*strchange();			/* change leading chars of string */
char	*strwstr();			/*use strwstr() instead of strstr()*/
int	strreplace();			/* substitute/from/to/ */
int	ndollars = 0;			/* #leading/trailing $$...$$'s */
int	explen = (isempty(expression)?0:strlen(expression)); /*#input chars*/
/* ---
 * html special/escape chars converted to latex equivalents
 * -------------------------------------------------------- */
char	*htmlsym=NULL;			/* symbols[isym].html */
static	struct { char *html; char *termchar; char *latex; } symbols[] =
 { /* ---------------------------------------------------------
     user-supplied newcommands (different than -DNEWCOMMAND)
   --------------------------------------------------------- */
 #ifdef NEWCOMMANDS			/* -DNEWCOMMANDS=\"filename.h\" */
   #include NEWCOMMANDS
 #endif
   /* ----------------------------------------
    html char termchar  LaTeX equivalent...
   ---------------------------------------- */
   { "&quot",	";",	"\"" },		/* &quot; is first, &#034; */
   { "&amp",	";",	"&" },
   { "&lt",	";",	"<" },
   { "&gt",	";",	">" },
   { "&backslash",";",	"\\" },
   { "&nbsp",	";",	" " /*"~"*/ },
   { "&iexcl",	";",	"{\\mbox{!`}}" },
   { "&brvbar",	";",	"|" },
   { "&plusmn",	";",	"\\pm" },
   { "&sup2",	";",	"{{}^2}" },
   { "&sup3",	";",	"{{}^3}" },
   { "&micro",	";",	"\\mu" },
   { "&sup1",	";",	"{{}^1}" },
   { "&frac14",	";",	"{\\frac14}" },
   { "&frac12",	";",	"{\\frac12}" },
   { "&frac34",	";",	"{\\frac34}" },
   { "&iquest",	";",	"{\\mbox{?`}}" },
   { "&Acirc",	";",	"{\\rm\\hat A}" },
   { "&Atilde",	";",	"{\\rm\\tilde A}" },
   { "&Auml",	";",	"{\\rm\\ddot A}" },
   { "&Aring",	";",	"{\\overset{o}{\\rm A}}" },
   { "&atilde",	";",	"{\\rm\\tilde a}" },
   { "&yuml",	";",	"{\\rm\\ddot y}" },  /* &yuml; is last, &#255; */
   { "&#",	";",	"{[\\&\\#nnn?]}" },  /* all other &#nnn's */
   /* ----------------------------------------
    html tag  termchar  LaTeX equivalent...
   ---------------------------------------- */
   { "< br >",	NULL,	" \000" /*"\\\\"*/ },
   { "< br / >", NULL,	" \000" /*"\\\\"*/ },
   { "< dd >",	NULL,	" \000" },
   { "< / dd >", NULL,	" \000" },
   { "< dl >",	NULL,	" \000" },
   { "< / dl >", NULL,	" \000" },
   { "< p >",	NULL,	" \000" },
   { "< / p >",	NULL,	" \000" },
   /* ---------------------------------------
    garbage  termchar  LaTeX equivalent...
   --------------------------------------- */
   { "< tex >",	NULL,	"\000" },
   { "< / tex >", NULL,	"\000" },
   { NULL,	NULL,	NULL }
 } ; /* --- end-of-symbols[] --- */
/* ---
 * html &#nn chars converted to latex equivalents
 * ---------------------------------------------- */
int	htmlnum=0;			/* numbers[inum].html */
static	struct { int html; char *latex; } numbers[] =
 { /* ---------------------------------------
    html num  LaTeX equivalent...
   --------------------------------------- */
   { 9,		" " },			/* horizontal tab */
   { 10,	" " },			/* line feed */
   { 13,	" " },			/* carriage return */
   { 32,	" " },			/* space */
   { 33,	"!" },			/* exclamation point */
   { 34,	"\"" },			/* &quot; */
   { 35,	"#" },			/* hash mark */
   { 36,	"$" },			/* dollar */
   { 37,	"%" },			/* percent */
   { 38,	"&" },			/* &amp; */
   { 39,	"\'" },			/* apostrophe (single quote) */
   { 40,	")" },			/* left parenthesis */
   { 41,	")" },			/* right parenthesis */
   { 42,	"*" },			/* asterisk */
   { 43,	"+" },			/* plus */
   { 44,	"," },			/* comma */
   { 45,	"-" },			/* hyphen (minus) */
   { 46,	"." },			/* period */
   { 47,	"/" },			/* slash */
   { 58,	":" },			/* colon */
   { 59,	";" },			/* semicolon */
   { 60,	"<" },			/* &lt; */
   { 61,	"=" },			/* = */
   { 62,	">" },			/* &gt; */
   { 63,	"\?" },			/* question mark */
   { 64,	"@" },			/* commercial at sign */
   { 91,	"[" },			/* left square bracket */
   { 92,	"\\" },			/* backslash */
   { 93,	"]" },			/* right square bracket */
   { 94,	"^" },			/* caret */
   { 95,	"_" },			/* underscore */
   { 96,	"`" },			/* grave accent */
   { 123,	"{" },			/* left curly brace */
   { 124,	"|" },			/* vertical bar */
   { 125,	"}" },			/* right curly brace */
   { 126,	"~" },			/* tilde */
   { 160,	"~" },			/* &nbsp; (use tilde for latex) */
   { 166,	"|" },			/* &brvbar; (broken vertical bar) */
   { 173,	"-" },			/* &shy; (soft hyphen) */
   { 177,	"{\\pm}" },		/* &plusmn; (plus or minus) */
   { 215,	"{\\times}" },		/* &times; (plus or minus) */
   { -999,	NULL }
 } ; /* --- end-of-numbers[] --- */
/* -------------------------------------------------------------------------
initialization
-------------------------------------------------------------------------- */
if ( explen < 1 ) goto end_of_job;	/* no input expression supplied */
/* -------------------------------------------------------------------------
remove leading/trailing $$...$$'s and set mathmode accordingly
-------------------------------------------------------------------------- */
/* --- count and remove leading/trailing $'s from $$expression$$ --- */
while ( explen > 2 )			/* don't exhaust entire expression */
  if ( expression[0] == '$'		/* have leading $ char */
  &&   expression[explen-1] == '$' ) {	/* and trailing $ char */
    explen -= 2;			/* remove leading and trailing $'s */
    strcpy(expression,expression+1);	/* squeeze out leading $ */
    expression[explen] = '\000';	/* and terminate at trailing $ */
    ndollars++; }			/* count another dollar */
  else break;				/* no more $...$ pairs */
/* --- set mathmode for input $$expression$$ --- */
if ( ndollars > 0 )			/* have $$expression$$ input */
  switch ( ndollars ) {			/* set mathmode accordingly */
    case 1: mathmode = 1; break;	/* $...$ is \textstyle */
    case 2: mathmode = 0; break;	/* $$...$$ is \displaystyle */
    case 3: mathmode = 2; break;	/* $$$...$$$ is \parstyle */
    default: break; }			/* I have no idea what you want */
/* --- check for input \[expression\] if no $$'s --- */
if ( ndollars < 1 )			/* not an $$expression$$ */
  if ( explen > 4 )			/* long enough to contain \[...\] */
    if ( strncmp(expression,"\\[",2) == 0 /* so check for leading \[ */
    &&   strncmp(expression+explen-2,"\\]",2) == 0 ) { /* and trailing \] */
      explen -= 4;			/* remove leading/trailing \[...\] */
      strcpy(expression,expression+2);	/* squeeze out leading \[ */
      expression[explen] = '\000';	/* and terminate at trailing \] */
      mathmode = 0; }			/* set \displaystyle */
/* -------------------------------------------------------------------------
run thru table, converting all occurrences of each html to latex equivalent
-------------------------------------------------------------------------- */
for ( isym=0; (htmlsym=symbols[isym].html)!=NULL; isym++ )
  {
  char	*htmlterm = symbols[isym].termchar, /* &symbol; terminator */
	*latexsym = symbols[isym].latex, /* latex replacement */
	errorsym[256];			/* error message replacement */
  int	htmllen = strlen(htmlsym),	/* length of html token */
	wstrlen = htmllen,		/* token length found by strwstr() */
	latexlen = strlen(latexsym);	/* length of latex replacement */
  int	isstrwstr = 1,			/* true to use strwstr() */
	istag = (isthischar(*htmlsym,"<")?1:0),	/*html <tag> starts with <*/
	isamp = (isthischar(*htmlsym,"&")?1:0);	/*html char starts with & */
  char	wstrwhite[128] = "i";		/* whitespace chars for strwstr() */
  char	*expptr = expression,		/* ptr within expression */
	*tokptr = NULL;			/*ptr to token found in expression*/
  /* ---
   * xlate every occurrence of current htmlsym command
   * ------------------------------------------------- */
  skipwhite(htmlsym);			/*skip any bogus leading whitespace*/
  htmllen = wstrlen = strlen(htmlsym);	/*reset length of html token and...*/
  istag = (isthischar(*htmlsym,"<")?1:0); /* ...html <tag> starts with < */
  isamp = (isthischar(*htmlsym,"&")?1:0); /* ...html char starts with & */
  if ( isamp ) isstrwstr = 0;		/* don't use strwstr() for &char */
  if ( istag ) {			/* use strwstr() for <tag> */
    isstrwstr = 1;			/* make sure flag is set true */
    if ( !isempty(htmlterm) )		/* got a term char string */
      strninit(wstrwhite,htmlterm,64);	/* interpret it as whitespace arg */
    htmlterm = NULL; }			/* rather than as a terminater */
  while ( (tokptr=(!isstrwstr?strstr(expptr,htmlsym):  /*strtsr or strwstr*/
  strwstr(expptr,htmlsym,wstrwhite,&wstrlen))) /*looks for another htmlsym*/
  != NULL ) {				/* we found another htmlsym */
    char termchar = *(tokptr+wstrlen),	/* char terminating html sequence */
         prevchar = (tokptr==expptr?' ':*(tokptr-1)); /*char preceding tok*/
    int  toklen = wstrlen;		/* tot length of token+terminator */
    /* --- ignore match if leading char escaped (not really a match) --- */
    if ( isthischar(prevchar,"\\") ) {	/* inline symbol escaped */
        expptr = tokptr+toklen;		/*just resume search after literal*/
        continue; }			/* but don't replace it */
    /* --- ignore match if it's just a prefix of a longer expression --- */
    if ( !istag )			/*<br>-type command can't be prefix*/
      if ( isalpha((int)termchar) ) {	/*we just have prefix of longer sym*/
        expptr = tokptr+toklen;		/* just resume search after prefix */
        continue; }			/* but don't replace it */
    /* --- check for &# prefix signalling &#nnn --- */
    if ( strcmp(htmlsym,"&#") == 0 ) {	/* replacing special &#nnn; chars */
      /* --- accumulate chars comprising number following &# --- */
      char anum[32];			/* chars comprising number after &# */
      inum = 0;				/* no chars accumulated yet */
      while ( termchar != '\000' ) {	/* don't go past end-of-string */
        if ( !isdigit((int)termchar) ) break; /* and don't go past digits */
        if ( inum > 10 ) break;		/* some syntax error in expression */
        anum[inum] = termchar;		/* accumulate this digit */
        inum++;  toklen++;		/* bump field length, token length */
        termchar = *(tokptr+toklen); }	/* char terminating html sequence */
      anum[inum] = '\000';		/* null-terminate anum */
      /* --- look up &#nnn in number[] table --- */
      htmlnum = atoi(anum);		/* convert anum[] to an integer */
      latexsym = errorsym;		/* init latex replacement for error*/
      strninit(latexsym,symbols[isym].latex,128); /* init error message */
      strreplace(latexsym,"nnn",anum,1,1); /* place actual &#num in message*/
      latexlen = strlen(latexsym);	/* and length of latex replacement */
      for ( inum=0; numbers[inum].html>=0; inum++ ) /* run thru numbers[] */
        if ( htmlnum ==  numbers[inum].html ) { /* till we find a match */
	  latexsym = numbers[inum].latex; /* latex replacement */
	  latexlen = strlen(latexsym);	/* length of latex replacement */
          break; }			/* no need to look any further */
      } /* --- end-of-if(strcmp(htmlsym,"&#")==0) --- */
    /* --- check for optional ; terminator after &symbol --- */
    if ( !istag )			/* html <tag> doesn't have term. */
      if ( termchar != '\000' )		/* token not at end of expression */
        if ( !isempty(htmlterm) )	/* sequence may have terminator */
          toklen += (isthischar(termchar,htmlterm)?1:0); /*add terminator*/
    /* --- replace html command with latex equivalent --- */
    strchange(toklen,tokptr,latexsym);	/* replace html symbol with latex */
    expptr = tokptr + latexlen;		/* resume search after replacement */
    } /* --- end-of-while(tokptr!=NULL) --- */
  } /* --- end-of-for(isymbol) --- */
/* -------------------------------------------------------------------------
back to caller with preprocessed expression
-------------------------------------------------------------------------- */
trimwhite(expression);			/*remove leading/trailing whitespace*/
showmsg(99,"mathprep expression",expression); /*show preprocessed expression*/
end_of_job:
  return ( expression );
} /* --- end-of-function mathprep() --- */


/* ==========================================================================
 * Function:	strwstr (char *string, char *substr, char *white, int *sublen)
 * Purpose:	Find first substr in string, but wherever substr contains
 *		a whitespace char (in white), string may contain any number
 *		(including 0) of whitespace chars. If white contains I or i,
 *		then match is case-insensitive (and I,i _not_ whitespace).
 * --------------------------------------------------------------------------
 * Arguments:	string (I)	char * to null-terminated string in which
 *				first occurrence of substr will be found
 *		substr (I)	char * to null-terminated string containing
 *				"template" that will be searched for
 *		white (I)	char * to null-terminated string containing
 *				whitespace chars.  If NULL or empty, then
 *				" \t\n\r\f\v" (see #define WHITESPACE) used.
 *				If white contains I or i, then match is
 *				case-insensitive (and I,i _not_ considered
 *				whitespace).
 *		sublen (O)	address of int returning "length" of substr
 *				found in string (which may be longer or
 *				shorter than substr itself).
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to first char of substr in string
 *				or NULL if not found or for any error.
 * --------------------------------------------------------------------------
 * Notes:     o	Wherever a single whitespace char appears in substr,
 *		the corresponding position in string may contain any
 *		number (including 0) of whitespace chars, e.g.,
 *		string="abc   def" and string="abcdef" both match
 *		substr="c d" at offset 2 of string.
 *	      o	If substr="c  d" (two spaces between c and d),
 *		then string must have at least one space, so now "abcdef"
 *		doesn't match.  In general, the minimum number of spaces
 *		in string is the number of spaces in substr minus 1
 *		(so 1 space in substr permits 0 spaces in string).
 *	      o	Embedded spaces are counted in sublen, e.g.,
 *		string="c   d" (three spaces) matches substr="c d"
 *		with sublen=5 returned.  But string="ab   c   d" will
 *		also match substr="  c d" returning sublen=5 and
 *		a ptr to the "c".  That is, the mandatory preceding
 *		space is _not_ counted as part of the match.
 *		But all the embedded space is counted.
 *		(An inconsistent bug/feature is that mandatory
 *		terminating space is counted.)
 *	      o	Moreover, string="c   d" matches substr="  c d", i.e.,
 *		the very beginning of a string is assumed to be preceded
 *		by "virtual blanks".
 * ======================================================================= */
/* --- entry point --- */
char	*strwstr ( char *string, char *substr, char *white, int *sublen )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
char	*psubstr=substr, *pstring=string,/*ptr to current char in substr,str*/
	*pfound = (char *)NULL;		/*ptr to found substr back to caller*/
char	*pwhite=NULL, whitespace[256];	/* callers white whithout i,I */
int	iscase = 1;			/* case-insensitive if i,I in white*/
int	foundlen = 0;			/* length of substr found in string*/
int	nstrwhite=0, nsubwhite=0,	/* #leading white chars in str,sub */
	nminwhite=0;			/* #mandatory leading white in str */
int	nstrchars=0, nsubchars=0,	/* #non-white chars to be matched */
	isncmp=0;			/*strncmp() or strncasecmp() result*/
/* -------------------------------------------------------------------------
Initialization
-------------------------------------------------------------------------- */
/* --- set up whitespace --- */
strcpy(whitespace,WHITESPACE);		/*default if no user input for white*/
if ( white != NULL )			/*user provided ptr to white string*/
 if ( *white != '\000' ) {		/*and it's not just an empty string*/
   strcpy(whitespace,white);		/* so use caller's white spaces */
   while ( (pwhite=strchr(whitespace,'i')) != NULL ) /* have an embedded i */
     { iscase = 0; strcpy(pwhite,pwhite+1); } /*set flag and squeeze it out*/
   while ( (pwhite=strchr(whitespace,'I')) != NULL ) /* have an embedded I */
     { iscase = 0; strcpy(pwhite,pwhite+1); } /*set flag and squeeze it out*/
   if ( *whitespace == '\000' )		/* caller's white just had i,I */
     strcpy(whitespace,WHITESPACE); }	/* so revert back to default */
/* -------------------------------------------------------------------------
Find first occurrence of substr in string
-------------------------------------------------------------------------- */
if ( string != NULL )			/* caller passed us a string ptr */
 while ( *pstring != '\000' ) {		/* break when string exhausted */
  char	*pstrptr = pstring;		/* (re)start at next char in string*/
  int	leadingwhite = 0;		/* leading whitespace */
  psubstr = substr;			/* start at beginning of substr */
  foundlen = 0;				/* reset length of found substr */
  if ( substr != NULL )			/* caller passed us a substr ptr */
   while ( *psubstr != '\000' ) {	/*see if pstring begins with substr*/
    /* --- check for end-of-string before finding match --- */
    if ( *pstrptr == '\000' )		/* end-of-string without a match */
      goto nextstrchar;			/* keep trying with next char */
    /* --- actual amount of whitespace in string and substr --- */
    nsubwhite = strspn(psubstr,whitespace); /* #leading white chars in sub */
    nstrwhite = strspn(pstrptr,whitespace); /* #leading white chars in str */
    nminwhite = max2(0,nsubwhite-1);	/* #mandatory leading white in str */
    /* --- check for mandatory leading whitespace in string --- */
    if ( pstrptr != string )		/*not mandatory at start of string*/
      if ( nstrwhite < nminwhite )	/* too little leading white space */
	goto nextstrchar;		/* keep trying with next char */
    /* ---hold on to #whitespace chars in string preceding substr match--- */
    if ( pstrptr == pstring )		/* whitespace at start of substr */
      leadingwhite = nstrwhite;		/* save it as leadingwhite */
    /* --- check for optional whitespace --- */
    if ( psubstr != substr )		/* always okay at start of substr */
      if ( nstrwhite>0 && nsubwhite<1 )	/* too much leading white space */
	goto nextstrchar;		/* keep trying with next char */
    /* --- skip any leading whitespace in substr and string --- */
    psubstr += nsubwhite;		/* push past leading sub whitespace*/
    pstrptr += nstrwhite;		/* push past leading str whitespace*/
    /* --- now get non-whitespace chars that we have to match --- */
    nsubchars = strcspn(psubstr,whitespace); /* #non-white chars in sub */
    nstrchars = strcspn(pstrptr,whitespace); /* #non-white chars in str */
    if ( nstrchars < nsubchars )	/* too few chars for match */
      goto nextstrchar;			/* keep trying with next char */
    /* --- see if next nsubchars are a match --- */
    isncmp = (iscase? strncmp(pstrptr,psubstr,nsubchars): /*case sensitive*/
		strncasecmp(pstrptr,psubstr,nsubchars)); /*case insensitive*/
    if ( isncmp != 0 )			/* no match */
      goto nextstrchar;			/* keep trying with next char */
    /* --- push past matched chars --- */
    psubstr += nsubchars;  pstrptr += nsubchars;  /*nsubchars were matched*/
    } /* --- end-of-while(*psubstr!='\000') --- */
  pfound = pstring + leadingwhite;	/* found match starting at pstring */
  foundlen = (int)(pstrptr-pfound);	/* consisting of this many chars */
  goto end_of_job;			/* back to caller */
  /* ---failed to find substr, continue trying with next char in string--- */
  nextstrchar:				/* continue outer loop */
    pstring++;				/* bump to next char in string */
  } /* --- end-of-while(*pstring!='\000') --- */
/* -------------------------------------------------------------------------
Back to caller with ptr to first occurrence of substr in string
-------------------------------------------------------------------------- */
end_of_job:
  if ( msgfp!=NULL && msglevel>=999 ) {	/* debugging/diagnostic output */
    fprintf(msgfp,"strwstr> str=\"%.72s\" sub=\"%s\" found at offset %d\n",
    string,substr,(pfound==NULL?(-1):(int)(pfound-string))); fflush(msgfp); }
  if ( sublen != NULL )			/*caller wants length of found substr*/
    *sublen = foundlen;			/* give it to him along with ptr */
  return ( pfound );			/*ptr to first found substr, or NULL*/
} /* --- end-of-function strwstr() --- */


/* ==========================================================================
 * Function:	strreplace ( string, from, to, iscase, nreplace )
 * Purpose:	Changes the first nreplace occurrences of 'from' to 'to'
 *		in string, or all occurrences if nreplace=0.
 * --------------------------------------------------------------------------
 * Arguments:	string (I/0)	char * to null-terminated string in which
 *				occurrence of 'from' will be replaced by 'to'
 *		from (I)	char * to null-terminated string
 *				to be replaced by 'to'
 *		to (I)		char * to null-terminated string that will
 *				replace 'from'
 *		iscase (I)	int containing 1 if matches of 'from'
 *				in 'string' should be case-sensitive,
 *				or 0 if matches are case-insensitive.
 *		nreplace (I)	int containing (maximum) number of
 *				replacements, or 0 to replace all.
 * --------------------------------------------------------------------------
 * Returns:	( int )		number of replacements performed,
 *				or 0 for no replacements or -1 for any error.
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	strreplace ( char *string, char *from, char *to,
	int iscase, int nreplace )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	fromlen = (from==NULL?0:strlen(from)), /* #chars to be replaced */
	tolen = (to==NULL?0:strlen(to)); /* #chars in replacement string */
int	iscommand = (fromlen<2?0:(*from=='\\'?1:0)); /*is from a \command ?*/
char	*pfrom = (char *)NULL,		/*ptr to 1st char of from in string*/
	*pstring = string,		/*ptr past previously replaced from*/
	*strchange();			/* change 'from' to 'to' */
/*int	iscase = 1;*/			/* true for case-sensitive match */
int	nreps = 0;			/* #replacements returned to caller*/
/* -------------------------------------------------------------------------
repace occurrences of 'from' in string to 'to'
-------------------------------------------------------------------------- */
if ( string == (char *)NULL		/* no input string */
||   (fromlen<1 && nreplace<=0) )	/* replacing empty string forever */
  nreps = (-1);				/* so signal error */
else					/* args okay */
  while (nreplace<1 || nreps<nreplace) { /* up to #replacements requested */
    if ( fromlen > 0 )			/* have 'from' string */
      pfrom =				/*ptr to 1st char of from in string*/
       (iscase>0? strstr(pstring,from):	/* case-sensistive match */
        strcasestr(pstring,from));	/* case-insensistive match */
    else  pfrom = pstring;		/*or empty from at start of string*/
    if ( pfrom == (char *)NULL ) break;	/*no more from's, so back to caller*/
    if ( iscommand )			/* ignore prefix of longer string */
      if ( isalpha((int)(*(pfrom+fromlen))) ) {	/* just a longer string */
        pstring = pfrom+fromlen;	/* pick up search after 'from' */
        continue; }			/* don't change anything */
    if ( iscase > 1 ) { ; }		/* ignore \escaped matches */
    if ( strchange(fromlen,pfrom,to)	/* leading 'from' changed to 'to' */
    ==   (char *)NULL ) { nreps=(-1); break; } /* signal error to caller */
    nreps++;				/* count another replacement */
    pstring = pfrom+tolen;		/* pick up search after 'to' */
    if ( *pstring == '\000' ) break;	/* but quit at end of string */
    } /* --- end-of-while() --- */
return ( nreps );			/* #replacements back to caller */
} /* --- end-of-function strreplace() --- */


/* ==========================================================================
 * Function:	strchange ( nfirst, from, to )
 * Purpose:	Changes the nfirst leading chars of `from` to `to`.
 *		For example, to change char x[99]="12345678" to "123ABC5678"
 *		call strchange(1,x+3,"ABC")
 * --------------------------------------------------------------------------
 * Arguments:	nfirst (I)	int containing #leading chars of `from`
 *				that will be replace by `to`
 *		from (I/O)	char * to null-terminated string whose nfirst
 *				leading chars will be replaced by `to`
 *		to (I)		char * to null-terminated string that will
 *				replace the nfirst leading chars of `from`
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to first char of input `from`
 *				or NULL for any error.
 * --------------------------------------------------------------------------
 * Notes:     o	If strlen(to)>nfirst, from must have memory past its null
 *		(i.e., we don't do a realloc)
 * ======================================================================= */
/* --- entry point --- */
char	*strchange ( int nfirst, char *from, char *to )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	tolen = (to==NULL?0:strlen(to)), /* #chars in replacement string */
	nshift = abs(tolen-nfirst);	/*need to shift from left or right*/
/* -------------------------------------------------------------------------
shift from left or right to accommodate replacement of its nfirst chars by to
-------------------------------------------------------------------------- */
if ( tolen < nfirst )			/* shift left is easy */
  strcpy(from,from+nshift);		/* because memory doesn't overlap */
if ( tolen > nfirst )			/* need more room at start of from */
  { char *pfrom = from+strlen(from);	/* ptr to null terminating from */
    for ( ; pfrom>=from; pfrom-- )	/* shift all chars including null */
      *(pfrom+nshift) = *pfrom; }	/* shift chars nshift places right */
/* -------------------------------------------------------------------------
from has exactly the right number of free leading chars, so just put to there
-------------------------------------------------------------------------- */
if ( tolen != 0 )			/* make sure to not empty or null */
  memcpy(from,to,tolen);		/* chars moved into place */
return ( from );			/* changed string back to caller */
} /* --- end-of-function strchange() --- */


/* ==========================================================================
 * Function:	isstrstr ( char *string, char *snippets, int iscase )
 * Purpose:	determine whether any substring of 'string'
 *		matches any of the comma-separated list of 'snippets',
 *		ignoring case if iscase=0.
 * --------------------------------------------------------------------------
 * Arguments:	string (I)	char * containing null-terminated
 *				string that will be searched for
 *				any one of the specified snippets
 *		snippets (I)	char * containing null-terminated,
 *				comma-separated list of snippets
 *				to be searched for in string
 *		iscase (I)	int containing 0 for case-insensitive
 *				comparisons, or 1 for case-sensitive
 * --------------------------------------------------------------------------
 * Returns:	( int )		1 if any snippet is a substring of
 *				string, 0 if not
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	isstrstr ( char *string, char *snippets, int iscase )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	status = 0;			/*1 if any snippet found in string*/
char	snip[256], *snipptr = snippets,	/* munge through each snippet */
	delim = ',', *delimptr = NULL,	/* separated by delim's */
	*strstrptr = NULL;		/* looking for a match in string */
/* -------------------------------------------------------------------------
initialization
-------------------------------------------------------------------------- */
/* --- arg check --- */
if ( isempty(string)			/*both string and snippets required*/
||   isempty(snippets) ) goto end_of_job; /* quit if either missing */
/* -------------------------------------------------------------------------
extract each snippet and see if it's a substring of string
-------------------------------------------------------------------------- */
while ( snipptr != NULL ) {		/* while we still have snippets */
  /* --- extract next snippet --- */
  if ( (delimptr = strchr(snipptr,delim)) /* locate next comma delim */
  ==   NULL ) {				/*not found following last snippet*/
    strcpy(snip,snipptr);		/* local copy of last snippet */
    snipptr = NULL; }			/* signal end-of-string */
  else {				/* snippet ends just before delim */
    int sniplen = (int)(delimptr-snipptr) - 1;  /* #chars in snippet */
    memcpy(snip,snipptr,sniplen);	/* local copy of snippet chars */
    snip[sniplen] = '\000';		/* null-terminated snippet */
    snipptr = delimptr + 1; }		/* next snippet starts after delim */
  /* --- check if snippet in string --- */
  strstrptr = (iscase? strstr(string,snip) : strcasestr(string,snip) );
  if ( strstrptr != NULL ) {		/* found snippet in string */
    status = 1;				/* so reset return status */
    break; }				/* no need to check any further */
  } /* --- end-of-while(*snipptr!=0) --- */
end_of_job: return ( status );		/*1 if snippet found in list, else 0*/
} /* --- end-of-function isstrstr() --- */


/* ==========================================================================
 * Function:	nomath ( s )
 * Purpose:	Removes/replaces any LaTeX math chars in s
 *		so that s can be rendered in paragraph mode.
 * --------------------------------------------------------------------------
 * Arguments:	s (I)		char * to null-terminated string
 *				whose math chars are to be removed/replaced
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to "cleaned" copy of s
 *				or "" (empty string) for any error.
 * --------------------------------------------------------------------------
 * Notes:     o	The returned pointer addresses a static buffer,
 *		so don't call nomath() again until you're finished
 *		with output from the preceding call.
 * ======================================================================= */
/* --- entry point --- */
char	*nomath ( char *s )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static	char sbuff[4096];		/* copy of s with no math chars */
int	strreplace();			/* replace _ with -, etc */
/* -------------------------------------------------------------------------
Make a clean copy of s
-------------------------------------------------------------------------- */
/* --- check input --- */
*sbuff = '\000';			/* initialize in case of error */
if ( isempty(s) ) goto end_of_job;	/* no input */
/* --- start with copy of s --- */
strninit(sbuff,s,3000);			/* leave room for replacements */
/* --- make some replacements (*must* replace \ first) --- */
strreplace(sbuff,"\\","\\textbackslash ",0,0); /* change all \'s to text */
strreplace(sbuff,"_","\\textunderscore ",0,0); /* change all _'s to text */
strreplace(sbuff,"<","\\textlangle ",0,0); /* change all <'s to text */
strreplace(sbuff,">","\\textrangle ",0,0); /* change all >'s to text */
strreplace(sbuff,"$","\\textdollar ",0,0); /* change all $'s to text */
strreplace(sbuff,"&","\\&",0,0);           /* change every & to \& */
strreplace(sbuff,"%","\\%",0,0);           /* change every % to \% */
strreplace(sbuff,"#","\\#",0,0);           /* change every # to \# */
strreplace(sbuff,"~","\\~",0,0);           /* change every ~ to \~ */
strreplace(sbuff,"{","\\{",0,0);           /* change every { to \{ */
strreplace(sbuff,"}","\\}",0,0);           /* change every } to \} */
strreplace(sbuff,"^","\\ensuremath{\\widehat{~}}",0,0); /* change every ^ */
end_of_job:
  return ( sbuff );			/* back with clean copy of s */
} /* --- end-of-function nomath() --- */


/* ==========================================================================
 * Function:	strwrap ( s, linelen, tablen )
 * Purpose:	Inserts \n's and spaces in (a copy of) s to wrap lines
 *		at linelen and indent them by tablen.
 * --------------------------------------------------------------------------
 * Arguments:	s (I)		char * to null-terminated string
 *				to be wrapped.
 *		linelen (I)	int containing maximum linelen
 *				between \n's.
 *		tablen (I)	int containing number of spaces to indent
 *				lines.  0=no indent.  Positive means
 *				only indent first line and not others.
 *				Negative means indent all lines except first.
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to "line-wrapped" copy of s
 *				or "" (empty string) for any error.
 * --------------------------------------------------------------------------
 * Notes:     o	The returned copy of s has embedded \n's as necessary
 *		to wrap lines at linelen.  Any \n's in the input copy
 *		are removed first.  If (and only if) the input s contains
 *		a terminating \n then so does the returned copy.
 *	      o	The returned pointer addresses a static buffer,
 *		so don't call strwrap() again until you're finished
 *		with output from the preceding call.
 * ======================================================================= */
/* --- entry point --- */
char	*strwrap ( char *s, int linelen, int tablen )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static	char sbuff[4096];		/* line-wrapped copy of s */
char	*sol = sbuff;			/* ptr to start of current line*/
char	tab[32] = "                 ";	/* tab string */
int	strreplace();			/* remove \n's */
char	*strchange();			/* add \n's and indent space */
int	finalnewline = (lastchar(s)=='\n'?1:0); /*newline at end of string?*/
int	istab = (tablen>0?1:0);		/* init true to indent first line */
int	rhslen  = 0,			/* remaining right hand side length*/
	thislen = 0,			/* length of current line segment */
	thistab = 0,			/* length of tab on current line */
	wordlen = 0;			/* length to next whitespace char */
/* -------------------------------------------------------------------------
Make a clean copy of s
-------------------------------------------------------------------------- */
/* --- check input --- */
*sbuff = '\000';			/* initialize in case of error */
if ( isempty(s) ) goto end_of_job;	/* no input */
if ( tablen < 0 ) tablen = (-tablen);	/* set positive tablen */
if ( tablen >= linelen ) tablen = linelen-1; /* tab was longer than line */
tab[min2(tablen,16)] = '\000';		/* null-terminate tab string */
tablen = strlen(tab);			/* reset to actual tab length */
/* --- start with copy of s --- */
strninit(sbuff,s,3000);			/* leave room for \n's and tabs */
if ( linelen < 1 ) goto end_of_job;	/* can't do anything */
trimwhite(sbuff);			/*remove leading/trailing whitespace*/
strreplace(sbuff,"\n"," ",0,0);		/* remove any original \n's */
strreplace(sbuff,"\r"," ",0,0);		/* remove any original \r's */
strreplace(sbuff,"\t"," ",0,0);		/* remove any original \t's */
/* -------------------------------------------------------------------------
Insert \n's and spaces as needed
-------------------------------------------------------------------------- */
while ( 1 ) {				/* till end-of-line */
  /* --- init --- */
  trimwhite(sol);			/*remove leading/trailing whitespace*/
  thislen = thistab = 0;		/* no chars in current line yet */
  if ( istab && tablen>0 ) {		/* need to indent this line */
    strchange(0,sol,tab);		/* insert indent at start of line */
    thistab = tablen; }			/* line starts with whitespace tab */
  if ( sol == sbuff ) istab = 1-istab;	/* flip tab flag after first line */
  sol += thistab;			/* skip tab */
  rhslen = strlen(sol);			/* remaining right hand side chars */
  if ( rhslen <= linelen ) break;	/* no more \n's needed */
  if ( 0 && msglevel >= 99 ) {
    fprintf(stdout,"strwrap> rhslen=%d, sol=\"\"%s\"\"\n",rhslen,sol);
    fflush(stdout); }
  /* --- look for last whitespace preceding linelen --- */
  while ( 1 ) {				/* till we exceed linelen */
    wordlen = strcspn(sol+thislen,WHITESPACE); /*ptr to next whitespace char*/
    if ( thislen+thistab+wordlen >= linelen ) break; /*next word won't fit*/
    thislen += (wordlen+1); }		/* ptr past next whitespace char */
  if ( thislen < 1 ) break;		/* line will have one too-long word*/
  sol[thislen-1] = '\n';		/* replace last space with newline */
  sol += thislen;			/* next line starts after newline */
  } /* --- end-of-while(1) --- */
end_of_job:
  if ( finalnewline ) strcat(sbuff,"\n"); /* replace final newline */
  return ( sbuff );			/* back with clean copy of s */
} /* --- end-of-function strwrap() --- */


/* ==========================================================================
 * Function:	strpspn ( char *s, char *reject, char *segment )
 * Purpose:	finds the initial segment of s containing no chars
 *		in reject that are outside (), [] and {} parens, e.g.,
 *		   strpspn("abc(---)def+++","+-",segment) returns
 *		   segment="abc(---)def" and a pointer to the first '+' in s
 *		because the -'s are enclosed in () parens.
 * --------------------------------------------------------------------------
 * Arguments:	s (I)		(char *)pointer to null-terminated string
 *				whose initial segment is desired
 *		reject (I)	(char *)pointer to null-terminated string
 *				containing the "reject chars"
 *				If reject contains a " or a ', then the
 *				" or ' isn't itself a reject char,
 *				but other reject chars within quoted
 *				strings (or substrings of s) are spanned.
 *		segment (O)	(char *)pointer returning null-terminated
 *				string comprising the initial segment of s
 *				that contains non-rejected chars outside
 *				(),[],{} parens, i.e., all the chars up to
 *				but not including the returned pointer.
 *				(That's the entire string if no non-rejected
 *				chars are found.)
 * --------------------------------------------------------------------------
 * Returns:	( char * )	pointer to first reject-char found in s
 *				outside parens, or a pointer to the
 *				terminating '\000' of s if there are
 *				no reject chars in s outside all () parens.
 *				But if reject is empty, returns pointer
 *				to matching )]} outside all parens.
 * --------------------------------------------------------------------------
 * Notes:     o	the return value is _not_ like strcspn()'s
 *	      o	improperly nested (...[...)...] are not detected,
 *		but are considered "balanced" after the ]
 *	      o	if reject not found, segment returns the entire string s
 *	      o	but if reject is empty, returns segment up to and including
 *		matching )]}
 *	      o	leading/trailing whitespace is trimmed from returned segment
 * ======================================================================= */
/* --- entry point --- */
char	*strpspn ( char *s, char *reject, char *segment )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
char	*ps = s;			/* current pointer into s */
char	*strqspn(char *s,char *q,int isunescape); /*span quoted string*/
char	qreject[256]="\000", *pq=qreject, *pr=reject; /*find "or' in reject*/
int	isqspan = 0;			/* true to span quoted strings */
int	depth = 0;			/* () paren nesting level */
int	seglen=0, maxseg=2047;		/* segment length, max allowed */
int	isescaped=0, checkescapes=1;	/* signals escaped chars */
/* -------------------------------------------------------------------------
initialization
-------------------------------------------------------------------------- */
/* --- check arguments --- */
if ( isempty(s)				/* no input string supplied */
/*||   isempty(reject)*/ ) goto end_of_job; /* no reject chars supplied */
/* --- set up qreject w/o quotes --- */
if ( !isempty(reject) )			/* have reject string from caller */
  while ( *pr != '\000' ) {		/* until end-of-reject string */
    if ( !isthischar(*pr,"\"\'") )	/* not a " or ' */
      *pq++ = *pr;			/* copy actual reject char */
    else isqspan = 1;			/* span rejects in quoted strings */
    pr++; }				/* next reject char from caller */
*pq = '\000';				/* null-terminate qreject */
/* -------------------------------------------------------------------------
find first char from s outside () parens (and outside ""'s) and in reject
-------------------------------------------------------------------------- */
while ( *ps != '\000' ) {		/* search till end of input string */
  int spanlen = 1;			/*span 1 non-reject, non-quoted char*/
  if ( !isescaped ) {			/* ignore escaped \(,\[,\{,\),\],\}*/
    if ( isthischar(*ps,"([{") ) depth++;   /* push another paren */
    if ( isthischar(*ps,")]}") ) depth--; } /* or pop another paren */
  if ( depth < 1 ) {			/* we're outside all parens */
    if ( isqspan )			/* span rejects in quoted strings */
      if ( isthischar(*ps,"\"\'") ) {	/* and we're at opening quote */
        pq = strqspn(ps,NULL,0);	/* locate matching closing quote */
        if ( pq != ps )			/* detected start of quoted string */
         if ( *pq == *ps )		/* and found closing quote */
          spanlen = ((int)(pq-ps)) + 1; } /* span the entire quoted string */
    if ( isempty(qreject) ) break;	/* no reject so break immediately */
    if ( isthischar(*ps,qreject) ) break; } /* only break on a reject char */
  if ( checkescapes )			/* if checking escape sequences */
    isescaped = (*ps=='\\'?1:0);	/* reset isescaped signal */
  if ( segment != NULL ) {		/* caller gave us segment */
    int copylen = min2(spanlen,maxseg-seglen); /* don't overflow segment */
    if ( copylen > 0 )			/* have room in segment buffer */
      memcpy(segment+seglen,ps,copylen); } /* so copy non-reject chars */
  seglen += spanlen;  ps += spanlen;	/* bump to next char */
  } /* --- end-of-while(*ps!=0) --- */
end_of_job:
  if ( segment != NULL ) {		/* caller gave us segment */
    if ( isempty(qreject) && !isempty(s) ) { /* no reject char */
      segment[min2(seglen,maxseg)] = *ps;  seglen++; } /*closing )]} to seg*/
    segment[min2(seglen,maxseg)] = '\000'; /* null-terminate the segment */
    trimwhite(segment); }		/* trim leading/trailing whitespace*/
  return ( ps );			/* back to caller */
} /* --- end-of-function strpspn() --- */


/* ==========================================================================
 * Function:	strqspn ( char *s, char *q, int isunescape )
 * Purpose:	finds matching/closing " or ' in quoted string
 *		that begins with " or ', and optionally changes
 *		escaped quotes to unescaped quotes.
 * --------------------------------------------------------------------------
 * Arguments:	s (I)		(char *)pointer to null-terminated string
 *				that begins with " or ',
 *		q (O)		(char *)pointer returning null-terminated
 *				quoted token, with or without outer quotes,
 *				and with or without escaped inner quotes
 *				changed to unescaped quotes, depending
 *				on isunescape.
 *		isunescape (I)	int containing 1 to change \" to " if s
 *				is "quoted" or change \' to ' if 'quoted',
 *				or containing 2 to change both \" and \'
 *				to unescaped quotes.  Other \sequences aren't
 *				changed.  Note that \\" emits \".
 *				isunescape=0 makes no changes at all.
 *				Note: the following not implemented yet --
 *				If unescape is negative, its abs() is used,
 *				but outer quotes aren't included in q.
 * --------------------------------------------------------------------------
 * Returns:	( char * )	pointer to matching/closing " or '
 *				(or to char after quote if isunescape<0),
 *				or terminating '\000' if none found,
 *				or unchanged (same as s) if not quoted string
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
char	*strqspn ( char *s, char *q, int isunescape )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
char	*ps = s,  *pq = q;		/* current pointer into s, q */
char	quote = '\000';			/* " or ' quote character */
int	qcopy = (isunescape<0?0:1);	/* true to copy outer quotes */
int	isescaped = 0;			/* true to signal \escape sequence */
int	maxqlen = 2400;			/* max length of returned q */
/* -------------------------------------------------------------------------
Initialization
-------------------------------------------------------------------------- */
/* --- check args --- */
if ( s == NULL ) goto end_of_job;	/* no string supplied */
skipwhite(ps);				/* skip leading whitespace */
if ( *ps == '\000'			/* string exhausted */
||   (!isthischar(*ps,"\"\'")) ) {	/* or not a " or ' quoted string */
  ps = s;  goto end_of_job; }		/*signal error/not string to caller*/
if ( isunescape < 0 ) isunescape = (-isunescape); /* flip positive */
/* --- set quote character --- */
quote = *ps;				/* set quote character */
if ( qcopy && q!=NULL ) *pq++ = quote;	/* and copy it to output token */
/* -------------------------------------------------------------------------
span characters between quotes
-------------------------------------------------------------------------- */
while ( *(++ps) != '\000' ) {		/* end-of-string always terminates */
  /* --- process escaped chars --- */
  if ( isescaped ) {			/* preceding char was \ */
    if ( *ps != '\\' ) isescaped = 0;	/* reset isescaped flag unless \\ */
    if ( q != NULL ) {			/* caller wants quoted token */
      if ( isunescape==0		/* don't unescape anything */
      ||   (isunescape==1 && *ps!=quote) /* escaped char not our quote */
      ||   (isunescape==2 && (!isthischar(*ps,"\"\'"))) ) /* not any quote */
        if ( --maxqlen > 0 )		/* so if there's room in token */
          *pq++ = '\\';			/*keep original \ in returned token*/
      if ( !isescaped )			/* will have to check 2nd \ in \\ */
        if ( --maxqlen > 0 )		/* if there's room in token */
          *pq++ = *ps; }		/* put escaped char in token */
    continue; }				/* go on to next char in string */
  /* --- check if next char escaped --- */
  if ( *ps == '\\' ) {			/* found escape char */
    isescaped=1; continue; }		/*set flag and process escaped char*/
  /* --- check for unescaped closing quote --- */
  if ( *ps == quote ) {			/* got an unescaped quote */
    if ( qcopy && q!=NULL ) *pq++ = quote; /* copy it to output token */
    if ( 0 && !qcopy ) ps++;		/* return ptr to char after quote */
    goto end_of_job; }			/* back to caller */
  /* --- process other chars --- */
  if ( q != NULL )			/* caller want token returned */
    if ( --maxqlen > 0 )		/* and there's still room in token */
      *pq++ = *ps;			/* put char in  token */
  } /* --- end-of-while(*(++ps)!='\000') --- */
/*ps = NULL;*/  /*pq = q;*/		/* error if no closing quote found */
end_of_job:
  if ( q != NULL ) *pq = '\000';	/* null-terminate returned token */
  return ( ps );			/* return ptr to " or ', or NULL */
} /* --- end-of-function strqspn() --- */


/* ==========================================================================
 * Function:	timestamp ( tzdelta, ifmt )
 * Purpose:	returns null-terminated character string containing
 *		current date:time stamp as ccyy-mm-dd:hh:mm:ss{am,pm}
 * --------------------------------------------------------------------------
 * Arguments:	tzdelta (I)	integer, positive or negative, containing
 *				containing number of hours to be added or
 *				subtracted from system time (to accommodate
 *				your desired time zone).
 *		ifmt (I)	integer containing 0 for default format
 * --------------------------------------------------------------------------
 * Returns:	( char * )	ptr to null-terminated buffer
 *				containing current date:time stamp
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
char	*timestamp( int tzdelta, int ifmt )
{
/* -------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static	char timebuff[256];		/* date:time buffer back to caller */
/*long	time_val = 0L;*/		/* binary value returned by time() */
time_t	time_val = (time_t)(0);		/* binary value returned by time() */
struct tm *tmstruct=(struct tm *)NULL, *localtime(); /* interpret time_val */
int	year=0, hour=0,ispm=1,		/* adjust year, and set am/pm hour */
	month=0, day=0,			/* adjust day and month for delta  */
	minute=0,second=0;		/* minute and second not adjusted  */
int	tzadjust();			/* time zone adjustment function */
int	daynumber();			/* #days since Jan 1, 1973 */
static	char *daynames[] = { "Monday", "Tuesday", "Wednesday",
	 "Thursday", "Friday", "Saturday", "Sunday" } ;
static	char *monthnames[] = { "?", "January", "February", "March", "April",
	 "May", "June", "July", "August", "September", "October",
	"November", "December", "?" } ;
/* -------------------------------------------------------------------------
get current date:time, adjust values, and and format stamp
-------------------------------------------------------------------------- */
/* --- first init returned timebuff in case of any error --- */
*timebuff = '\000';
/* --- get current date:time --- */
time((time_t *)(&time_val));		/* get date and time */
tmstruct = localtime((time_t *)(&time_val)); /* interpret time_val */
/* --- extract fields --- */
year  = (int)(tmstruct->tm_year);	/* local copy of year,  0=1900 */
month = (int)(tmstruct->tm_mon) + 1;	/* local copy of month, 1-12 */
day   = (int)(tmstruct->tm_mday);	/* local copy of day,   1-31 */
hour  = (int)(tmstruct->tm_hour);	/* local copy of hour,  0-23 */
minute= (int)(tmstruct->tm_min);	/* local copy of minute,0-59 */
second= (int)(tmstruct->tm_sec);	/* local copy of second,0-59 */
/* --- adjust year --- */
year += 1900;				/* set century in year */
/* --- adjust for timezone --- */
tzadjust(tzdelta,&year,&month,&day,&hour);
/* --- check params --- */
if ( hour<0  || hour>23
||   day<1   || day>31
||   month<1 || month>12
||   year<1973 ) goto end_of_job;
/* --- adjust hour for am/pm --- */
switch ( ifmt )
  {
  default:
  case 0:
    if ( hour < 12 )			/* am check */
     { ispm=0;				/* reset pm flag */
       if ( hour == 0 ) hour = 12; }	/* set 00hrs = 12am */
    if ( hour > 12 ) hour -= 12;	/* pm check sets 13hrs to 1pm, etc */
    break;
  case 4: break;			/* numeric result */
  } /* --- end-of-switch(ifmt) --- */
/* --- format date:time stamp --- */
switch ( ifmt )
  {
  default:
  case 0:  /* --- 2005-03-05:11:49:59am --- */
    sprintf(timebuff,"%04d-%02d-%02d:%02d:%02d:%02d%s",
    year,month,day,hour,minute,second,((ispm)?"pm":"am"));
    break;
  case 1:  /* --- Saturday, March 5, 2005 --- */
    sprintf(timebuff,"%s, %s %d, %d",
    daynames[daynumber(year,month,day)%7],monthnames[month],day,year);
    break;
  case 2: /* --- Saturday, March 5, 2005, 11:49:59am --- */
    sprintf(timebuff,"%s, %s %d, %d, %d:%02d:%02d%s",
    daynames[daynumber(year,month,day)%7],monthnames[month],day,year,
    hour,minute,second,((ispm)?"pm":"am"));
    break;
  case 3: /* --- 11:49:59am --- */
    sprintf(timebuff,"%d:%02d:%02d%s",
    hour,minute,second,((ispm)?"pm":"am"));
    break;
  case 4: /* --- 1231235959 (mmddhhmmss time as integer) --- */
    sprintf(timebuff,"%d%02d%02d%02d%02d",
    month,day,hour,minute,second);
    break;
  } /* --- end-of-switch(ifmt) --- */
end_of_job:
  return ( timebuff );			/* return stamp to caller */
} /* --- end-of-function timestamp() --- */


/* ==========================================================================
 * Function:	tzadjust ( tzdelta, year, month, day, hour )
 * Purpose:	Adjusts hour, and day,month,year if necessary,
 *		by delta increment to accommodate your time zone.
 * --------------------------------------------------------------------------
 * Arguments:	tzdelta (I)	integer, positive or negative, containing
 *				containing number of hours to be added or
 *				subtracted from given time (to accommodate
 *				your desired time zone).
 *		year (I)	addr of int containing        4-digit year
 *		month (I)	addr of int containing month  1=Jan - 12=Dec.
 *		day (I)		addr of int containing day    1-31 for Jan.
 *		hour (I)	addr of int containing hour   0-23
 * Returns:	( int )		1 for success, or 0 for error
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	tzadjust ( int tzdelta, int *year, int *month, int *day, int *hour )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	yy = *year, mm = *month, dd = *day, hh = *hour; /*dereference args*/
/* --- calendar data --- */
static	int modays[] =
	{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0 };
/* --------------------------------------------------------------------------
check args
-------------------------------------------------------------------------- */
if ( mm<1 || mm>12 ) return(-1);	/* bad month */
if ( dd<1 || dd>modays[mm] ) return(-1); /* bad day */
if ( hh<0 || hh>23 ) return(-1);	/* bad hour */
if ( tzdelta>23 || tzdelta<(-23) ) return(-1); /* bad tzdelta */
/* --------------------------------------------------------------------------
make adjustments
-------------------------------------------------------------------------- */
/* --- adjust hour --- */
hh += tzdelta;				/* apply caller's delta */
/* --- adjust for feb 29 --- */
modays[2] = (yy%4==0?29:28);		/* Feb has 29 days in leap years */
/* --- adjust day --- */
if ( hh < 0 )				/* went to preceding day */
  { dd--;  hh += 24; }
if ( hh > 23 )				/* went to next day */
  { dd++;  hh -= 24; }
/* --- adjust month --- */
if ( dd < 1 )				/* went to preceding month */
  { mm--;  dd = modays[mm]; }
if ( dd > modays[mm] )			/* went to next month */
  { mm++;  dd = 1; }
/* --- adjust year --- */
if ( mm < 1 )				/* went to preceding year */
  { yy--;  mm = 12;  dd = modays[mm]; }
if ( mm > 12 )				/* went to next year */
  { yy++;  mm = 1;   dd = 1; }
/* --- back to caller --- */
*year=yy; *month=mm; *day=dd; *hour=hh;	/* reset adjusted args */
return ( 1 );
} /* --- end-of-function tzadjust() --- */


/* ==========================================================================
 * Function:	daynumber ( year, month, day )
 * Purpose:	Returns number of actual calendar days from Jan 1, 1973
 *		to the given date (e.g., bvdaynumber(1974,1,1)=365).
 * --------------------------------------------------------------------------
 * Arguments:	year (I)	int containing year -- may be either 1995 or
 *				95, or may be either 2010 or 110 for those
 *				years.
 *		month (I)	int containing month, 1=Jan thru 12=Dec.
 *		day (I)		int containing day of month, 1-31 for Jan, etc.
 * Returns:	( int )		Number of days from Jan 1, 1973 to given date,
 *				or -1 for error (e.g., year<1973).
 * --------------------------------------------------------------------------
 * Notes:     o
 * ======================================================================= */
/* --- entry point --- */
int	daynumber ( int year, int month, int day )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
/* --- returned value (note: returned as a default "int") --- */
int	ndays;				/* #days since jan 1, year0 */
/* --- initial conditions --- */
static	int year0 = 73, 		/* jan 1 was a monday, 72 was a leap */
	days4yrs = 1461,		/* #days in 4 yrs = 365*4 + 1 */
	days1yr  = 365;
/* --- table of accumulated days per month (last index not used) --- */
static	int modays[] =
	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
/* --- variables for #days since day0 --- */
int	nyears, nfouryrs;		/*#years, #4-yr periods since year0*/
/* --------------------------------------------------------------------------
Check input
-------------------------------------------------------------------------- */
if ( month < 1 || month > 12 )		/*month used as index, so must be ok*/
	return ( -1 );			/* otherwise, forget it */
if ( year >= 1900 ) year -= 1900;	/*use two-digit years (3 after 2000)*/
/* --------------------------------------------------------------------------
Find #days since jan 1, 1973
-------------------------------------------------------------------------- */
/* --- figure #complete 4-year periods and #remaining yrs till current --- */
nyears = year - year0;			/* #years since year0 */
if ( nyears < 0 ) return ( -1 );	/* we're not working backwards */
nfouryrs = nyears/4;			/* #complete four-year periods */
nyears -= (4*nfouryrs); 		/* remainder excluding current year*/
/* --- #days from jan 1, year0 till jan 1, this year --- */
ndays = (days4yrs*nfouryrs)		/* #days in 4-yr periods */
      +  (days1yr*nyears);		/* +remaining days */
/*if ( year > 100 ) ndays--;*/		/* subtract leap year for 2000AD */
/* --- add #days within current year --- */
ndays += (modays[month-1] + (day-1));
/* --- may need an extra day if current year is a leap year --- */
if ( nyears == 3 )			/*three preceding yrs so this is 4th*/
    { if ( month > 2 )			/* past feb so need an extra day */
	/*if ( year != 100 )*/		/* unless it's 2000AD */
	  ndays++; }			/* so add it in */
return ( (int)(ndays) );		/* #days back to caller */
} /* --- end-of-function daynumber() --- */


/* ==========================================================================
 * Function:	emitembedded ( imagenum, isquery )
 * Purpose:	Emits embedded gif (or png) message to stdout
 * --------------------------------------------------------------------------
 * Arguments:	imagenum (I)	int containing image number desired
 *		isquery (I)	int containing 0 for command-line run,
 *				1 for query mode, 2 for query mode but
 *				suppress msgfp output even if it's enabled.
 * Returns:	int		#bytes emitted (returned by emitcache()),
 *				or 0 for failure
 * --------------------------------------------------------------------------
 * Notes:     o	If mathTeX fails, these images contain
 *		error messages that can be displayed
 * ======================================================================= */
/* --- entry point --- */
int	emitembedded ( int imagenum, int isquery )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int	nbytes = 0,			/* #bytes in embedded image */
	imgtype = 0;			/* image type 1=gif,2=png */
unsigned char *eimage=NULL, *embeddedimages(); /* retrieve embedded image */
int	emitcache();			/* emit embedded image to stdout */
int	maxage = MAXAGE;		/* maxage is typically 7200 secs */
/* --------------------------------------------------------------------------
Retrieve and emit embedded image
-------------------------------------------------------------------------- */
/* --- retrieve image --- */
if ( imagenum<1 || imagenum>MAXEMBEDDED ) imagenum=1; /*out-of-bounds check*/
eimage = embeddedimages(imagenum,&nbytes,&imgtype); /*retrieve image*/
/* --- display message image on stdout --- */
if ( isquery )				/* don't emit error to shell stdout*/
  if ( eimage != NULL ) {		/* have embedded image */
    imagetype = imgtype;		/* set embedded image type */
    nbytes = emitcache((char *)eimage,maxage,nbytes); } /* and emit image */
/* --- show message text on msgfp --- */
if ( isquery != 2 )			/* msgfp output enabled */
  if ( msgfp!=NULL && msglevel>=1 )	/* display on msgfp, too */
    fprintf(msgfp,"\nmathTeX> message#%d %s:\n         %s\n",
    imagenum,(nbytes>0?"succeeded":"failed"),
    strwrap(embeddedtext[imagenum],64,-9));
/* --- back to caller --- */
return ( nbytes );			/* return #bytes emitted, 0=error */
} /* --- end-of-function emitembedded() --- */


/* ==========================================================================
 * Function:	embeddedimages ( imagenum, nbytes, imgtype )
 * Purpose:	Returns unsigned char ptr to embedded gif or png message
 * --------------------------------------------------------------------------
 * Arguments:	imagenum (I)	int containing image number desired
 *		nbytes (O)	ptr to int returning #bytes in image,
 *				or returning 0 for error
 *		imgtype (O)	ptr to int returning 1=gif, 2=png,
 *				or unchanged for error
 * Returns:	( unsigned char * ) embedded gif or png, or NULL for error
 * --------------------------------------------------------------------------
 * Notes:     o	If mathTeX fails, these binary images of gifs/pngs
 *		supply error messages that can be displayed
 *	      o	String initializations for these binary images were
 *		created by my utility file2hex.c, and the important
 *		thing to notice is that the images are broken into
 *		one or more 500-byte strings.  If you change that
 *		length, change variable stringsz correspondingly.
 * ======================================================================= */
/* --- entry point --- */
unsigned char *embeddedimages ( int imagenum, int *nbytes, int *imgtype )
{
/* --------------------------------------------------------------------------
Embedded Image Allocations and Declarations
-------------------------------------------------------------------------- */
/* ---
 * Each image broken up into 500-byte strings.  See Notes above.
 * ------------------------------------------------------------- */
static	int stringsz = 500;		/* sizeof each image string */
/* ---
 * image1[] contains a 1885-byte gif rendering of expression
 * \usepackage{color}\color{blue}\footnotesize\fparbox{
 * (1) mathTeX test message:\\cgi program running okay.\\
 * See mathtex.html\#message1}
 * ----------------------------------------------------------- */
#define	IMAGETYPE1 1			/* 1=gif, 2=png */
#define	IMAGESIZE1 1885			/* #bytes in image1[] */
static	unsigned char *image1[] = {
  (unsigned char *) "GIF89a\xc6\x0\x38\x0\x84\x0\x0\xff\xff\xff\x0\x0\xff" 
  "\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb\xdb" 
  "\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff==\xff\x16\x16\xff\x1\x1\xff" 
  "\x9f\x9f\xff\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9" 
  "\x4\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xc6\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh" 
  "\xaa\xael\xeb\xbep,\xcf)`\xdfx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f:\x11r" 
  "\xc9l:\x9f\xd0(O)\xadZ\xaf\xd8,\x90\xaa\xedz\xbf`!7L.\x9b\xaf\x63\xde" 
  "\x80\xb0\x43\x38\xb2\bE\xe1L\xaf\xe7\xd2\xba\x82\xe1\xa6\x1f\xdc\x6\vUs" 
  "\x0\x5\t{8\n\x10\x6\x6\a\x8a\x8c\x87\x37\n\v\x1\as\n\x1\t\f;\x83\x42\x9c" 
  "vYx9\a\b6\f\f\r\n8\v~Q\x90\x8b\x39\x4\xac\x8c\x36n;\xe\x10\xa4\x5\x9a<" 
  "\x90\x41\xbd\x9fh\x1>\x3\t\xa2\xa9\x7f\xfQ\xe\xae\xbf\xae\a7\xbf\x37\t" 
  "\xc5\xd1\x37\xcb\x43\xd7\xc0\xa0\xc2=\xaf\x38\a\xc7\x37\xdc\xb0\x10\v\x4" 
  "\n\a\x3\n\xe8\x83\f\x4\x4\x87\f\x10\a\x6\xa9\x6\xe6\xec\x39\xb3\x37\f" 
  "\xe6\v\x9c\b(\x91\xda!\x8f^\xaa~\x4\xfe!\xa8G Y\xc1z:\b\x94;\x97n]\xa5R" 
  "\xfe\n,T\xd0\x10\xc0\xc6\x8e\x0\xdc\xc1\xe3\xb7\xe0\x1e\x83\x62\b\xfe" 
  "\xff\x1\xf0v$\xd4\rp\xc6\x44\xb1\xd2\xf7leMo\t\xfc,x\xb3\xd2\x99\r\x96\?" 
  "k\x2\x90hc\x80P\x0\xe\x2\xcc\xd4\xe1\x8d(\x0\xa3\x6\xd8 \xfdY-\xa8\xd5" 
  "\x9e\x43!\x14\xa5\'\xf5MT\x1b<s\x2\xd8i#\x0\xa9\x5\x9a\x9c\x1a\xc5\x8a" 
  "\xc4\xa5\r\x98\xdf\xc2\xbd\x95\v\xed\x90\x37\x96\x1c\x1f\xd8\x65\x46\x95" 
  "\xa6\x34p\xeb\xc6\x15p\xb0\xa0\xc1@\xa6\x87\x12\x0\xbe\x34`\x9e\x83\x81",
  (unsigned char *) "@\xf5\xed\xed\xabx\x1d\x63\xc7\xa4\x1a\x1fx\x1c\xa9" 
  "\xe1!n\x6\xdeT\xe\xec\xc4-\x0\xb8/\xe9\xa2\xc6qw2\x80\x4\xf6&\xc7\xee" 
  "\xcbZ(\xbd\x1d\x87\x1a\x4\xc2\xbd\a]\xaf\x2\xba\x1e\xdc\xec\xcd\x9b\xf6" 
  "\xab\xdb|\x82\?\x3\xce@\xb8\r\xd8l\xcd\x8d<]\xb5\xed\xb8\x1dhc\xe2\xc0U" 
  "\x9c\xed+t6\xf4\xeey5\xde\x35\x34\xa1\x4\x1aX\x3;\xb0@\x0\xa9\x92W\xa6" 
  "\xb7\x66`\x90z\xac\xd5Z\xf7\x9d\xf\xb6\xbe\r\xf5\xfe\x1\xa0\x1ex\x0\x88" 
  "\x17\x12,\xf7M\xfe\xf5\xce\x12\xa6%\xc4\x8f\x1\x98@\x82@\x82\x88\x1c\x80" 
  "\x8a\x2\r\\\x98\xa1\x2\bTtJ \x5\x34\xe0\xc0\x39\x1b\x62\x88\x8a\r\n\x18" 
  "\xd0@\x0\x10\xad\xf4\x0\x61\xa6\x1c\x10\xc0\x31\x89\xb0\xe8\t!\"\xb2\x61" 
  "\xc0\x8bh\xdd\xb3\x6O!\x8e\xa8\x3:\x1a\x16i\xf\x8f\f\xf8H\x80W\xab,\xe9" 
  "\x91\x87\xba\x15x\xc0\x94\v\x90\xb2#\x8c\xaf\x15\x63\xdd\xfG\x11\xb4\xcb" 
  "\x11\x87\xe1\x10\x66\x11\x37\xe\x11\xe6 \xa4\x8c\xe9\x11\x13h\xaeI\x8b" 
  "\x9b\x37\x84\xb9\x0l\x1c%\x90\x8c\ren\xe9\x3\x1_\xea\x80\x80\x96\xda\x4" 
  "\xaa\x85\x39\x37\x38X\x85i6\xc4\xc2\x3g\x82\x36\x8a\x85\x65\xeb\x4\x13" 
  "\x44\x9e\b\xa8\xe9\xe8\xa5\x98\xdeq]\xa6\x9cv\xca\xe0\xa6\x9e\x86*\xea" 
  "\xf\x88\x8ej\xea\xfq\xe4\x19\x46\xa9\?$\xc0\xd3\xa9Q\xb8\x1a\x45!\xd5}" 
  "\xc1\xea\x9eK\xc1\xea\x84\xa2\xad\xd4\xea\xc5\xad\xba\x6\xcb\x16\x1d\xa6" 
  "\x11\x63RH%\xa1\x5[\x3\xd1H\xe4\xaa\x1\x62\r\xa0\x1b\x1\x1\xfe\xcc\x1" 
  "\x8f\x2\xee`dRN\xd3V\x1b\xd2;\x87H\x84OE\xf9\xfc\xd1m\x1\xd2\xee\x91\xee" 
  "P\x1\x8ckm\xbb\x14Y\xc2,\xbb\xeej\xab,,\xf5\x64\x8b\x15\x1\xb7\x89\xb4" 
  "\xc7Iw\xda\xa9\xaa\x9e\x9bx\xeb@1f\x8d\xb5Kd\?\xed\xe6\x9e\x95\xea=\x96" 
  "\xc8\r\xf\xa4\x92pv+EL\x8aXd\xd9tUd*\"e\xa5k\xfb\xdc\x35\x9cq\'\x3",
  (unsigned char *) "pq\x9f\x0L\x1c\xdel\v\x1c\xc3\xf1\x1b\xcd\xfd\x64)\x13" 
  "n9\xd0%h<1<\xec\x66\xc3&\xb0\xdbJ\b\xff\xd4\xf3/y\x91l\x1em\xc6)\xdd\xf4" 
  "\xd3l\xf1\x9c\x83\xd0\xd0P\xb3\xc0jI{\xc4\xdd\xabQ\xb8\xb5\xcf\r\xd2\xf1" 
  "\x85\xd8K\xe5\xbd\x34\xf4,a\xd7\x85\x3t\xfay\xd7L/m\xc7\xed\xb4\xdb\x36" 
  "\xa4-\xca\xd9\xcf@\x8b\xe1@l\x1fR\x12\x3\x37\xe3\f*\x1f\t\xfu`|L9\xec-K" 
  "\xa7P\xac\t\xcb\xc3\x12h\xa0\xdc\x88\xd3\xa6\x17\xd4\x94\xd3}8A\t>\xa0" 
  "\xc9+\xfe\xe$#\xf9+\x5(R(|M\x98\xc6\xc0\x66\x6\xf8!\x1c\x95ql\xc8\xd4\x1" 
  "\xe7$\xc0\x86\x89_^\xe9\xcd\xeb\aT\x89;-P\xc6l\xe1:%\xca\x8e\x62\x86_" 
  "\x16\xa2N\x2\x46\x9aH|\xf3\xc5\x1b)%\xec\xfa\xbc\xf8]\x3\x80\x61\x12\x41" 
  "\xf0\xcf\xcd\x34\r\x14\xa5\xe\x34\xe7:\x4\xd8\xe9\x3\xe9@p2~\x9dw\xfa)E" 
  "\x9aV\xac_~\xfb\x38\f\x1c\xa7\xe\\K\x1,\xa1\x89\xe\xdd\x1d\x11\xfc\x1b" 
  "\x8a\xfft\x15@C1\xc1U\xea\xc0\x2\xb0Z\x6)\x1f\xa4\xa8\x45\x44\x80\x14]" 
  "\x82%\xc1\'\xac\x61\x82]\x1b\x9c\xb0\x36\xd8\xa8\x5r\xf0\x83\xab\xd2 " 
  "\x1f\x14\xe0\a\xfb\x61!UQ@\xe1\x12T(\xa6\x81\x4.T\xaa\xd3\x84\x1e\xba" 
  "\xa4\x85\x41\xd0j\x13G\xb8\x61\x1e:a\b\x1d\xa8\x64\x41\x8e\xea\xc3\x16" 
  "\x44X\x0\xa1t(\fb\xd3\a\x12|\xe6+\xd6\x44\x43K\xfx\xe1\x19Lq\"R\x89\x30" 
  "\x11\x87i\"\x14\xb2\x31,\xfa,1\x1a\\\x4\xfe\x42\x64\xf4\x10\x9eL\xad\x66" 
  "\n\"<\x8d\"\xe4\x92\x92\x39\xb4\x91\x1c\xe3RG\xb9\xfcU\x8ay@\xe4\x1e\xf1" 
  "\n\x89\x1d\xf\x92\x91\x93\x14\x83_\x3\xc4\x63>\x1e\xc2\x91\x89\xa0\x43" 
  "\x8e\x17\xe9\"R\xfc\x30\x80W\x89\x8b\"\x88lGF>\x92\fJ\x96\x2\\$\xd9\x16" 
  "\xb2\x12\xc2\x89\x33\xee\x0Q*\x12\x1\x1b\xd4\x42;\xad<\x85",
  (unsigned char *) "\x86%K\xd9\xcc\x98V2\xd7\x90\xf2)\x86\xc1\xd6\xec\xa0" 
  "\xe6\xb1Z\xeaG\xf\x8b\xa0\xc7#L\xf6\xb1=\x90\xf2+S\x1\x66Xt\xc2\x93\x95" 
  "\x65\x65+\xa9\x19\x62\x10\xdc`\x96\xd1\\\xc2\x99\xa0\xca\\\xcb<\xc3\xca" 
  "\xb9\x41\x33Q\r@\x9d\xda\x34\xa7\xb9\xb6\xd1\"`\x88\xd3\xf\x34\x35\xc3" 
  "\x19r\x1e&k*3\xdak\x16\x33\xeO&\xe1\x8arA\x5r\xdeR\xab\xcc\xf5\xad/\xb3" 
  "\xa1\x9bo\xfct\x0\xfamS\?\xf9\xa4\\\x1c\x14\xb0\x8cu\xd0\xe9\x18\x94\x9b" 
  "\'!\x94\xb3\xd0\xe6\xd4\xe4\x9e\x63\xc1$uv\xe0NM\xf5 E80\f\xe0\x7f\x90" 
  "\xb2\xd1\xfcu\xb3\x37\x35\x99\xdcx>*\x9f\x4\xbd\x61!\x5\xe2\t\x10)W6\x92" 
  "\xe\x14\x30;\xb1\f\xe6|i\xd2\x0\x1\xc8>-\v\xe9+X\xd6\xd1\x64Z\xf1\xa2" 
  "\x86X\x87\xe7~\x82$\x17\x61\xa9\x42\xd0\x43\x45\x87\xd4\xf1!\x1c\x8d\xc8" 
  "y\xces\xaa\x8e\x90$\x8f@P\xeb\x1f\xdf\x83\xaa\xec\x82\x44\x91\xa4>/\x1cw" 
  "\xf2\'\x91\xbe\x1a\xd5+\xf5\xa8IL\xfa\xd1\x93\x98\x1a%\xdeU\xc9\xa8\xd9I" 
  "R\x84~\xca\x83J1pL72\xa1\xf,%E8\x11\xc2\t}\xdd\x41#\xcb\x98\xc3\x37\x1d" 
  "\x6~bR\x5\x9d\xe6\xc7\x87\x96\xa4\x11\x84_p\x0#=\xea\x85\x2\xe\xd0\b\x1e" 
  "\x84l\x15h\xa4\xd7+T0u\x8f\xd5\xach\x7f\x15\xda\xd1\x9aVR\xa7M-\x18\x32" 
  "\xab\xda\xd6\x16\x81\xb5\xae\x8d\xed\x10i@\xdb\xda\xda\xf6\xb6\xb8\xcd" 
  "\xadnS\x10\x2\x0;",
  NULL } ; /* --- end-of-image1[] --- */
/* ---
 * image2[] contains a 2296-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (2) mathTeX failed: probably due to\\bad paths, permissions,
 * or installation.\\See mathtex.html\#message2}
 * ------------------------------------------------------------ */
#define	IMAGETYPE2 1			/* 1=gif, 2=png */
#define	IMAGESIZE2 2296			/* #bytes in image2[] */
static	unsigned char *image2[] = {
  (unsigned char *) "GIF89a\x1\x1\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x16\x16\xff==\xff\x3\x3\xff\x1\x1" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\x1\x1\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcftm\x97@\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8\xa4r" 
  "\xc9l\xe6\x44\xce\xa8tJ\xadZ\xaf\xd8!4\xcb\xedz\xbf\xe0\x30p+.\x9b\xcf" 
  "\xe8\xf4\x8e\xacn\xbb\xdfp$\x1b\x38 \xf8\x10\x8e,BQ\x10\xf3\x83{}\x80" 
  "\x7fz\x84\x83\x82:\x81G\x8aps>\x5\x6\x39\x90\x6\v\b9\x3\vU\x82\x5\t\x91;" 
  "\n\x10\x6\x6\a\xa1\xa3\x9e\x9f\v\x1\a}\n\x1\t\f=\x9c\xad>\ty\x9c\xa7\?" 
  "\xb7\\\xba\x42\xbc:\xbe\x44\xc0I\x88Q\x8e=\a\x96\b\r9\xe\xf:\v\x3T\xa7" 
  "\xa2<\x4\xd1\x0\xa3\x39x\?\xe\x10\x96\x5\xb0>\xd4\xc4:\xd6\x39\xd4\x42" 
  "\xe8Y\xea\x41\xec\xe7\xb8\x44\xeeH\xf0M\xc6;\x3\t9\xb3O\n\x97\xcbR\xe" 
  "\xa6\xc1\x9bv@\a=\x1d\t\xf2\x1d|\x17o\xe1\xeyU \xf6\x90\'\x11H\xc5!\x1" 
  "\xa9\xd8\x33x\xeaZ\x81\x0\x88\x2\xf4 \x0\x61\x1\x1\x5\a\xfe\x6(@)\x88\x1" 
  "\x1\x2\x9e\x18@8`\xa0\x1f\xa5\x93\xabxd\xdb\xc1\xc0\xe4\x2\x44\bTY\xf2" 
  "\x81\x92&\x0\x97\x30\xf5=\xf0\x84\xae\'\x81\x9f\x0\x30)`\xd0\x89\xa1\xf" 
  "\x92\xb5\f$\x88\x36\xe0\x81I\x90\x0`N\xb5\x83-\xc1Kh9\x90N3\xfb\xf4\x1a" 
  "\x35\xaa\xff\x12\x34 &\x95j\xa4\xaew\x97\xa6\xf5IN&\xcd~b]*\xd9\x98\xe3@" 
  "\?\x1e\v2\xe9H9\xb1 6\xc7",
  (unsigned char *) "\xe8\xb6\x2X\x90\a\x1b\x41\xab\x6\x1d\xe7 yI3\x0\a\x1" 
  "\xae\x89\xf3$\x99\xb2Uj\x9c\xa3\"\v0\xd4\xa8\x65\x8b\x8a\?Z2\xe0\xcc\xc1" 
  "\x1e\b:\x1a\xd8\x8c\xcd\x1a@\xe9\xca\x94$\xf5n\xfa\xcf\xc0Pm\xbd\x1\xb8" 
  "\x46\x87\x1a\xb7\xea\x89\x9e@\xe5>|\x84\xb0r\xeai\xff-\xc6~\x9a\xe9)\x5" 
  "\x4\x1ax\xe7\x88\xf9\x9c\xe7\x4\x86W\x8a\x94\xe4`\xc1\x83\xe3:\xbf\x87" 
  "\x1f\xff\x1a\xfd\xcaV\xe\x34\xbbNw\xea@\x1eu\t(V\xd6k\x85U\x6\x9ex\x98" 
  "\xf9\xfeG \x2\xde|\xc6\x43~\x8b\xd1G\x8d}\xea\x41\x97\x43\x80\x6\xe5#" 
  "\xc7z@\x18vO$\x5 \xe2\x61|\xdd]h\xd3x\'\x96\xf7\xd8\xe\xfb=\x94\x83W\?D" 
  "\x96\"\x81\xd4\xb4\xb8\x93r\xe=\xd4_$\xea\x1c `6=F\x92\xc0\x8c\x41\x12" 
  "\x38\x99\x1\f\xc0\xb7\x62\x61\x12\x46\xd2\xa2\x85(\xfd\xe8Y\x11\xd6-\x10" 
  "NTd\x11\x80H\x83$\xd2\x18\tJ9\x88\xc7#\x8f^\xea\xe4\x19\x1\xce\x30\xc3" 
  "\xccP\x1f\x91\x45\"\x98\x0\x88Y&\x9a:8P\x80s8n\xe6\xe6\x44\xbc\xf5\xa1" 
  "\xe\x3i\xc6\tKp\x0\x4U\x0\x9cr\x12j\xa8\x91w\xd2sg\x84V!H\xa7\x9a$\"\x19" 
  "h\x3W\x1a\x61\xddS\xc2\x91\x90H\xa0:\xa0\xf4\xc0J\xf\x8c\xaa@\xa9\n \x90" 
  "\xd2T0\x16\xf0\x80\x3\'\xa1z\xea\xa8\xfa\xd0\x16@M\x6\x35\xd0\x1e\x3\f" 
  "\x1c\x10\xc0\x61\xa0\xdcJ\xcc\xacI\xae\n\xe8\x2\xb3\x92J\xab\x1\xbaZy" 
  "\x14\xb2$y\x98\x90\x45\a\xfe\x9c\x64\x16\x0\xc4\xe6\x1a\x10S\xe(0@\x3v" 
  "\xa8\xaa\xd2\xb1\xd8t\xfb\xad\x1d\xc9\"$\x1aO\xd0\xce\xd4\xf\'*%\xb0l" 
  "\xb3\x99J\xf2\xaa\x1d\xccn;\x18\x87\x1d\n\xc1\xeb\x12Jj\xd3\x4\x39I\x4\f" 
  "\x4\x39\xc9\x14\x31\xce\x10\x4\x3\x80p.AT\xf6\x43\xc2;P\xfc\v ;4L%\xbf\?" 
  "\x10Po\xc5\x1a\xc6!\xf2\x10\x17yQ\x8bJ#k",
  (unsigned char *) "\xc1q\xc7\xeb\xee`[\xca\x30\x13%\nwb\xd4\x41s\xcck\xac" 
  "\fq\xf\b\x18\x8c\xf3\xcf@\xa7l]\xd0\x44\x17m\xf4\x13:\x1f\xad\xf4\xd2" 
  "\x38\x13\xc6H\x11O7\x11\x35\xd3T\x1fR\xa8!a\x10&L/U1\xb1I\xd7\"\xd7\x42" 
  "\x84\xd8n\x90m\x84\xc6\xeW\xb5u\xc6\bI\\O\xd2\xe4\x1dQr:q\x8bl\xce\x10w" 
  "\xb7\x91\xb7\xc2\xed\xd0\x17\x63\x39-/a\xdd\xdc]*\x91\x91\x8aU\x1f}x\x8c" 
  "~\xf7\xb0\xb8\x46p\x9f\xc3\x16ZG\xbd\xd4\x11\xb2vU\x3\x41V\x92U\x9e\xd4Q" 
  "\xfe\x33\xe1z\x13K\x85\xd6\x14^\x10X\x5\xd4\xb9S\?u\xf5U\x1$\x99\x84\x92" 
  "J\xa4\x9f\x1a\t\x2\xa6/\x83\xfb\x81\xb6oV\x93`\x4\x4 {N\xbb\x9f\xde\xf1" 
  "\xefv\xb8\x1e<9\xbd\a\?|\x1f\xc5/\xe3\x17\xaej\xc5\xdd\x94\xe5i\x85N\xaa" 
  "\'\x81\xd9\xe1<Nh\x3\x30\x38o\x96\xfcVhrObC\xbeo\xd1\x98\x66\xe4N\xd4" 
  "\x18@\x96\xdb\xe2\x90\x9f\xda\x0\x5\xd1\xf6\xd9l\x90\x41\x36\x9e\xfcj\x2" 
  "\xa0\x83\xa8!\x9d\x30\xd9\xc4\x7f\xd8\x98\xdf\xf\n\x18\'\x9b\xd4&`\xcc" 
  "\x41\xa0\x0\x81s\n\xf3\x95\x89}\x93\xa1 y\x18\xa8\x9b%]dp\xfd\x31\xd0|>" 
  "\xa3\x1fz\xf4H\x84\bz\xdfx\x6\x30\x93\x97\xf5m1\xe\xa0\xd0,\xd8\xc1\x9c&" 
  "E\xa5\x85\x96`\xa1\x7f\x66#\xa4\x1f)d\x85\x38\xfc\x1\x86$g$\v\x95I\x87.d" 
  "\xc7\x81l\xa8\x8f\x11\xaa\xd0\x37>\xbc\xe0\xf@\b\xa9!\xbd\xe6\x46\xe9+" 
  "\x92\x15k\x88\xad\x32\x85\x88\x1\r\x98\xfe\x92\x11q\xf4$\x1a\x32q\x1c" 
  "\xe0\b\xa3\xc3\xd2\x98\?\'I\xc9\x8bl\xfc\x81\x8f\x32S\xc4.q\xf1\x8bj|M\?" 
  "\xb6\xc8\x44>2$Es4\x8f\x14}0>\xe4\x1c\xca\x31\x62z\x14\x93\xf8$\x9c\x43" 
  "\x86)~d\xe2\xa2\x1\x4\x91\xa6\xbd\x19\xa4O\x93\x1a .\xb8X\xa6I\xbe\b\x1b" 
  "\x94|\r\xa0r3\xa8\xff\x85\x32",
  (unsigned char *) ",\xeb\x1a\x65\x98Ji\x11\x1bz\x12\x0i\x8a\x1f\xa2 \xf9G" 
  "D\xd2rLG\xb9\x14+\t\xf4\x92\x1e\f\xce\\\xe0*\x94\xb1`\xd4\x13\xf0\xb8" 
  "\xcbL\xd6\n\xd7\x30\x33\xe1*X%+Y\x94\xa8\x43\x65\xd0#\x8ej)\xe0Z\xd8\xa0" 
  "W\xb6\xb0u\x0S\xc9\xea\x9b\xa3\x8a&\x1\xfe\x3\x8dq\xa6+_\x4\x4\xa7\x2" 
  "\xc4\x39\xcd)\xa1\xf3K\xa5\xfa\x18\xb6\xd4\t\xcdrV\xa6\x99\x4\x10\x17" 
  "\xab\x90\xa5N}\x92\v\x9f\xe7\xd4U:\xbdI\xabi\xf1`h\x92\xe0\x81\xc1,\xa6#" 
  "\x87)\xf4\xe@`h\x17-D\xb0\xf0\x41\xadP\x89\xc0\xe8\xfe\xce\"\xaa\xd1P=b" 
  "\n\x12\xed\xa8\xcfx\x6\xd1\x8f\xee+\f\x84S\xc2\x1e\x46\x93\xb8\xab\xb5" 
  "\xf4\n\b\x8d\xc2:qu\x85\xc0\x61kf\x89\xb3\xe9K\x9d\x10\xd3\x9d\xfa\xf4" 
  "\xa7o\x3\xaaP\x87\n9\x86y\xcb\xa1\x66\x98\x9a\xd4\xb0V0\xa6\x16j(#%j\x19" 
  "\xac\xf3/H\x88q\x17\x92\x0\x1b\xdb\x86\xa1\xd5\x8b\x5\xa3\xab\x93\xe9" 
  "\x43/G6\x89J$Nk\x9aQ\x95\x18\x4\"\x8e%@$G\x85\x43H\x98\xa2z\x6\x65\x30" 
  "\x3TK#\f(\x8e\x3W*,N\x1e\x8f\x93\x1b=\x2\xfb\xc2\x8cyB;q\xd8\x87\xf8nV4" 
  "\xeb\x90\x82\xa6{yJ\x1fXG\x8e\xd8\xe1\x84v9\xf1\\L\xb4\xa7>\xf0\x81\xee/" 
  "\xcf\x92,U\xf2\x41\x80@^\xd2\xb3\xd3\x33\xe6\xf0\x30+\bw8\x80+\x12\xb3" 
  "\xec\xecV\x92Y\xca\x46\xaft\aJ\v\xf6\xf6\x42\t\xaa\x84\x16*\x1e\x1\v\xd5" 
  "\x86\x66\xab\x0x\xcf\x39\xf8\xbb\x9f\x18\xe1\x87@\f\xbaO\x1d\xf0\xa3\x8f" 
  "r\xfe\xa3\xf2\x9e\xa9\x34\xa6\x44\x82\xf4\xe0x&a\x8a\xee\x32\xa5\x7f\fQ" 
  "\xee\x4\x13H)\v\xf6\xc6Y\xd3}\x86\x80\x98\x16S<\xb0\x46\x86\xaeH\x8f\x62" 
  "\xad\xe7\xb7%b\x86\x93\x91\x91\xefz\xd0\xb4\'\xfa\xde\xf7\x8c\xb8\xb0" 
  "\xabo\xec\x38\x1e\xf8\"1\x87\x41lb\n\xd7\x63\x80<\xc0W\a`l",
  (unsigned char *) "\xa9^\xb1\x33\xaa\x16\xa5\xaf\xa1\x17\xf4\xa3\x1e/H" 
  "\xc0\xf4\xa9\n\xb1\xfe\xdd\x30~\xc7\xb3\a\x5\x4\x64%CZ\tvk\x84\v<\x16" 
  "\xc4\xc5&\"\x90I>\x97\xbe\x1\x80\xc8\xa2\?\xd3+.\xde\x93IX\x5\x8a~\x1c" 
  "\xfe\x92-q\x89\xcbN\xf6\xb8tq\xaa\xccXG\x8c\x8d 3\xa4\xc4\xe9\xa1\xcc}V" 
  "\x1c\x89\x1e\xbf\xd2\x19W\xe6\xe6##Q\xaf#\xd7\x61\x33\x38nZ\xe4\xaeY\x13" 
  "\x5`\xea\x1c\xf4\xca\xe6\xaex *e\xb9\xd9\x9f\xad\xba\xd7\x33Q\xe5\xb0{" 
  "\xa9\xd9J2\xc9\x84\xf3\x38\x91\x8f\x39\xd3\n\xa0\xddt\xb3\x9f\xa9\xf3\xf" 
  "\x10\xb7y\xd0wf\x0;\xd5}\'Ma\x8e\vFa<\x80\x8f\x66\x43\xaf\x8fx\xaajN\xb3" 
  "\xc4J\x94\x44\x8e\x30O\xac\xa4\x18\xf3\xaa\xd4\x94\x30\x80\xca\x80\xf8l" 
  "\x2;\x8e\x44\xe1\xb3\x80\x14\x13@.\xa2\xfeiO\xa5:\x85\xd7\x46\x5\xc8_0I9" 
  "\xd6;\xd4Y\xd3Z\xa6\xfa\xf0\xb4\x15\xee\xa3\xe2_\xfb\xfa\xd7\xc8\x6\xea" 
  "\xb1\x93\xcdl\tG\xae\xd9\xd0\x96\xf5\xb3\xa3M\xed\xb3N\xbb\xda\xd8V\xda" 
  "\r\xb6\xcd\xedn{\xfb\xdb\xe0\xe\xb7\xb8]\x0\x80\x10\x0\x0;",
  NULL } ; /* --- end-of-image2[] --- */
/* ---
 * image3[] contains a 2235-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (3) Can't mkdir cgi-bin/mathtex/\\cache directory: check
 * permissions.\\See mathtex.html\#message3}
 * --------------------------------------------------------- */
#define	IMAGETYPE3 1			/* 1=gif, 2=png */
#define	IMAGESIZE3 2235			/* #bytes in image3[] */
static	unsigned char *image3[] = {
  (unsigned char *) "GIF89a\xe9\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff==\xff\x1\x1\xff\x16\x16" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xe9\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcft=\x2x\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8\xa4r)Z" 
  ":\x9f\xd0\xa8tJ\xad\xf2\x9a\xd6\xacv\xcb\xedv\xb1\xde\xb0xL\x1e\x83\xcb" 
  "\xe8\xb4z=<\xfb\x6\x84\x1e\xc2\x31,(\x6\xb8\x82\xb1\x80x\"\x14zr\x80\x62" 
  "\x7f\x81J\xex~\x83R\x88m\x1\x41\x5\x6y\n\n\x6\x89\x3\v@\x3\t\xe\n\x4\v\v" 
  "\x92\x45\a\t9\x86{\t\xa2<\x5\xa9\x38\x9cR\xaf;\xac\xaa\x39\xb1\x42\xa5K" 
  "\x81\xb3\xabJ\xb8\x42n<\a}\x0\rz\n\x8f\x38\v\x89<\x3\r\xc3\xae\xb4\x42" 
  "\x5\f9\xd1\x45\x6\xd6\xd5\xa2\x4\xcbO\xdc=\xd8<\xdf\x42\x3tK\xaa\xe1;" 
  "\xd9\xe4\xe6\xbf\xc8o\xbe\xe}\xc7\x39\x3\x10>\a\xd4:\x3\xeb\?\n8\xe\xfa" 
  "\x5I\aN`\x15\x82H \x9c:\x12P\xdb\x8e\x86\t\x17\xfe\x0\xa6\x3\xa1+}8\xde" 
  "\xe9(\x10\xe0Y\x8e\x7f\f\b\x10\xd8\x16`\x1\x1\x5\a\xfe\x2)\xe8\xc3\xe0" 
  "\xc1\x1\x3\xfft\x10x`\x12\xe5\x0J)q\x84#\xf0\x12\x0&\x5\fZ)h \xa9\x99" 
  "\xc9\x0\x12\x37\x19X@\x8d\x41(\xa6\t\x86\x66\x33\x90@\xa4\x32\x0R\x1\x10" 
  "(y2\xa7\x8e{Ziv\xbd\x89\x32P\xc8\x91\x38Z\xbe\xfc\xb7\xb4\xeb\x34\x97" 
  "\x30\x1\x38\xfd\x34-A)\x9e\x99r\x80u\x4\xe4@L\x1c\xe5\x12\x9c:\xd0\r\a=" 
  "\x1f\t\xf0,0g\xe0\x80Nk",
  (unsigned char *) "\x16\xab\x39\x6\xd0\xf8\xb1\xe5\x5\xff\x10t\xc4\xd1" 
  "\x93\xb2(\x3\r\x0\xc8\x93\x85Tt\xa9\xcdL-\xf3X\x9ags\xba\xca\x9eu\x84" 
  "\x94\xacsr\xba\xc4\x0\x16\xab\xa6l[R\xba\x99\x80\x1d\x37\xfb\x83Qn\x1c\"" 
  "\x14s\xf8\xe5\x81\xe0\x81\xa1\xe5\xa4=\xe6\x31L\x0\xc2\xe7\xeb\xab\xd7" 
  "\xbd\xc6Ny\x1t\a\x93\x1t\xde\xee\x3\xfc\xe\x64\x6\x18\x17\xa5\x14\x93" 
  "\xe0\x1:\xe4\x63\xd7\xaa\xc8\x9d\xa0\'\xeb\xbb\xc9\xdf\xf6K\t\x19\x81\x6" 
  "\xc7\xcdWDr\x9c\xc5\x84\x0\x46\x9d\x89\xfe\xf7\x97\xe\xf9\xec\x30\a\x0Q" 
  "\xc9\x17\x1f}Xe\xa7\xdakQ9\xc3\x9br\xf5i\x17^2\"\xa1#\t\x3\xd8p\'\x9eo" 
  "\x1d\x9a\x92\xd7\x85\xdc\x45H\x1e[\xd8\x85\x83\x92\x35\b\x1c\xb0\x17\x0" 
  "\x5\xac\xc8\xd7\xf\xa9\xc9\xf5@\xe\r`\xf4\x80t\x80iX\xcd\x1f\x93Y\x87" 
  "\xe2n\xe\x41\x96\x62l\xe\xdcS\xc0\x8f\x9c=\xb9\xca\x66Z\xc9\x65\xe1jyi" 
  "\xa6G|\x4\x19p\n\x98\x92\xa0\x84\x83\x92\xb1-\x99\xa6o\xff\xe5@\a\x2\x92" 
  "@\xd0\x8e\x98\x46\x10\xa8U\x97\xe\xe8\xc1\xc0^\b\x84\x6O\'\x9f\xe0Q\xe3M" 
  "\f4\x80Y\x3\rP\x82\xe8\x82\x38\x36\xe0@\x80\x86\x1d\x90\xe8P\x93.:\x14" 
  "\x7f\x1\b\xe6\x94\'.)Zi\x90>0\xf0\x9e%\x0@p\xc0\xa9\v\xfc\xb1\xe8j\x9d" 
  "\xd8\x13\a\xa5\x9e\xc6\xea\x8a\xe(}\x1a\xeb\xa0@\x19\xda\xe8\xa3\xb0\xc2" 
  "Z\x80\xa3q\x18 \'S-e\xb2\xd5\x2z\xf8\x82\x9c\x46=|x\xd3)\f\x14\xd7\x83" 
  "\x1d\x85\xfe\x11\x39\x84\xb5K\xf4\x81\xad\x10\xc3,\x10\x95\'\t\xdc\xf8" 
  "\x83\x44@\x10 \xed\xb5r\x4\xe1\x11\xb9\x39\x98{\x84\x9dZ\x9d\x9b\x3\x2" 
  "\xca\xb2\xb1\x86I\xed\xea(E\xaa\xf6\xf6\xc0o\x9d\xcc\xf6\x30\xe\xf\xa3" 
  "\xf5k/{\x94X\x81\x80\xb8\x6/\x8c\x4\xbc\xd3\x31\xb7\xad\xc1\x14\x43\x81" 
  "\xc0\xc4j\\\xfcp\xc0\x15w\xec\xf1\xc7\x3r\f\xf2\xc8$\x8f\f\xf1\x11\x85$",
  (unsigned char *) "\x91r\xc9\xcc-R\xc4\xca,Sq2*\x6\xf9\xb0\v\x84\xed \xc1" 
  "n\x16\x37\x17\xd1\xf3\x18\xb6\x4\x11t\x14\x33\x1b\x11\x19\x11\xbf\x15" 
  "\x66\x34\x19G\xfT\xb3\x15\x3\a\x11\x35\xd1\";\xd1\xb4\x10W\x17\x1\x91" 
  "\x18Y\xfb\xd0u\xcc\x1bk\x92Jjg\xa9\xa2T\x8fm\x95\x95\x96I\xc8\xee\xf0SPe" 
  "\x12\xe5\x93\xa1[\xe9\xc9\xb6\x1egG\v\xd7\?#\x1\x15\x87Qu\a\x5V\xb8\x91" 
  "\xf4\x93wwn\xadM\x97OcS\xb3S\x82\x38\xcc\xc4\tU\x89\xcc\x85,\xe0H\xcdT" 
  "\x13\x61\x38\x19#7\x9c\xfe\xf7\x1\x0zuX\xc9\xad\x15L\xb3\x1d\x9b\xf8\xe8" 
  "\fgT5Gz8P\nn\xba\xc1nZm\x96\x1\xe7\xd3\x87\x9a\r3\xdeg\xa1\xc9\xa3\xfb" 
  "\x0)\x95&\xbb|\nPY*[\xc1\xb3\x4\x96\x1}4m\xfb\xf1\xb0\xed\x44%\xf1\xd3" 
  "\x97\x12\xe\x66\xe0\xe4\xc5\x11\x2\xc3;\x6\x9ah\xd1\xdb\xd6\x9b\x65\x6" 
  "\x1c\a\x9f\xfa\x96%\xaf\x17[\xe7\xa7\xf\x90\xf\x4\x9a\xb7\xc3}\x92\xd8Oa" 
  "l\t\xf0w\x18@\xe1\xf9\xddn\xfa\xc7\x9e\x0\xe8O5\tX\x11U\xe4\x83\x83\xe6" 
  "\xf4!g\xe5\xf9\x90\x84$A\xc0\xfe\x1c\xb0;\xd0\xd9\x92xd\xe7\xbfG \x84L" 
  "\x96\x19\x80KF#\xc2\xf7\f#\x1c\t\xac\x86\xf6\xb0S\xc2\x82]\xa1j\xb0\xa9" 
  "\x5\x8c\x36\xa4\xe\xec@\xae\"\x1\xb4\x12\xe4\x62\xd8\xbe\x3(P|\xd1\b\x5" 
  "\x3\x30\x46\x43\x87\xc4\x66\x87\x12\xa4\xcaP\xac\xe5\x9e\xc6\x44\xe3\x83" 
  "O\nG\x1\xa6\x61*\x1cQ\xf1|>\xa4\ry\xa6\xb8\'\t\xe6\x80@\xdf\x8b\xfe\x9c" 
  "\x99J\x85\x8d\x30\x66i\x82Z\xf1\x93h6\xa2<\x1\x32\xb0M\x0\x31\x63\xb0|S(" 
  "\xbd\x38.\x1aSR\x85Hl\x86\xa5\x39\xe6N\x8dy\xea#\x94Z\xc7\x1a\x1c\x65\xe" 
  "\x90\fD#\x1a\xe9\x44\f\xca\x4\xc2O\xe1\xa8\xe3\x99\xee\x88\xbeGj\x5R\x0" 
  "\xb0\x93\xa8\x2\x32\x0\\\x15*\x13\x9b$U\xafV%,\a\xf4(",
  (unsigned char *) "\a\x9b\x9a\t\x7f,\x85(\x8c\x94\x92l\xa3\xc2\xc3\xaf" 
  "\x1e\x45\x19\x39\xc9\xa8\x95;\xc0\x8d+\xea%\x9bX\x8e\x32Q\xb5\x34\x65S|" 
  "\xd9\x0L\tF\x1d\a8IUt2,\x6PJ\x1f\xb5\x8a\xd5/+\xa1\f\x2\xc0\xa7\x9at\x80" 
  "U0oi\xab\xa5\xc0\x81\xev9O\xd5\xe6\xa5\x3k\x11\x31\x62\xe9:\':\x1b\xe8" 
  "\xa0\x8d\b\x1\x82\xdc\xaa\x43;\x91&\t\x89\xec\xec\x65\xa2#\xe7\xc4\xee" 
  "\x99\xcf\x89\x15\rlI\xe0\xc4M<\xf6\x35\x80~q\x9c\x6u\x2\x1c\x18\xd5\xafJ" 
  "\xc4%\xa1\x41\xf8\'D\'J\xd1w!\xb4\xa2\x18\xcd\xe8\xfe\x8e\xc6u\a\x1c\xa1" 
  "\x1\x66\x16s\x99\x12@\xda\xc0\x61\xa8S\xa3\x61\xfb\x41\xb4p\xc4\xc3.\xe8" 
  "\xa2\x15\xbc\xd0\x19Lc*\x8d\x99\xe6\xa0m{\xec\x98\x1d*\xa1\x34\x33\xbc.<" 
  "5\x1a\x83\x88\xc0\xa1\x84\xa6=\x8dI\xb3*\xd5I\xc5P\f\xac\\t\v\x4J\xde" 
  "\x33\x8e\n\x85\xad\x45\x66kG8\x1aV\x9d&\vQ\xb4\xce^\xa3\xf9\x1f\x1a\xect" 
  "\x80\a<Tqm\xb3\xdc\x42\x34\x37\x96\xce\xa5%Di\xd9\x1b\xe2\xd4\xa6\x96" 
  "\xb8\xa8\x35(w\xc9\x62\x45\x36g\x96\xbd\xb1\xd5&nM\xa4h\xf0P\x8ev\x89\x5" 
  "\xb0j\x93\xcb\xddX\':\x98\x90\xce\x38hY\xdbR\x82\xa2\xd8\xc5\xd5\x42^b" 
  "\x80\x17hD\x10\x87\xf0\x85o5\xe6\x43\xa0\x62\xd4\x43\x1b\x45~v8@\x1m~" 
  "\xd0\x11Z4\x16\xce\x89\xb0\xfdLk\xad\x17\x1c\xf9\xad\xd1\xb6\xe6\xa0\x9d" 
  "\x39PC\x8d\xcf\xfa\x44v\xfc\xe4\xc2\xc9\xe6\xd0\x91\n\x1e\xc3\xb8\x1\x3!" 
  "u\xf0\xc3@\xe5\"7r\x0*\xc8j\xfe\x8d\xa8\xdc\x6\xe\xae\x86,\x82P\a[\xd8\a" 
  "\xee~\xa4:\xa2@\xf\x38;XN\xe7\xa8!\xaa\vJ\x14\xe4n\x88]E\xba\b;3D\xe3" 
  "\x8c\x98\x63#\xe9\x36\xb7L\x8a$\xcf\x1f\x14\x10\x10J|\xab=)\x82\x1c\x17" 
  "\xab\x38\xe0\xc9\xbc\x17\x44\x91\x85\xdc\x81\x38t\xde\xaaUB\a\xce\x80",
  (unsigned char *) "\xa3h$\fO\x10\x8e\x11M\xe1P\x93~(\xdc\xd8R\x99#\xa7" 
  "\x13\xcap~\xb1\xb3_\xfe,\x86=\xd9\x8d\r\x85\x19\x19\x1a\x16\x63%I\x91" 
  "\xdc\x1\x85[\x2$\xccz!\xaa\xa9\xa0\x4\x4\xf4\xf1J\xc7\x35\xf3~\x92\x92" 
  "\xe6\xa2<\xa9\xabY\x9e\x84\x95\xc0\x34r0\x89\x45\x13\xad\x94\x84\x15\xa5" 
  "\x98\x66\x1e\x80\x15\xcdij\xf3LX\xa6U\x90\xa5\xdc\x63oZ\xb3;\xdf\x14\x1d" 
  "\xe7>Y\xaaS\xf9\x30z\xcd\x9c\x83\x9e\xbe\x1a\x6\x2i\x8c\x12\xd2YHp\x7f`" 
  "\xcex\x9a\"\nK\xad\x87\x39\xd8\f\tv>C[\xf3L\xc6\xb7\b\x10\xae;\xd7\x43" 
  "\xa4\x63}*J\xbb@\xd0\x88\xc2\x96\x1_\x91\xd3W\xc7$\xbah+\xc4\x4\xd1\x62@" 
  "\x18\x43\'\xad\xe8J{\xba\xa2\x94\xfe\xb4\xa8\x63\x16\xeaQ\x9b\x1a\x64" 
  "\xa5>\xb5\xaa)\x96\xeaU\xbbz\r6\x88\xb5\xacgM\xebZ\xdb\xfa\xd6\xb8\xe\x1" 
  "\x0;",
  NULL } ; /* --- end-of-image3[] --- */
/* ---
 * image4[] contains a 2238-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (4) Can't mkdir cgi-bin/tempnam/\\work directory: check
 * permissions.\\See mathtex.html\#message4}
 * --------------------------------------------------------- */
#define	IMAGETYPE4 1			/* 1=gif, 2=png */
#define	IMAGESIZE4 2238			/* #bytes in image4[] */
static	unsigned char *image4[] = {
  (unsigned char *) "GIF89a\xe9\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x1\x1\xff==\xff\x16\x16\xff\x3\x3" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xe9\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcft=\x2x\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8\xa4r)Z" 
  ":\x9f\xd0\xa8tJ\xad\xf2\x9a\xd6\xacv\xcb\xedv\xb1\xde\xb0xL\x1e\x83\xcb" 
  "\xe8\xb4z=<\xfb\x6\x84\x1e\xc2\x31,(\x6\xb8\x82\xb1\x80x\"\x14zr\x80\x61" 
  "\x7f\x81J\xexlF\x88;n<\x5\x6;\v\n8\x3\v@\x3\t\xe\n\x4\v\v\x91\x45\a\t9" 
  "\x86{\t\xa0\x8f\xa7\x38\x9aQ\xac;\x5\xaa;\xae\x42\xa3y\x8a\x43\xb5:\x8e;" 
  "\a}9\x3\r\x94\x38\v\x89<\x3\x10\xbe\xab\xa8u\f9\xcb\x46\x6\xcf:\xd1\x38" 
  "\x4\xc5N\xd6=\xd4;\xd9\x42\x3t8\xd2\xb7;\xdfW\x1\x98\xb9\x0\b\f\a\xc2\x0" 
  "\x3\xf>\a\xcd:\x3\xe2@\xc2\xe\xf7\x42\xdb\xda\xfbU\xfd\x90<\b\xa4o\x1c" 
  "\x90\x81\xe6\x80\x4\xa4\xd3NW\x8f\x2\x1\x92\xe5\xa0\xc4\x80\x0\x1P\x4\x2" 
  ", \xa0\xe0@ \x5}\x18\x34\x38`\xc0]\xb5\x6\x1b\xfe;\xeP\xd0\x31\x10\x35" 
  "\x2$\xdfMb\xa0J\x1\x84H\xc7\x36\x6(\xf5\xee\xd4\x82\x66\f>\xfdL`S\x9c" 
  "\x81\x4\x16\x89\x1(\n cJ\x8f;\xe2\x1\x10I\x92\xe2\xc6\x5\x5\b\xa0\xe4x`e" 
  "\xcb\xa6\r4\x1d\xc5\xe3\x94k\xa0\x8a\x17O>\xf5\nU\x87\xd4\x46\xe7~4\xac" 
  "\xd6g.\x8e\xae<\x14\xc4\xed\x91\x0\xcf\x2p\x6\xe\x84\x93\x16p\x9a`\x0" 
  "\x81\a+\x9e\xa4.\xe2]P",
  (unsigned char *) "\xdb\f@\x0\xe0@\"D=\xe\x46\x39\xfe\xa9\x98\x87\x81K\x0" 
  " \xf6\x89|8`Eg\x18\x1bT\x12\x9c\x18qi\xc8\xa0\x45\xbb\xee\xdc\x17\xc0" 
  "\xdfp\xa5_\xeb\x38\x9dP\xae\x30;wM\xda%\xe5\xf8\x15\xeN\xf +\xf7|/\xf2r" 
  "\xc4\v\xe6:8\f &\xe2\xe7;\xa6\x37\n\a\x18\'Ka\xfd\xe\xd0q\xdey\xd5\x34P" 
  "\t\xda\xb1<G\xfezy\xf1\xee\xe3/%\x90\xbcs{\xf3=v\xe5\x98{1Z\x83\a\xf4Tg" 
  "\xd2~\x1\xe2\x30\a\x0\x44\xc5\xfew\x1fjK1g\x1f\x64\x44!3\xdb\x63\xfjC" 
  "\xdd\x30\x16\xa1\x42\r\x3\xd1`\x17S{\xfd\x14\x0\x9a\x62\x1d=\x3\xa2\x87" 
  "\x91\xb4\x97\xe0\x89\xe5\x89\xe8\x83~\xc3\x14\x18\x9c\xe\rH\xf4\x8b\x84" 
  "\xce\xfcqXr)b\xc7 a\xcf\x91\xe7@<\x5\xa8\x46\xa1\x82\xe2\xc8\xd6\xd4T\xe" 
  "z\x6\x1a\x2;!Y\x9e\x1\xa5Pc\x0\x1\x93\xe1\x30^\x90\xb0\xe5\x11%y\x1d\xe1" 
  "\xc0\xa3\x94\xf2Q\xf9\xe2^=t\xa2\x3$\x1$@\xf\x2Y\xf6\x90\xc9&\x9d\xe0" 
  "\x81@W\n0\x0\xc1$\x10@\xc0R\x9f\x3\x16\x0\x81\x3q\xe8\xd0\x91\x9f\x36!\n" 
  "\xa8M\xea\xb5Y@P\x9c\x8c\xf4\xa7\xa2\x10\xc8\x88\x3;\xfa\xe0\xf1\xc0\x1" 
  "\x9c.\xf0\a\xa0\x9em\x2O\x1c\x89Nj*~\xa4\f\x1a\x87\x1\xf\x38\xf0\xd3\xa1" 
  "\xa6\x96\xea\x1aGH-\xb5(\xa0w\xae\xa4\xe7$\aPz*\x82\?\xc0xW\x10\fX\xfa" 
  "\xca\x1d;\xd8H\x84\xb2N\xf4\xc1\xac\x10\xbe,@\x14\'\t\xfe\xbc\x5\x4OA" 
  "\x10`\xac\x65\x45P\x83\xad\x1cGh\x1b,\x9ai\x1ak`:\x6\x91\xb1Q\xejV\xe1)" 
  "\x15\x85Q\xf1\xee\x99\x42t\xc3\x43\x65\xe9\xaa\xf1\x1dKV `-\x14\nD3\xa0" 
  "\x14\xfe\x2!,)r<\x9b\xef\xc2H \xa0\x30\xc3\xe\x1bL.\xc3\x14Wl\xb1.\x13_" 
  "\xac\xf1\xc6\xb7\x1c\xbc\x44!C\x80\xcc\xb1\x81\x83\x18!\xf2\xc8Ux",
  (unsigned char *) "\xac\x4,\xff\x90\x12\xcb,H|\x9b\x5\xcbG\xd0\x8c\x6\xcc" 
  "\?\xe0L\x85\xcaJ\xc4\xeb\xc3\x36\xf6\"\xd1\x32\xbc\x43\x37YF\xd0\? \xbds" 
  "\xc6R\xf8\xec\xf\x14\x5\x89\xe1\xb4\x42\x45\xa3|\x4\x8c\xec`\xf5\x0Q\xb0" 
  "\xc4sQ\x9eq\xe4\x94\x91\x1e/YW\xcfL5\xdd\xf4\xce\x9e\x63Ou\x95\x1e\x99|V" 
  "\xecH%5U\xd2ib\xef\x44\x93T\xd5\x42rO\xdc\x9c}f\xd6\xa5o\xf7$\xb7{0=\xa3" 
  "\x95X\xb5\x11\xdeI\x1yg\xb5\x95J,A\xc5\x14\x2%\xd1\xa7N\xe6\xf\x30\x65" 
  "\x37\xd8\xfeMi48\xe6\xc8\t!,\x80\xb6\xe\xb3\x94\x91\x0t\x8e\xd8\x64\xf8R" 
  "\xc3X\xb2\xc5Y\x17\x19\xec\bh\xb5\xda\x65\x94\x8d\xb2\x8d\x2\xac\xbb." 
  "\x19\x65!Ie\xc0hIF\x99\xd9\x84/\x19\x39\x80G\xca\xfb\x1e\xc9\xec;|\xe6" 
  "\x65\x1f\xba\xbf\xc3\x1a\xee\xcc\xeb\xe6\xde\x95Z\"V\xe8\x96\xab\xe7 " 
  "\xbcn\xe0Sf:\xd3\xc7\xc1\x9e\x0\x1f\xcd$0\xe2Q\xf2\x41\x37\\\xe\xda\x1dy" 
  "_z\xdf\x5\x90\?\x83\b\x9a\x9f\xf4t\x80\x80\x1a\xa9\xf\b\xff\xab\x10\xff" 
  "\xd6\x93@\xfb\r\xec=tX\xa0^\xea\xc7\"\xf7\x0\x43<}\xb8`\xec\"!\?g\f\xd0" 
  "\x82#\xc1W\x10\xe\xd6\x80\x2\x38 (\f\xd0\xc3\x1\xe6\xc7\x9a\x65\x1c\xc5&" 
  "\xcajMu\xb8\xb4\x1f\x17^\xc8=\x1d\x61\x61\xfdlc\x0\x6<lB\x0\xa4\x86\xd9" 
  "\x80\x18\x8e\b1+<\x91\x18\"\x5i\xe8\x9e\x2<jS\xa1yb\v\xab\xa3\x43\xf2" 
  "\x38\x91\x1P\x1c!\xfbp\x83\x87\x41]*N\xa8\v\xfe\b5\x86\xf4\b\xd6\xd9\xe;" 
  "X\xc2\x9f\x92V\x95\"=\x99\xaf\x19\x85)\x12*,\xf2\x90\xe2\xb0Q1i\xd4\xd2" 
  "\x1a\xdd\x43\x46\'yI\xfyT\x9f\x18\x99h\xa5@L\xc6L\x0\x38\x64$\xdc(&8.\a" 
  "\x91Y\xa2\x63~\xb6\x18\x9a,=\xa0P\x88i\x15\x35\x12\x45\xf\x46\xad\xe7};" 
  "\x80\x94V\xd4s\xabJ9\xa3",
  (unsigned char *) "U\x9c\xc1\x94\x1\xf0 (BeR\x1f\x91\xe0\xa4,\x8a\x91\x0t" 
  "\xe5@\x95+)%%X\xe5*\xa0\x88g\x95\x9e\xd4\v(\rC+L\xf2\xf2U}\xea\x64\xaf" 
  "\x62\xa5\xcb\xcf\xc0\x61<\xc4 \xc0&@\xc5\xcbM63\x9a\xe0\xa8%\xbd\x82\xe0" 
  "\ve\xc9\xcc\x64\xea(\x2Ol\xc4\xad \x80\x63YuHV\xb7\"\xf1\xado\x16\xc1Y9" 
  "\x80\xa7\xf\xdc\x19\xce\x1f\xe6\x80gV#\x82&V\x92\xaf\xa9\xe5s\x92\xff" 
  "\x94\x2\x1c\x1e\xb8\x86\x80\xd5-\xa0\xeb\x43\xa8\x42\x17\n\x5|2\xf4\xa1" 
  "\x10=\x98\x1dX\x89\x86\x93\x41\xc1\xa2I\xc0\xa8\xfe:\xba\tQ+\b\xabX\xa1" 
  "\x91\xa1\x17\x2\x61\x33\xe3\xc4,\x16\x8f BIs\x80\x95\xa6`ra\xd4\x43\x3" 
  "\x8c\n@\x9d;\x8d\x41\x43\x46\xe9Ys\xd6\xc9\x83Z<\xc0\x9ei\x0\x6\x41\xc3" 
  "\x0#\xe0%\xa3jP\xc3\xe9\xbd\x90Z=qDm\bq\x4\xc5\xbf\f\xb2\x8e\xfb\x91\x41" 
  "X\ah\xc0\x41\x1d\xd7\xd2\xa0<\x8e\x1b\x93\xc3\xd3W\xa6\x92\xa1K\xd1m\x97" 
  "O\xd1\x3U\xea\xe6U\xac\xd0\x64\x14\x30\x19Q8\xd2j\xd6\xaahe-\x95s\xc9" 
  "\x33\x18Q\xe\xb5p\x85-gy\x1b\xe9\x34\x37X\xa9\xa0\x5\x15\x41\x91\xdb(" 
  "\xdaJ\x10\x1\xad\xe1`\x92\x11\x41\x1c\xb2\xf7<\xca\xde\xb0{\xb4\xf1Kw" 
  "\x9c\xe1=\xa0\x39O0\xc7\xf8\x83\xa5Z\xd3\x8f\xd2\xe6\xa6\x42~\vL4HB\x1a" 
  "\xdc\xe0\xf1\xb3\xe9\x1b\xcf\xf8V\xa1Y\x1cl\xa6\x19\x96mJ]\x86\xea\x5" 
  "\x95\xcd!\"\x12l\x93z&\xd8\xd4\n\x1d\x87>\xd8\xa9`p\xab\x1\x81\x97\x6Q" 
  "\xa9\xc6]P\xc1\xfe\x80u\x1e\x5\xe\x37\x0\x1a\xcc`\b\x93\x81\x1cP\xc4\xc5" 
  "\x0\x11\xbc.p\x1c\xab\x86\xa2\x9a\xc4OCTbq\xc9\xb4\xa2\xe5\xec\x92\x86%" 
  "\xe2\xc1\x9d\xa6J&\x1c\x92\x89<\x7fP\x80>X2-\xf0\xd0p\x88W\x84\x62\x80" 
  "\xf\xd3^\f\xa5\x65\x86:\xe8\x8f\x1\xfe\x63\xae\xde\xb2/`:@",
  (unsigned char *) "F \t\x15\xa7s>\x97\x44;\xb2R\x8a\xee\x9b\xa2\to\xaeu" 
  "\xe0\x90\xe4}\xac\xc4\x61\xc5\xe4W=\x7f\xf9Nt#1aH\"\xc6\x90K\xc9\xf0\"" 
  "\xb9Qa\x1dX\xd5\f\xf>\x5KP\xf7\xca\xc0\xa1RF\xb0*U\xa9r\x95\xa7=U\x92PB" 
  "\x6U+W\xf5\x63\x91\\\xc2)\xb0\x18\x45\x92\xfd\x94\aU\x5Y\x97\xb2\x12\x93" 
  "\x96\r\xb5\xcc)\xef\xf2\xc7\xce\x94&t\x9e\xa9\xe<\xed\xaau\x9cZ\xe1h~" 
  "\x9c\a\x3\xb4\xa9\xc1_`_\xc4Xb#\x9e\xd0\x13\b\xcc\xb2g9\xfd\x90\x84\xbe" 
  "\xd2\x37\x9d\xf5\x8cg8\t\xa8\x3i\xb1\x84\x0\xd5\x42X\xbe\x1c\x43\xdaQ+" 
  "\xf0\xd5\xc2\x62XW5\xe4\xba\x30\x46\x37\x9a\n\xc2(Y\x19\xf6\xc5\xdb\x8eQ" 
  "\xf2\xd2\xa0\xe\xa8\xa5\x43M\xea\x8a\x8d\xba\xd4\xa8N\xd7\xa9S\xcdj6\xac" 
  "\xba\xd5\xb0.\x83\rfM\xebZ\xdb\xfa\xd6\xb8\xce\xb5\xae\x43\x0\x0;",
  NULL } ; /* --- end-of-image4[] --- */
/* ---
 * image5[] contains a 2212-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (5) Can't cd cgi-bin/tempnam/\\work directory: check
 * permissions.\\See mathtex.html\#message5}
 * --------------------------------------------------------- */
#define	IMAGETYPE5 1			/* 1=gif, 2=png */
#define	IMAGESIZE5 2212			/* #bytes in image5[] */
static	unsigned char *image5[] = {
  (unsigned char *) "GIF89a\xe6\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x16\x16\xff==\xff\x1\x1\xff\x3\x3" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xe6\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcft\r\xdcx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8\xa4" 
  "\x31\x0`*\x9f\xd0\xa8tJ\xadZ\x9b\xd8\xabv\xcb\xedz\xb5L\xe7wL.\x9b\xbd" 
  "\xe1\xb3z\xcdn\a\xd3\xc0\x1\x81\x87p\b\v\x8a\xc1\xadP, \x94\b\n|T\x81" 
  "\x83I\xeznE\x88Pp>\x5\x6\x37\f\r\x6\v\f7\x3\v\?\x3\t\xe\n\x4\v\v\x91\x44" 
  "\a\t8\x86\x43\x5\t\xa3G\x9d;\xaa\xac\x38\xae\x42\xa6{\x8a\xb4Q\x8e=\a" 
  "\x7f\x0\x6\t\av8\v\x89;\x3\x10\xbd\x37\xab}\x97\x37\xb1\x43\x6\xcf\x44" 
  "\x4\xc5\x39\xd1;\xd4\x42\x3\xc2\xbe\xb7q\xdcJ\xba\xc6\xb5\xdd\xc6\r\xbb" 
  "\xcd\x38\x3\xd2@\n7\xe\xec@\xd7U\xf3H\r\x83\xf0\xde\?\xf7\xb9Y=\xf5\x6" 
  "\x14|\xd2!&G\x81\x0\xc9p\xb8\x63@\x80\xc0(\x2\x1\x16\x10Pp`\x90\x82\?\f" 
  "\x1e\x1c\b8\xae\xd2\xa5L\n\x18,\xebh\t\x0\x3Q\x96\xfe\x12(\x80\xc0\xeeWC" 
  "b\x0VF\x82(\x91\"*\x0\xe7Lj\xe4x\x12T\x1\x2\xfj\x1e\x18 \xb0\"\x0\xa0" 
  "\x9d~\xe9\xa1\x39\xd1\xa8\xc9\x86\xf\x83\x36%jSG\xce\x46\xfex\x1cp\'\x89" 
  "\x8f\x2M8\x86\xeePPPG\x2=\v\x84\x19\x38\xe0LZ=\x83\x1\xf8\x38H\x80\x0" 
  "\xe1\x8d\x8d\xaf\xe2\x2\x98\xdb\xe4OI_-\xc1\x1e\xfc\x33om\xdb\x1c\fq\xcc" 
  "\x3\x8a\x89\xad\x61_",
  (unsigned char *) "l\x1;\x13l\xf7\xf1\xbc\xb3\x0\xd2:\x8bl9V\xe2~eul\xe5" 
  "\xa1\xf7.W\xb8\tm\xc5$@\xe9\xb0\x64\x1doq8\x88\xfc\x8e\x36^\x1d\xb3\t:S" 
  "\x1b\x89*\xd7z\xc1^\x17\x8e\x45\xee\x35\x30\x81\x64\x85\x8f\x1a\x1e\xd6" 
  "\xe\xf3\x1b\x9fZ+w\xadl\x8a\x38\xd1\\U\xe1\bpz\xf4\x8e\x3\xe9n\xd4\x1" 
  "\xa0r\xfakk\x91No\xb6\x66\xdb-\xed\x1b\x12\x1d*\x8e\xc4 \xdarVx\x9f\xd7+" 
  "\x0\xf6\x30\xc5g\xfa\xdd\x17V$\xcf\x95\x17 u\xfcY\xfe\x97\xd5\xe\x7f\r" 
  "\x90S]\xc9<\x90\x1a&\xc8X\x13Hd\x94\x10( l\x4\xea\x30\xd8\r\x4\x14\xf0" 
  "\xc0\x80y\xf5\x32Gx\xd4Y\x3V]|\x1c\xe8\f*\xd7\x18@\x0\x4\xb2\x99W\x18" 
  "\x65-\nH\xd1\r\x19\xda\xc8\x8a\x1\x37\x85\xb3\xa0\xe\xa0\xc8\xc6\xc7_\x0" 
  " @c\xf\x9cx\x2\x8a\x1e\b\f\x15\x12\x4\v\xac\x4\x81@\x10\\\xe9!\x4\xe\xcc" 
  "\xa1\x3\x3\xc1\x18\xa0\xc7I\x9fh\xa4\x9e$a\xea\xd1\xc0\x1l.\x10H\x96g" 
  "\xfa\xe2\x89\x83sX\x89\xe5\x95vVg\x10\x97s\x18\xd0\x80\x3\x96P\x84\'\x9c" 
  "y\xae\x35Q\x2u\x12\ng\x94\x44\x31@\xa5\xa0wF\xaa\xa7\x14\xd7\x89\x96\x3Q" 
  "\t1\x80\xe2+y\xe8\x30\xa1\x10\x9f\x8a\xe7i\x92\?\xf4\xb2\x80J\x9f$p\xd5" 
  "\xf\x41\xfe@\xc0\xa6\xa4\x9e\x42\xc4\x35\xad\xee\x10\xaa\xf\xafRQi\xe" 
  "\xb9\xf6\x80@q\xfa\x1c!\x11\xe\x45Z\xe1&=\xf1Hq\xac\x82\xa1\x61SM\xe\xe" 
  "\xdc\x1a\xac\x10\xc8\xfe\tt\x5\x2\xab\x46\xa1@4qJ\x81m\x15\xbbzH\x87\xb4" 
  "\xd3*\x82\x0\xb9\xd3\x9e\v\xee\x90\xe5\xb6\xeb\xee\xbb\xdb\xb1\v\xef\xbc" 
  "\xf4\xba\x11.\x14\x85\x80*H\xbd\x39\xe4[\x84\xbf\xfc\x32\xbb\x5,w\x8c" 
  "\x34\v\x12\xb5^Ap\x1f#\x99q0\x10\xfS*\xaf\x14\xb1\xf9\xb0\xd8\xb3\x45${E" 
  "\xc5\x41p\xec\x45\x36\x42\x80\xac\xeb\xc4Qx\xbc\x83\xc9\x44\xe4",
  (unsigned char *) "\x43\x6\xca\xffh\x1c\xf0\x12\x13\x83\xb9@\x1\r\xa8\xa4" 
  "\xca\x39\xe\x85\x34\xc7\x31\x12\xe9u\r\x1\xb7]Z\xa5H\xe9\xb1\x4\x0\xcf" 
  "\x10\xf1\xd1\xd3\xccG\xaf\x62IF\x1b\xb9\x93sbH\xc7%RN\xaa\x42\x12\xf\'" 
  "\x1e\xf9\"\xd4 K\xf3\xc1uI\?\a\r\xe2\x3Iaf\x92\x44\x33W\xfd\x93T\x14Qe" 
  "\x94LI\x6\xc4Z\xdd\xd1\xc5\x64\xf4Q\x1%\xc6TU\b\xd8\x9dm\xbc\xcd\xe2\xd0" 
  "\xc0%+\xc1\x17\xd3\x88<\xba\x63\x0\x8d\xd1JV\xa5\xadv\x1p[a\x90#\xc0\xd8" 
  "\xd1\x15\xe9\xc5\xd7<\xfe\n0\x8e\x93\xe3\x99\x9b\x94\x93\x1\x84\xb1s\x90" 
  "\\\xa6tv\x14\xe3\x3t\xce\xba\xe4\xddV\xb2\aB\x9b\xc7\xeeK\xe9\x96q&\xa0" 
  "\x8c\xef\xf8\xe2%o\x8b\x1b\xee\xb8\xef\xc2\aO\x1a\xc9\x89\xcf\xe5\xc7%\t" 
  "\xf4\xf7\xcby^{\x87[{\xae\xd5s\x9c@\x1\xe4\x86\x9e\x32\xd2\xb7\x1e\v\x2" 
  "\x12\xee\x5\x84\xf7\xf3\x1d\xb6=Y\xe8Of=\x87\xcd\xad\xcf\xc4[.^3\x80\x46" 
  "\x91\xdf\x1fL/\xd7\x44\xaf\x98\xf8\x87\xd1_\xe4\x96W8\x1c<\xa0\x0\xe\x38" 
  "\t\x3\xf8p\x0\xe9\x39&\x16\xbfX\xc9\x84\x1e\x63\xb9\r\x1\a\x82\xef\x91\f" 
  "E\x1cH\xbd\xcc\x18\x80\x1\xe4\xa2`\xf6\"a6\x11\xfa\x42%\x15:\x19~\xd6\x2" 
  " \bZP@\x5(\xc0$\xd8\x12\xc3\x19\x1e\xa6\x81\x8ay\xe0\x61j\xb8\xa6\x1e" 
  "\xdc\v2z\xe0\x92$\x96\x84\x93K\xd0/\x12\xe\x18\x9c\x88Hd\x9e\xa3\x10\xd1" 
  "\x1\x1f:\x8a\x64>H\xc4\xc3uPD\xach\b\xf\xa2\xd8\'\x1\xcd\xc8H\x95\xeb" 
  "\xfe\xe2^\x6\xe7\xb5\xdb\xfd\xe4\x89\xd4\xab\x1f\x81\x6\x41# \xdd`I\xd7p" 
  "\x94\xe1\x8c\xf8;6\x1e\xc5K\x84\x3\x42\x1\x96\xd4\x0<\xfa\t\x1e\x45\x83@" 
  "3V\xb2\x15\xb2$\xe0&d\x2J!\x15%H\xc5\xfc\xa9$`\x82\x87\x1e\xf6\xd8%_\xfc" 
  "\xe9\x1aVB\x91\xda\xc8\x3,\x1c\x44RLv*\xd4#/\xf1I\xa2@\xa0",
  (unsigned char *) "\x90\x1\x38$l\xep(/\xfd\x31PY\x1a\xe4\x1\x6\x45\xcbHUB" 
  "\xe\xce!\x6\x1\xec J@\xea\xad\x96\xb7\xdc%\'uS@\x1c\xf4\x62\x42\t#\xc2" 
  "\x1f\xd0%\xab~\x8d\xaa\x99\?\x0G\x10\x98y\x13\x66\xee\xf0\x15QX\xa6\x31" 
  "\x63\xd5\x83\x64\x92JZ\?|Y+\x10\xd1\xad\x36\xb0L\x9c\x37\b\':\x89 \x87r" 
  "\xb2\x61[\x1cY\xa7\xf\xd4)\xcfz\xda\xf3\a\xf4\xbc\xa7>\xf7\xf9\x43<LR\r" 
  "\x0\xcb\xe6\xbe\x9e\x10P\xf1\x1cs\x9f#+\xa6\xa6\x0\x0\x89\fva\x10\v\x13" 
  "\xd7\x11\"*\xd1 P\x14>|\xd0\xe2\xfe\xb4&\xd1\x35\x33\x84\xab\x0\xb4\x89R" 
  "\x19~\xd4\x92$x\xcc\x65\xdf\x33\v\x8f\xac\x39R`Hs\f\xe1\n]2P:\x5\x95up/4" 
  "\xe5\x1\xc7l\xda\xb1g@\x82G\xed\xca)\x18Hv\x80\a\xc4S\x12lSZR\x89\x4\x37" 
  ")U\xe5)\xf2\xd1I\xd4\xbc\xd6\x14\xa5\xed\x64!I\x15\x89)\x80\xd6\x9f\xc9T" 
  "U\x12W\x5\x8aP\xe4\x36\x88\xd8\x30\x62\x1b\xc4j*Y\x91\xea\x93\xc0\xe5" 
  "\xcd\xadw\x83*+N\xe2\x11S\x84\xcd\x17\x2\xc1\x63\x19~\xf8\x38\x11\xcc!w" 
  "\xac\x84\x9d\x43{\xe7\x1a\xcch\xe6<\xae{\r`\x8f\x86\x8c\x90\x9c\fy\xd4!" 
  "\xect\xb4\xc6\xc2\xca.\x87\x33\xc8\x3,\xf0\xcc\xb7Ya\x18V\x18v)\xc9\x62" 
  "\x17\x18\x93\xae\xc2\x94\x64\xc6t\x0\x42\xe4\'\?\x15\x8eP!\xac\xd9\x90" 
  "\x8f\x94Q\xc8\xe4\x38Q\xaf\xe9\x43,I_K\xbdo\x91\a~\xd3\x91\x9f\x0\xff" 
  "\x30\\\xd8J\xc7\t\x6\xb0\x43ksP\x1a\x32\xc4T=W2\x9b\xd9\xfe\\k\x1e\x3" 
  "\xe9h\xb6\xff\xb1\xd5\x1\xc8\xf8\x1c\r\xceV2\x81P\x0<\x4\x82\xaa\xdf\xbc" 
  "\xb0\x82\x6\x91\x61\xfy\x18\x19\xeb\xc2\a*w\x89\x85v\xd2\xe9\xce\xa1\x16" 
  "p[9@\xc6\x17\xdf\xb1_\xf3\x1\x97\x39;\xc2I\x8c:t \x19\xa1\x31p8\x11\x86" 
  "\x46\xbb\x1b\xa3\xef^#\xbc\x85L",
  (unsigned char *) "\vrx\xfb\xb3\'\xba\x11\x0m\xb4\x63\x80{\x84\xa2\xfe\"" 
  "\xe2\x41\x95s\xee\xc4\x14\xb0\n\x81X\xd1\x92\x80\x32\xe2(u\x0\xa9P.JJ" 
  "\x8e\xd2\x4%\'\xc2Hw\xcc\x18\xc5O\v\xcaQ\"\xa2\nS\xb8XK\f\xe5S\x8bk\x9c" 
  "\'\xa0\xe2\x84\xc5\xb3\x8cT/-\x11\xcc\\\xe2\x32I0\xa6\x12N\xd8\xd4@\xc2" 
  "\xac\x18\x8a\x99\x81U\x17\xc2\xa5.\x81\xa4\xe6&\xde,\x15\x1d\xa6i\x10o!" 
  "\x1\xadGF\x98\xa8\x92\xa1Mg\xe\x3U\x4P\x15\x34\x8fv\x11\x35\xe4\x13\xa1[" 
  "8\xebK\xbf\x30,\x10\x99\xf6\x16w\xc6\xf3\x15\xb8\x32\xd0\x33T\xab\xbel\b" 
  "\xb4\xa0\x17)M/E3\xfa\xd1\xedr4\xa4\'\xed\rIS\xfa\xd2\x89\x46-\xa6\x37]" 
  "\xe9&\xd4\xe0\xd3\xa0\xe\xb5\xa8GM\xeaR\x9b\x9a\x4!\x0\x0;",
  NULL } ; /* --- end-of-image5[] --- */
/* ---
 * image6[] contains a 1954-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (6) Can't fopen("latex.tex") file:\\check permissions.\\
 * See mathtex.html\#message6}
 * --------------------------------------------------------- */
#define	IMAGETYPE6 1			/* 1=gif, 2=png */
#define	IMAGESIZE6 1954			/* #bytes in image6[] */
static	unsigned char *image6[] = {
  (unsigned char *) "GIF89a\xd9\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x1\x1\xff\x3\x3\xff==\xff\x16\x16" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xd9\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcf\x34\n\xdcx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8" 
  "\xa4N\xa4l:\x9f\xd0\xa8t\x8a\x64R\xaf\xd8\xacv\v\xb5r\xbf\xe0\xb0x\xea" 
  "\x1d\x9b\xcf\xe8\xf4\xad\xdc\x1b\x10x\x88\x87\xb0\xa0\x18\xdc\n\xc5\x2" 
  "\x62\xa8\xc0\x63\xdd\bxz7\b}j:\x81\x0\x83\x0qA\x3\x86\x8c\x90\x43l;\x5" 
  "\x6\x38\x3\f\n\f7\x3\v\?\x3\t\xf\n\x4\v\v\x97\x44\a\t8~\x95\t\n\x1X\x96" 
  "\x0\x6\xb1\xaaw\t\xa8=\xadH\xbc\x41\xb5\x0\xb7\x9d\x9f=\b\xaf\x0\xeo\x5" 
  "\xb9\x45\x94:\a{\x0\f\x9f\b\x1\xd1\vv<\x3\xe\xd1\x37\xcc\x44\x5\x9c\x37" 
  "\xba:\x6\x97\xbeQ\xd0\x8cr\xe1\x38\xe6\?\xe4G\xf1@\x8d\xed\x38\xd8=\xf" 
  "\xa8\x4\xd9\xef\x44\xce\x98V1\xb2\xd6\t\x13\x84\x1e\a\xc4\x61\x9a\aD\xc1" 
  "\r}=\xfc]\t\x85\xc3!\x0\x8b\xb4\x18>\xd4(\x4\x62\x11\x8b\x18\x1\f8\xc8" 
  "\x43\xa2;\x8e<\xfe\x0\x8e\x43\xc5\xe0\xc0\xa3\x37\x39\x62U\"\xa8\xc3!\x3" 
  "\x2\x4\xf6\x5X@@\xc1\x1\?\n\xf6\x30hp\xc0@\xc8\x8b\a\x8a\x2\xc8\xb9\xe9" 
  "\r\x81\x6\xa2\f$\xc8&\x8d\xe7\x82\x2\x4v\xf6\xfc\xb9\xf2\xce\x1e\xaa\x19" 
  "o\xdc\xcc)\x96\xa8\xd1\xaa\xa5\xc2%XE\xe0\x0\x31\x1c\x43\x8b\xda\xb4\xaa" 
  "\x96\xad[E_w\xc8\xac\x99\xd4\xdc\x37\x7f\xd3\xd2\x86]\xb2\x97\xc7\x1\x8b" 
  "\x6\x1a\xd8\xd9\x96\xc3\xe5\xeX",
  (unsigned char *) ">\xa6\x2X \x87\xd6\x81\xae\xe5\x34\xbeS\xd0\x0\a\x4" 
  "\x87\x6\x88\x15 \xf8\xb4\xd3\x65\x3\x97\a\x1f\x86\x87J2e\xcc\xa5\x45^" 
  "\xdeVHa\xe\x7f\xb1\a\xcc\xe6\xb6)\x88\xe3\x1d\xfe\x82_\xca}z\x9e\xca`" 
  "\x88\x5\x2\b\xa0p\xb5\x8e\xd1\xddX\xdd \x5\x1\x95p\xe0\x9a/%x+up09\t\xe+" 
  "\x80|\x1d\x39\xeb\x8a\x4\xaa\x63\xe\?\x1e\xf2\xd2\x64\x11[\x8bwO\x0\xbe" 
  "\xef\xa3\x98\xaf\xb3\x1f_\x98\xf0\xf\xe7\x4(\x17\x80.\xce=c\xdb:\x0\x1c" 
  "\xfeS\x9eI]\xe1\xf7\xce]\xe3\x14\x87\x83RJ\xdd\x66\x1d*\x5\x96\xd4\x1ah" 
  "\x17\"5\xf\x2\a\x90\x84\x9d\x87;\x80(\xe2\x7f\xf8\rv]\x85@\x1c\xb7\x80" 
  "\x38\b8\x80\x43\x0\x18\x35\x10\x1d&\xdc\xdcVHj\xd5]R\x9e\x85\xb4\x8c\xc8" 
  "\x80\x8c\x37@\xc0Ihw\x4\x80G}8\xc8Q\xde\x8b\xe7\xf9T\xe4;T2\xf9\x10#\x97" 
  "@P\xd9R0UI$\x0r \x90\xe5\x96>\xd8\xa8\x61~\xc3})\aNz\xf5\xa7\x43)p9\xf9V" 
  "\x8c>\x84\x32J)v\x80\xf8\xc8\x90\v(\xe0\x80\x3\xe3\xfdyT\x1\xe<\x0SE\x7f" 
  "\x1e\xa9\x65p\a\xf4\x94\xc0\xa1\x6h\xf9\xa2\x9f\x80R\xea\x10\x9c=X\xaa" 
  "\xe7&\xe|B\xa8\xa1\xb4H\xca\xc0P\x9f\x64uU\x82\x2}\xfa\x46\xa4\xf\xbcH" 
  "\xeaR;\xa1\x83\x3\x9d\x8f\t\xea\xa7x\x82\x86\xda*\'k\xb5\tDj\x84H\"\xcd" 
  "\x81\x95\xd4\x81\b\x12\x37\xee\x2\xa4\xac\xb2>CD\xb2\x8c\xe4\xd0\xac\xf" 
  "\xd1\xfeM\xfb\xc3\xa8MX\xbb\x9c\x9bo\x12;\xabr\x87\x9c\xa7\x4\x1\xde\x86" 
  "\xfb,\xb8X\x1cw\x3\?\xf9@knE\xe6\xa4H\x4\xbb\xef\x1e\xf1\x80\xbbR\xa8{\a" 
  "\x1c\xf8\xd6+\x85\xb6\xfe\"\xd2o\x14\xfa\x6l\xf0\xc1i\x14\x8c\xf0\xc2\fo" 
  "\xa1p$\x0#\"l\xc3\x14/\xfc\xf0\x32(\xf1\x80\x31\x1a\xa2\b\xd1q\xc5\x16s" 
  "\xeb\x3\x83\x42\x90\f\x6\xbd@\xa0",
  (unsigned char *) "\f\xb2\xc1\xf{G\x84\xc9+\xc7\xac\xc6q\xa1\x84v$O>\xf9" 
  "\x11\xd8\xa9\x35\x43\xf9N[\xf1<\x15\x95\x64\x62\xd1\xb5\rOJ>\x85\xb3K" 
  "\xe3q\xe5\xe7%bR\x87%uO\xafk\xd4M\xb0.\x8dG\xd4\xe9\xc9\x9c\x85J\xa3\xe1" 
  "\xf1\xc0*\xa8uE\\\xd8`\x92}I\x9f%\x89\x46Zg\xb2\xd1\"\xe3\xbd\x96\x45" 
  "\x88&-09\x99wX\x9cy\x6ZjU^\xe9\xf5\x15*=\x0\xec\xdd\xfb\xc1\x62x9\vd\b" 
  "\xe4\r\a\x80\x37_,&-\xd8\xe1\x0\x44\xd1\x8dy\xe4{\xbc\xb3\x9d;\xfejw\xb5" 
  "\x39\xdd\x83S\xa1R\xd9\x8f\?H\xe\xea\xa0\xfb\t\xad\x44\x14\xc6Sy\x87*" 
  "\x9e\x13\xe\x4\x97\x15p\xbb\x84\x10\xd6}\x9d\xee\f\xe0^\xba\xe9\"+B\xd3" 
  "\xaa\x1dZ\t&t\xeb\x86\xf5\xc0\x89\xee\xb8\xbd\xa4\x9a.[\xde\x95\x1~\xc8" 
  "\x88\xfd\r\xda_2\xa4gGv\xb8=2\xeb\x1e:\xbc\x12\xc7\xb5\xa4\xcf#\xb6\xe6" 
  "\xca*\x94\xea\x1b\xc0\xbex\x1$\xe0\vj\x8e\x42**\xa5\xe2\xf8Ti\xfb\xff\x3" 
  "Th\xdc \'\x2ZJW\x9b\x1\xa0\x2\x6H\x80\xca\xf4\xea|M\xd0\xd7\xc0\xf6\x95" 
  "\x83\t\x9e\x44\x11\x1a{\xc2\x1e\xba\xb1\x41\x1fh\xab\x83\x10\xccW\xf1" 
  "\xc4\x0\xb3\x10\x9ap\x12#\x4\xc3\x2\xcfr\xc2\x16\x36#\x85.\x8c!\xcb`(" 
  "\xc3\x1a\x9aK]t\xb0\x43\xc4\xa8P\x88\x1d\n\xa1\x87N\x0\xa2\xc0\ba\xc3" 
  "\x1e\xa4\x8f\x13\x96\x38\x1c\x17\xfc\xb0\xb1J\xf4\xe2\x1bN\x9c\x3\x14" 
  "\xef\xb1$\xf3\xd5+\x13\xbd!C\xf1\n\x0,\x10\x91\xf0\x82\xc0I\xfe\x2\xcc" 
  "\x32\xf6\xb8\x1c\b\x4\x2\x16\x1c\xc3\x34\x6\x92\x46\x14\xfa\x80\x33\xdd " 
  "c\x14<\xe2\xb2\x8d\x88\x91!t\xfc\x45<f\x1\x0\xe8\x99\xab\x1a\xd1\x0K\x17" 
  "\x46x\x80\x6\xb0\xb0h\x82\xd9\x99/\x94\xb6\x95G\xe4L,8a\x89Y@\xa3\x35iL" 
  "\x12-Wa@\xaf\xda\xf2\x96qT\xd2\x92ra\xa4O\x1c\xc9\x95:>`",
  (unsigned char *) "1[\x12%\xd3\x1e\x89I=\x18\xa5k\\#\xc9Xt1\r\x9b\xad\x42" 
  "\x91-y\t\xe1Rh\x0\a\x88\xc0)p\xd3\rq\x80\x3\x38\xc0\xb5\xc6\xe\xaf\xf1" 
  "\xe\xea\xca\x33L\xda\x64\xf1\x36\xc6\x4\x63\xdd\xa6\xf9;s\xa0\xc6\x1c" 
  "\x45\x61\x94\xdd\xc2\x42\x1c\x3\xec\xcd\x9b\x82sMe\b\x2\xa5n*F$_\"\x18\r" 
  "\xe3`\x8d\xc4\xd5or#\xaa\x1dz\xd4\xa3L\xda\xf9\xc3\x9d\xeb\xb2Of0S\xcf" 
  "\xbb\xb9\f\x1$A\x97\xf5\xdc\x39\xba\xaf\x64\xae\x1b\xd4\x41\x85L\f \xb9" 
  "\xf6\fH@\xe5J\x82J\xc6\x93\x3@\xb1(\x18(\xb1^\xfe\x82\x38\xd4 y\xf2\xed" 
  "\xa2\x84\b\xd1\x99\xfa\xc9Q\x8f\xbe\xa3\x10\n\xd0\xc7x^AQ\x93^\xe2\xa2" 
  "\xc0\x13^LS\xa3 T\xf0\x84,\x18\xcd\x41\x80\x66$\xc7\x7f\x14o\x81\x15\x45" 
  "\x80\xf2\fE\xbd}\xcaSJ}\xa4\x92\x8f\\\x8a\x37\xea\x89\xa9\x8f\x95\x61" 
  "\x93G\xc3\xe2#{v\b\xa5\xe2\xa1L{\xfc\xf9\x33\x35\x8dO{\xd9\x43\xca\x94" 
  "\xbc\xf7&5\xd1j9\xf2\x92\xe8Os1\x1e#\x8d\x43T\xba\x82R\xe\xfc\x17\xa8\x0" 
  "\x6\x85i|RD\xa1z\xa2@\xbd\x82\xea}\xa3j@\xa9\x62\xd5+K\x1d\xd0\xaf[\xb1" 
  "\xab\x61sU\xa4\xc6\xce\xf5\x0\x8au\x9f\xa8\x18X\xc0\x6\x32\x2\xaf\x9d" 
  "\xea\x63R\xdc\xd2\x39\xb8\x32@N\xc4\xa3\xd6\x1e\xc6s#_\xf8\xb0\x44p\bB" 
  "\xb5\xa0\xd0\xc6\x1c\f\xa0\x32~\x1c\x82\x1f@\x18\xad\x1b\x45g\x1,\r\x90" 
  "\x88x!D-\x16q\f\xa7\x14\t\x99\xc2\xc0\x13\x1c`J\f-\xfb\xad\x13@rZ)\xb4" 
  "\xa7\xa5\x63H\xaer&\xa7\xab\x5\xe9R\xf7\xba\xbe\xc5\xaev\xcd`\xdd\xedz" 
  "\xb7\n4\xfc\xaex\xd1W\x83\xf2\x9a\xf7\xbc\xe8M\xafz\xd7[\x83\x10\x0\x0;",
  NULL } ; /* --- end-of-image6[] --- */
/* ---
 * image7[] contains a 2110-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (7) Can't run latex program:\\check -DLATEX=$\backslash$
 * "path$\backslash$", etc.\\See mathtex.html\#message7}
 * --------------------------------------------------------- */
#define	IMAGETYPE7 1			/* 1=gif, 2=png */
#define	IMAGESIZE7 2110			/* #bytes in image7[] */
static	unsigned char *image7[] = {
  (unsigned char *) "GIF89a\xd9\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x16\x16\xff==\xff\x1\x1\xff\x3\x3" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xd9\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcf\x34\n\xdcx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8" 
  "\xa4N\xa4l:\x9f\xd0\xa8t\x8a\x64R\xaf\xd8\xacv\v\xb5r\xbf\xe0\xb0x\xea" 
  "\x1d\x9b\xcf\xe8\xf4\xad\xec\x1b\x10x\bG\xb0\xa0\x18\xdc\n\xc5\x2\"\x8cP" 
  "\xe0\xd5\x80Ml<\x5\x6\x37\a\r\x6\x8a\f\x0\x3\vm\t\xe\n\x4\v\v\x86\x44\a" 
  "\t8\x7fY\x5\t\x97=\x9c\x81\xa3K\x1\x41\a{\x0\a\x8a\x6\t\n7\vv;\x3\x10" 
  "\xa9\x37\x9fy\x8c\x37\xa0Y\x8a\?\xbc\xa4\xc1\x83:\x3\x9a\x0\x5\xb2q8\x3" 
  "\r<\a\xba\xcb\xc0\x41\xaf\x0\xe\xd2T\xbe=\xd6\xc1\xdck\xa6\xbf\xd2\xc0" 
  "\xdf\x39\x5\x1\xb6\x38\xaf\f\x4\x4\x97\x4\x1\v\x4\n\a\x7f\n{\f\xf\xab" 
  "\xd4\x39\xb4\xf0\x1\xc8\x10\x86h\x19r\aO\x9e\xa8]\x97\xd4\xb1\xbbq/\x1f" 
  "\x0\x6\xf0\x16\x14`\x90@\x13\x81\x3\x8fr\x10x\x10\xa9\x95\x1d~\xee\xf0" 
  "\xb0S\xa0\x8e\xa1\xa5\x5\x14\xfe\x41\xfa{\xb8\xae\xdd\x83\x82\a\x6(0\x88" 
  "P\xca\xb0\x1c\a\xf4\x31\xd4\xa9J\x16\xbaq;\x12\xd8Y \a\x80\x81\x3\x35ud" 
  "\xe3\x61\x0\x42\xb5=\xd9\xa2\"5\x1a\xee\x92P\x0\x44\x93n\xbc\x31\x0)\xad" 
  ">\xd0r\x18\xc8X\xe\xaaS\a}\x1e\xe0h\xf0\xca\x1cV]M\x9f\x2\xb8\x9a\xd5" 
  "\xe8\xd4\xa3I\x97>\xb9\x89#\xa7\xe\xb5:\xfc\x92s\xab\x83\x1e\x81\x44y" 
  "\xab\xfa\xd0\x1b\xf5R\xe3\x1d",
  (unsigned char *) "K\'!\xa6z+\xe7\xcco\x4 \xbc\x61\n\xea\x80\x9c\xa5\t2" 
  "\x1a\xd5\xf4\xcd@Q\xbd\x0$;^\x9d\x94\n\xdf\x43:\xbb\xee\x10\x8c\x33,\x0" 
  "\x65\xae(\xeb\x46M\x99g\xeb\xdd\xacu\x8b\xb5\xfa\xea\xb1<i\b\x10\xf5X" 
  "\xbaJ8F\x1cx\xe1-\xfc\x9d\xfb\x31p,\xaf\xdf\xe6p05\xc7\x83s\\k\x89\xed" 
  "\x33\x35\x91!\xeb\xc3\x8drN\xf`2z\xe8\x86\xe4\xdd\x30O\xd9@f\x1cr\x10" 
  "\x18jPT)\xd9\x95K1\xe0\xd4|\x8c\xd8&\x9c|\xed\xf9\xfe\x62]6\xeb\xd8\x4" 
  "\x14\xf\x94\x88\xd5\xdd\r\b\f8K$\x93\xc4r[L$A\xb0\x80\x2\x10@0S\x88<\x15" 
  "\x0\x81\x3\x9b\xe5\x0\"\x4\xd0x\"S\x2\"\xae\x38\xa2\x88*\x92\x98\x9cL\x2" 
  ">b\"\x8a\x46\xf1\x87\xd2=\x8f\x10t\xd0Q\xf1$\xf0\xc6\x8a\xd0\x18\xc0_6\r" 
  "\x1c\xe0\xe4\x2}\x84\xa8\xcb\x8d\x1d~x@\x8c$\xca\x38\x97\x31]<\xe8L\xe\b" 
  "\x1c\xc4\x80\x81\xe4\xd4\xa1\x3xC\xa0\xf9\xc3\x1ej\n\xa1\xe6\x39\a\x81s" 
  "\xcc\x1c\x38,\xe0\xca$\t4\x3\a \xd9\x1@\x0\x99\x14r\xd9\xcd\xa0\xbc\x5" 
  "\x1\xf\xe\x11\xe\n@\x9f~\xfa\xa4\x3Z\x8a\xe\xaa\x80\"\xbeM3\xd3L\x91." 
  "\xea\x65(p\xb4\x99\xe9\xa7\xa0\x6\xc1h\xa8\xa4\x96*\xc8\xa6\xa6\xa6\xaaj" 
  "\x15\xa8\xf6\xd0G\x9c@\xbc*F\x8a\x66\f\xd0\x1f\x85x\xe8\xd1\x84\xac\xfb" 
  "\xdcz[\xae\x9e\xba\xd6*!\xb8\xe4Q\xec\x34\x6\x4\xf0\xc9\x2\x18\xa5\xa2" 
  "\xc0\x2\xca\x2\xbaUj\xf\xfe(r@\xb5G\x19\xf0l\x0\xe6\x19Pmj\xd0\xce\x93Z" 
  "\xb4\x42\bj\x94)\x99 \xf1\x87\'\xd2\x98\x9b\xac*\xe6\xe\x1+\x10\xa3\xc2w" 
  "D\xa1>\x4\xa0\xf\x88\xb6\xe8\xbbX\x0o\x10 \v^\xb7\x15\xe5/\x85\xa2\x39" 
  "\xf0\xdd\x31\x80\xf2\xe0\x80\xa3\xcaL\x84\x4(\xbc=\f\xa6\x1c\x12\xdf{D" 
  "\xbd\xbf\r\x81o\xf\a\xcf\aJ\xc8g2\xd0\x80&\x14w",
  (unsigned char *) "w\xc9\xc1\xe9\xe4P\x91zD \xa0\':7T\n\xc4\x36\x1d\xdf" 
  "\x36s\xcd<\x1b\x81s\x11\xd9\x15\x33\x16#c\xc5#\xee\x43\x11\xe1!4J\x94]t" 
  "\xcd\x12:M\xbb\xa8\xcd\f 0\x0\x61\xbbL\xb8\xc6+\x3 \x17\x0*F@\xb9\xc9" 
  "\x1e>m\xd4\xd1U,M\xd7\x90\xb6\x46\xc1\xc4\x89\xd8w\x90-\x4\x44\x94L\x84" 
  "\xf\xdbK7\xac\xe9\xf\xe5\xe0\xe1\x0\xcaw\r\x4XW}W\x83\xb2!\x1f\nA\xb2\x2" 
  "\xe3\x90,\xd6\r\xf\xdcJp\xe\xdc\xb6r\x8d\x3\x1\x38Z\b+\x9c\x1b\xf0\xc7" 
  "\x9f\xfe@\x8cu\x87[t\x9d\x96rk\xa0\x1f\x31\xadl\xd9\x14\xfe\xf7\xf\xafq" 
  "\xa7\x14k\tX\xc6\xb8\xec\x62\x31[\xa9L\x98n\xad\"`So\xf2\x87\xd0GYh\xd7" 
  "\xe\a\x1bR\x0\'\x5\x38\xb0\x80xE\xec\xbc\xde!E\xa9\xd6\xda{\xd2\xfQ\xfb" 
  "\xa5\xa6\x64\x83\xbb\xa8\xc3N\x9e\x98*\xbc\x88\?\x1a\xbf;0\xc0\n\xe$[" 
  "\xc2\xbe>\x2\xef\xb2I\xe6\xd0i\x1d<\xeUCw\x83\x87\x38\xf4q\xe9\xff\xf5" 
  "\x80\xce\xbcZ\xd3\x9c\xea\xb0\xa6\x38\xc1\xd9\xc5\x0}\xd0\x9c\xf4L\xca~ " 
  "\x1bVYn\xf0\x86\xc7\xdc\xe7\x6\xe\x98\xa0\x9f(\xe3\x80\xec\xf1 d]\xe9" 
  "\x97>\x8c\xa1\x1f\x97\x89\xc6|\xf7\x9b\xf~RQ\x8e\xcd\xf8\xf\x80\xbd\xbb" 
  "\x83h\x98\xf2\x1f:\x94GA\xe7\xb9\xce&f\xb8\x83\xf8\xe9\xe0\x82\xd5\xa8" 
  "\x8f\x6\x3\x46+\xf6\r\xeb!\x9e\x31\x80L\xb2\x44\xa2\x1e\x39\xaf@I\\\xa2" 
  "\x65\x94\x35\xc0mu\vnVT\x4\x4L!\xf\b\xd0\x63\x8b\xdaj\xfeJ\x0\xd8\x6\xae" 
  "\xca)\x2\x1fHd\xd9\x3\xc6\xb8@\x1dx\xb0~Ez\x3\x95rt\x8c\x13\xc5\x83\x89" 
  "\x34Z\xcb\xfj\xc7\x14\x1f\x31\x62Go`@\x14\xb7\xf4\xc1#RH\b\a\t\xd6\xaa" 
  "\x8eP\x92\xe5(\xefL{\nB#{`\xb3\x39\x81\xe9\x92\xf4\x32\xe4\"\x83\xf1\x46" 
  "\xe1H\xa1\x93}\xd0\x2\xc7\x36\xa9\x86\x6\xa8i",
  (unsigned char *) "Rd\xfc\x64\x9b\x1cu\x85Q\x92\x12\r\bP$\x15\x62\x89\x6W" 
  "\xbe\xf2\x96\xa0\xea\x13\x1d\xec\xd0\x46,\xf0\n\n\xbf\x44\x42\x30)\x94\n" 
  "Y\xe2\x92rG\x1c\xd3\x31P\xa8\x85u\x1d\x8b\x1c\xeaz\xe6&\xe4%M\xac\x88" 
  "\xa4\x88\xa3@\x4+\xf4\xb6\x31\tv\'9b\xa0\xd8\x35\x9e\x16\x84\x42\x91\x13" 
  "\x32\xed\x9a\x8f\x31\xc7\xb0\nE\xe4\xc6\x41\?P\xc0\xc2\xe4\a\x86\x9fU" 
  "\xec\x9crz\x14>\xd9\xb3\x89Kt2\r\xc8\xa0\x90\xaf\xf6r\xc4k\xa5\x12iuC" 
  "\xa8\x44~\xf8\x12\xa3\xf1\xeeh\nI\xc8\xdd\x8a\xe3\xb6\x87LT\xa1\x13y\xd9" 
  "\xfe\x45xX4\x9a\xacm\x12\r\x95\xc7\x43\xff\x80\x1a\x8b\xd9\nQ!\xe5\x10M0" 
  "\xaa\x1f\xc9\xdc\x46[\x87\x61HK\xf0w\x12\x8a`\xf4q\xc2*\xe7\x16\x1\xe6" 
  "\xa7\xc1\x1d`u\xf6#\x98P\xad\x32\x14\xd3\xd5o|=\xe5\x8aWjA\x12\xc8\x4" 
  "\xeezwy*e6\x97\xad\xaa:&\xaa\x35\x1\xaa}0h\x94\xcd\x14\xa5tk\xd8\x3\xd3" 
  "\x80\x8a\xbfJ*aTq0\xc7\xf6.\xb3V\xc6\xa1\x13\xa9\xa9\x39L\x2\x17\x64\x15" 
  "\xdb\x61\x46\x33\xd3\x43\xf]\x7f#\xb3[\xccn|m\xcd\x1c> 5\x80\xc1\xda\xc2" 
  "z\x8b\xda\x85\x1c\x2\x8b\x3\xe0\x91\x61X1\x4\x80\x88\x1ax\x88s\xeeu.\b" 
  "\xacIf\xafs\x9c\x1d$\xc7\x83{\xdd\xec^\xfdg\x8d\x99\xdc\x89\x1a{\xa5\xec" 
  "\x31&\xd2\xa4\xd5\x9al*\x6\x84\xc5L\xc9\x37\v\b\x12\x34\x9e\xbc\xa8\x5" 
  "\x10Qd\xa1\x81\x86\xf6\x86\xe7\xc9\xe1^\xed\xd3\xdb\x97\xb6\xa7(\r\xd2" 
  "\xa1\x82\x94\xcb\x1a\xffY\x86(\x97\x42\xaa/\xc2v\xeb\xb9\xfd\x19\xe5\xfN" 
  "A\x10}l\xb3[\f\xda\xd6\t\xafQ\xc0\'f\xd2\x0\xb8\xf8\xd1\x89LS\xd1\x95" 
  "\x66\xc4\xde\x39\xf2\xf\x90\x32\xd2\x12 \xd1;\xa6\x97\xf8\xe9\x1d\x9e" 
  "\xd0\x44|\x9b\b\xdf\xf5\xee\x17Kyl\x8f\n\xd5\v`\xf6\xd2w,n\xf8L,\b\x90" 
  "\x1f\xe\xd1\xb1IO\x82",
  (unsigned char *) "\xcay\x8f\xd7\xca\x61\xd1r&\xe0\x39H/}\xf0\xa6 \xc0" 
  "\xe9\t\xeb$FQ\xfe\xc9\xb7\x43\xda\x82M\x90\xac\xd3\x9d\b\x90\xa7i\xf6o" 
  "\xc3\xdd<\xe6(L:\xd0/\x1c\x8a\x82<\xfc\x82-e<\x5j\xf8\x1\r\x0<\xc3\x8eyL" 
  "d>i\xb2\xc8H&\xc5\x90\x93\xcc\x64\x30,\xb9\xc9P\xce\xc2\x93\xa3Le\a\xd5" 
  "\xe0\xcaX\xce\xb2\x96\xb7\xcc\xe5.\xd3 \x4\x0;",
  NULL } ; /* --- end-of-image7[] --- */
/* ---
 * image8[] contains a 1896-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (8) latex ran but failed:\\check your input expression.\\
 * See mathtex.html\#message8}
 * --------------------------------------------------------- */
#define	IMAGETYPE8 1			/* 1=gif, 2=png */
#define	IMAGESIZE8 1896			/* #bytes in image8[] */
static	unsigned char *image8[] = {
  (unsigned char *) "GIF89a\xc6\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x16\x16\xff\x1\x1\xff==\xff\x3\x3" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xc6\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcf)`\xdfx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f:\x11r\xc9" 
  "l:\x9f\xd0(O)\xadZ\xaf\xd8,\x90\xaa\xedz\xbf`!7L.\x9b\xaf\x63\xde\x80" 
  "\xb0\x43<z\bE\xe1,\x8c\xcf\x9fr\x9f\xfd\xb7\xa7\x3\xd2:\x5\x6\x36\b\x4\n" 
  "\fw\x3\v<\x5\t\x83=wt\x8d\x8f\x41\x91\x39\x8d\n\x1;\to\x93\?\x9e~\x80" 
  "\x39\a\b6\r7\a7\v\x3<\x6\x94;\xafg\xae\x43\xb1\x37\xb3\x96\x37\x4\xac\x0" 
  "\xb3\?\xbdt\xa2\x37\x3\t7\xe\xa5\x0\xa9\x36\x3\xa7\xb0\xb5\x37\xf\xce" 
  "\x64\xbf\?\xd0\xad\xd1\x39\xd3\xd6~\x7f\x9a=\xbf\r\x1\f\xf\f8\xdd:\xbd\f" 
  "\x4\x4\x8f\f\xe\a\x6\n\x0\f\v\x4\v\x5\f\t\xc4\x4\a\x8b\x39\x3\x10\xf4\x2" 
  "\xccI\xb7\xce\x6\x81\x0\xf4\x14\x1c\xc0\xc5+\x81\xbaU\x0\xfe\r\x92(\xcf" 
  "\x1d\xbc\x1c\n\xdf\xc9S\xf7H\x1\x84G\xe8\xe8\xd9\x8b\xb8\xe0\x90#\x1b" 
  "\xd9\xfe\xbe\x4\xb3q \xde\r\b\x1 X:\xb0\v\xdb\xa3\x4\xac\x16\xbc\xe1\xf5" 
  "\x88\x80\x3\x65\xa9\xfe\xc5!\a\v\x2\x80\a\xa5p\x2\xd0\x89\x32YJ\x3\xfd\n" 
  "\x4(\xd5\xabj\xb4^J\x99\xf2\x44\x39\xc8\'P\x4SY\x82\xbc\x96\x65%2\x97\b" 
  "\x1a h$\x10\x95K\x9b\x37\x14\x10h0\xd6\x46\x82\x96\n2\x19\x84\xc0\x46" 
  "\x1b\xe\xb9t\xb9\n\x86\xcb\xf2\x8d\xd5\xc1\xe7(\x1\xae\xbb\xf5n\xdeL",
  (unsigned char *) "\xf\x92!#\xeb\xc5lK\x1b\xf\xfa\x2\x38\xc9\xf2-\xe\xac" 
  "\xf1\xe+\xac\x85\xe0\x0\xb3\x66\x38\x12\x84\x66\xfc\x94\x92\xc6\xc3[=\xf" 
  "V\xbd\xb5\xf6,\x8d\xb6$\xe3\x6\x66n\xc7\x2\xa2\x99m\x11\x5`\f\xb5\x42S" 
  "\xb3\x92\x13\x30\x8a\x19\x0\x82\x41\rv&\x8e\x9b\x8c\xee \xd8\x9f\xfb\x81" 
  "\x9d\xd3+\xf0\xd6Z\xb3\x8e\x3\xb0n\xbb+\xf3\xa3\x5~\x8a\x35\xa8\x39\x8c" 
  "\xd9z\xaa\xe2)\xe8\xe7\xfc\xfc_\b\x10\x14\x94\x1ep\b \x80\x2\x10\x4g@t" 
  "\xbf\xb5\xb3\xc8\x41#\xdd\xfe\a\x1Q\xfb\xf5W\x12~yA\x88\xcd\x3\n,\xd3W#" 
  "\xfc%\x90\xdf\x7f\x1\xb6\a\x80G\v6\xc8\x0@ F\xb8\xe1\x80\xf\xfc&OI>]\x96" 
  "\x8f\x19\x66!\x83\x43\x1y\xdc\xc0\xc0pz\xb4\x31\x63\x13\xc7\x18\xc1P)=" 
  "\x12\x2\x44\x90\x9f\xe4\x0\xe4\x36\xdc\xfc@\x0\x8e\x46\x12\x83\xe4\x93PF" 
  "\x11#\x0\xba\xf0\x80T\x94Xfy\xc4\x94\xff\xb5\x41\xa4\x96`\x86\x99\x44ob" 
  "\x96i\xe6\x12\\\x9e\xa9\xe6\x9a\x37\xa4\xe9\\\x8d\x43\xf4\xc1\xe6\x9ch" 
  "\x90\xe9\x3(C\xe0\x19\x6\'Q0\x84$\x9fV\xb8Y\x1b\x11)yQ%\x14\x94\x99qh" 
  "\x15\x82\x16\xeaK\xa2\x66VC\'\x9av\xe2\x30\fT\xe4@e\xc8\x42\x36\xccS\xcf" 
  "\x1c\x97\xaa\x38\xcb>\xb1\xe0\xc3L\x2\r\x14\xb0\xce!lP\xe4*@\aY\xe2QW\bm" 
  ":\x87O\x9c\x18\xa0\xd4\xab\x83\xb4\xf3\x8el+~\x8a\x8f>\xfc\xe0\n\xcd\xae" 
  "\xb0\xb6\xe5\xa9=\xcf\x1\xe6\x1c<s}\xf8\x91\x41\xf0\xfe\xa4\x43\x65\xad" 
  "\n\xf9\xd9\xc3JR\xcd\xf1\x0\x31\x6\x38\xd5\x95z\x3,\xd4\xd6\xb7[\x95\xb4" 
  "\x3\x3\xcc\x18\x10\x87z\xe3\xad\x36\x98\x1\x46]\xf9\x19H\xe2\xa2\x14UX" 
  "\xb0\x15\xeaUDAA0\x94\xbe\x36HEU\xbd\x85\x90\xfbN_\x86\x31,\x98\x2\xf0" 
  "\x36\x10Z\xbe\x43\xac\x14\x19\x61\xb3\x38\x96W\x0\x17gwY\x1b\xc5\xbd\x91" 
  "\x0}\xba\x96\x87\x18\xc6\xac\xb9",
  (unsigned char *) "\x66X\xca\x9b\xe0\xa5\x17\x95|\xd9\xa2\xf2\xa0\x1ag2" 
  "\x80;W\xde|\x80\xbd\x19\x93\f.cbT\xda\x14\xca\x93}&\x19J\xaa\t\xcc\xc3" 
  "\x2\x6\x30P\n\?\xb9\x99<(\xd1R\x17\xdd\xef \xb2\xedvCi\xa7\xfd\xf2\x9ak" 
  "\xaf\x14pO\x3\xa9\x88\xcdn\xbeP\xf\x8d]\x10\xdc\x86\x45\xa5\xc9\xcb=c" 
  "\xb0\x41[=p\xda%\xe\xb0s^\x3\x99>\xe2\x9d\xa3W\x13\xfc_[\xdd\xd5\x15K" 
  "\xdc\xcd=7\xdeNP\x15L8%\x88\x1f\x65\xc0\x1d\x46Mn\x3s\xb3\x8cx\x3\xdfR" 
  "\xab\xb3\x85\xd0\xfe\x9d\xeel\x0\x7f\x10\x96\xc8\v\x81\xe4\x30 :\xe9x\x5" 
  "\x90\x80\x9fJ\xa1\x14]/\x18*\xa0\xa1\x89LJ\x9b_\x89\xa6\x87k\x88\x43\x5" 
  "\xe3\x64\xfb\x86\x0\x6\x87\r\xea\x6^k\x8f\xef\xb6\xb3\x1\xe2p(\xfe\x6" 
  "\xd5\x1a\x86\xad\x42\xc0\x1b\xbd\xcf\x8eu\xe9\x12\xbe\xf8\xc3\x94_\xee" 
  "\x80K\xf8>Hw\xc3\x8f\xce=q\x8b\xeG\xe2@~\x97\xde\f\xa2\xed\x8e\xe9\xf7" 
  "\xd8>#P\bz\x5\'\xfc\x95\xe1h\x15\xff\x3\x93\xfe\xac\xb0\x6`uA\x1\xae\x30" 
  "\xa0\x14\x10x\x91\x35\rpR\x10\x44\xd2\x3#HA\x18\x81\xae`\x15\x82\x1f\x19" 
  "\xe4\xe4\x4\xe\x1a\xc1\x83\xce\x39\xc6\xfb\xd4\x64\x96\x1b\xfd\'\\a\xb8" 
  "\x83\x9e\xcew\x84\x15\x16L\b.\x1c\x89\xe7\xb2T\x88\x43\xcc\xcf\x6\xdc" 
  "\x92Li\xc2@\x89\x42\x41\n5\xe7\xa0\x45-\x9c\xa4\x16-\x9d\xe6h;X\t\xc4z" 
  "\xf4\x43\'Hjj\x98i\"ap\xf0\x44 dC\x10\xa6\x0Sqd\xe4\x3\xcb\xe4\xcd\x33" 
  "\xcb\x1a\xfe\x88Hp\xe1\x93\x84\xd0$/\x9c\xdaHA*\xf2+^\x98q \x16\x89G\x18" 
  "\x87\x45\xa5\xb4\xd9\xe2\x8dl\x84\x96\x3\xcc\xc8\x9fl\x9d\xec(\xac\x18" 
  "\x80t\xca\xb8\xa9>\xa6\x31\x8c\xcd\x8aV\"\x99\x41\x10J\xcc\x3S\xc4\b\xe3" 
  "x\xc2\x31\x8e\xef]\x90\x17\x30\t\x0\x1b\xfeU.N\"\x91\x17N\xa1XV\x18\xd7" 
  "\x43\x8a\xf5\xc2",
  (unsigned char *) "\x93\x11\x11\xd8!\xce\x61\xcaR\xe\xcd\x64\x82p\xc5;" 
  "\xc2\xe5\n|\xbdrT\n3\x80\xc3t\xd9\x9c\xcd\xe4\x64\'aQ\x11*\x1\x0\x13\x99" 
  "X2\bn\x98J\xcd\\\xe7\x32;\x5\xce\x6\x8b\x41\xcc\x33\x97\xb9\x17\xf\xcd\v" 
  "h\xcf\x9c\x46Z\xec\x42\xb5\x8c\x35Sg9\xc3Y\x8f\xa2\xf9\a\x94\x88\xac\x99" 
  "iYK\x2\xda\xb2-\xd0\xe5\x5\a\xf9\xd1\x9a\xd6\xa6#5\xda\x88\x46j\xe1\x99" 
  "\xa7sL\x3\xc4{fs\x10qP\x0\x34\xf2\xa2\x9aw\xe2s\x10Z3\x1b\xd9\xfe\x33" 
  "\xb6\x64\xd8\xf3\x11\xf4X\xa3\xd6\x8c\xb7\x19\xb2(\xf1\x15\x2\x8b\\\xeb" 
  "\x66\xce\x63\xbek>\xac:\xc9\xb9\xce\x41y\xa1\xd1g-\x8e=\x1e\xfd\xceH\xb7" 
  "\x12P\xbc\xe8\xe4\x31)\x1d\x15G-GL^P\xee\x43 \xedU\xe\x34J\xd1\xa6u\xd1" 
  "\x9d\x8e\xc8\v\xe7N\x97\xa2L\xa1\xe#\a\xd8\x1d\xf7\xf2#\"\xff\x14\xcf" 
  "\x10K\x8d\xc7S\x89Z\xa0=*\xaf\x11\xc4\xe0\x9d\x84\x9e\xaa\x10\xa5z\xd5" 
  "\x44oa\xc6\xddp\xfa\xd5\xec\x15uz\xd7s#\xf5\xf6\xc9\x9f\x11-\x82l\a\xe0" 
  "\aU\x8e\xaa\xae\xf9\x1c\x93\a\b(E^\x88\x84\x8b\x1b\xf2\x41G\x7f\x65!\x8f" 
  "\x8e \xc8,\xb6PH\xf6K\x9f\xfbp\xb0\x80\x82\x12\x0U\x82\xc5\xa0_\x93TA(= " 
  "\x90\x1d\xfd\x2=rA\x1f$L\xb0\xb2Up\t\x9c\xc8\xf0\x18\x83\x32\xe1\xb3\xa0" 
  "M-\x16P\xab\xda\xd6J\xe9\x92\xae\x8d\xad\x16X+\xdb\xda\x1a\x81\xb6\xb6" 
  "\xcd-\xdbh\xc0\xdb\xde\xfa\xf6\xb7\xc0\r\xaepU\x10\x2\x0;",
  NULL } ; /* --- end-of-image8[] --- */
/* ---
 * image9[] contains a 2215-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (9) Can't run dvipng program:\\check -DDVIPNG=$\backslash$
 * "path$\backslash$", etc.\\See mathtex.html\#message9}
 * --------------------------------------------------------- */
#define	IMAGETYPE9 1			/* 1=gif, 2=png */
#define	IMAGESIZE9 2215			/* #bytes in image9[] */
static	unsigned char *image9[] = {
  (unsigned char *) "GIF89a\xe1\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff==\xff\x1\x1\xff\x3\x3\xff\x16\x16" 
  "\xff[[\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4\x1" 
  "\x0\x0\x0\x0,\x0\x0\x0\x0\xe1\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcf\x34\f\xdcx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8" 
  "\xa4P\xa4l:\x9f\xd0\xa8t*eR\xaf\xd8\xacv\xab\xb5r\xbf\xe0\xb0\xf8\xeb" 
  "\x1d\x9b\xcf\xe8\xf4\xaf\xdc\x1b\x10x\x88\x86\xb0\xa0\x18\xdc\n\xc5\x2" 
  "\xc2\x8cP\xe0\xd5\x80U\x1@\x5\x6\x37q\n\r{\x0\x3\v\?\x3\t\r\n\x4\v\v\x86" 
  "\x44\a\t8\x7f\\\x5\t\x97<\x91\x81\xa3K\x83\?\a{\b\x1x\b\a8\vv<\x3\xf\x8b" 
  "\x37\x9fy\f8\xa0\\\x6\xbb:\x4\xb1\xa4\xc2<l:\x90\x37\r\xae\x37\a\xb1\x3" 
  "\x10=\a\xb9\x39\x3\xbe\x41\n\xc8\xd5Y\xbd\xc3\xdc\x45\xc5\x39\xdb\x0\x6" 
  "\xca\x0\a\xa0\xa6:\x5\x1\xb5\x38\xd7\f\x4\x4\x97\x4\x1\v\x4\n\a\x7f\n{\f" 
  "\xe\xe6\xd7\xd3\xf\xea\xad\x9a\x65\x88 \x80y\xf5\xeeq\xc2\xd1H\x1\x83[\f" 
  "\xe<\x3\x90\x0\x42\x84\a\x86\b8\x88\x64 \x81\x1d\x84\xf6\xf0\xdd``i\xc1" 
  "\xc3_\x1b\xfe\x1bt\xb4\x33K \x9ex\xe\xdf\x0 i\xc0\xa4\xc7\x80\xf3\xf0" 
  "\xbc\x8bwCcBf\n\x14\xde\b\xa7\xe4\x1b\x8e\x3\xff\xd4-r\x0\x8a\xd9\xe\x5" 
  "\xe8vx\x4\xb0@\x8e\x38\x65\x44ue\x13\xf7\x0\x80\"q\x97\xc2\x8d\x1b\xeaK" 
  "\xd5\"sC\x1d\x89\xdb#V\xad\xd2\xab\x64o\xac\xa3*MG\xcd;s\rtU\xa4\xc0\x1" 
  "\xe\b\xd7\xe6\x9a\x1c\xbaw\xcf\xd4\xaa\x43\xb1\x62\r\xbb\x95\x88\xd1\x65",
  (unsigned char *) "\xff\xe.\b\x8a\x16\xf2\x8e\xb7\xe9nL\x82\xc0\x38\xae" 
  "\xdd\xadY\xc5v\x6\xab#\xd9\xd1Ko\xa5\x89>*g5\x0S\x6\xac~fM\xda\x96Zq\x9a" 
  "`[\xcd\n`\xf3h\xd7P\x1e\x97\x8b\x9c\xe3\x41\x30\xa4<\xa2\xe9\x88\x43\xf1" 
  "\x9ak\xde\xa4\x89{\xf6\xfc\xdc\xd7\xd8\x65\xa0 0`\xf0\a8Z\xd7\xf5x\xf2 " 
  "\xfa\xbd\xe9\xed\xb1\xe1\x41\x65M\xe0\xfc\xf7\xe8\xe0Qw\f\x6\xd0\nO\x1r" 
  "\x0\x1c\xb0\x63H\v\\\x1f\x65\x9c\x19\x2\x9cV\xe2\xec\x10\xda%\x9cQ\xfe" 
  "\xe7K\x1~a\xc7\x90\x3u\xb5\x85\x17\x1e\xae\xd5\xd5\xc3]\x0\xa8\x43!(\ftu" 
  "\x83v3\x19\b\xca=\x1fnS]O2\x15\x15\xdf/\xb7\xb9\x82\x0\x4\xb5 \xe0\xa1," 
  "\x91L\x2\v}@u8\xd9\x3\xf\x4\xc5\xa3t\x5<\xd0@\x8a\x9a\xf1X\x97\'\x3(\x90" 
  "@\x8f\n\xfc\xd8\x64\x8f:\x90\x34I\?\x91!\xd7\xdb\x8fW\xd9\x93\xc0\x1bO" 
  "\xfa\b%\x4\a\x84\xb9\xc0~Y*\xc9\xa5\x91\xba@\xa0\x12\x82\x61\x1e\x30\xe6" 
  "\x93\xd2\xb4\x92\xa4\x8e\xf7\x30\xe9$\x96\th\xd2\x84p\xe5\xe0\xd0G0#Y" 
  "\xc8\x3\x1d\x80\xd2\x87\x4\x99>\xa4\x62\x84\xa2\x39 J\xda\x42<,\xc0\xde$" 
  "\x15\x89\x98\x61\x10\x9cH\x1a\x14\x1\x95\xc2q\x6\x9f\x4\b\xda\xa8\x9e" 
  "\xdd\x84\x1]\xa4)Rb\xa9\x11\xf5\xe0\xa0\xaa\x30|\x1eT(\xe_\x95\n\x86\x2" 
  "\xbdH\xd7\x43P\xbc>\x95\xeb\x11\xbc\x6\xc5M\xac\x97\xee\x80\x80\xa3\xb6&" 
  "\xab\xec\x13\xc4.\xeb\xec\xb3]\xac\b\xed\xb4\xd4\xfe\x62\xd1,}~,\x9am" 
  "\xb5\x84\xd4qG\x10\x3\xc8v\x88}\xc8\n\xd1\a\xa4\xe1.G.\x18\xd7z\xd2X\xf" 
  "\xee\xe\x81k\x0\x9f,\xe0\xe6\"\xf3\xd6{\xefL\xf\x4\x30\xe2\x3\x10\xd0" 
  "\xb1@\x0\x80\xcd\x1b`\x82\xbd\x35\xe0\xef\x1d\x3\xdf\x6\x89$\x94X\"\x4" 
  "\xa9\x43\r\x92\t\x12\x7f\xc4\xab\x3\xc5\xe2X\xcc\xf1\x1cG\\[[\x11\xa7" 
  "\xfa\x10@dM\xd6",
  (unsigned char *) "rr;\xfdi\bN\xe+\xcb\x15\xd9-7\f\x1c\x19(\xb3\xb0\x43" 
  "\x33\x10\r\x0\xca\\\x1\xa2\n\xa1^5=7*\a\xd0G\xbc\xdb\x83\xc8%\xff\xd0" 
  "\x34\x31\xc4!\xfcZ\xd4\x97$p[\x1\x44\xc6<\xb5.\xe4\x18\x0\xd5\"M\tZ\x88" 
  "\xb9\x13\xb5\xa3\xd9\x11*\x11\xb8\\\xd9g\xf7\x66\x44\xda\x46\b\aIM\xb9" 
  "\xd4\x14\xd2\x1f$Q\x82\xc7\xdc\x83mC@ek\x10\xa7\x11\xeZ\x1f\xd4\xe0<\xb4" 
  "\xea\xa0\xb5\xd6\a\xa4h\x88\xa4\x43\xe1\x45\xa6\xae=\x8c\xb9\xc9\x1e\xc1" 
  "h\xc4\xd1T3\xc1s\t\?\xfe\xfe\x88\xf3S\xa6\xb5\xe8\xc1H\x10y/\x0t\?^3Ro" 
  "\xd0\x84K;\xa1W\x9a\\\xe7w\x83\x3\xe0\xb3\n\xed\xa4M\xb6\x4qP\x11\xe<:" 
  "\x10\xd2\'\xee\xd6rI\xe2\x10q\x86\xc8\xd8\x9a\x66\xb2g\xd8\xcb\xf4\xd4" 
  "\xff\x11*\x10\x18\xbeu\xd8n\xea-\xe6*\xec\?\f\xce\x88+\xe1\xb8\xdc\xc0" 
  "\xc7\x30Go\x1a\x38\x9d%\x80TP\x1\xac\xaf\x8b\xbd\x94\')\xac\xcc\x39\xf4%" 
  "|\xfe\rr5\x13\xa4\x8b\xa3\\\x81\x18\x11\x0jH\xae\x1d\xe3\x0\xcc\x10\xd8" 
  "\x36\x9e\xa6X\xc5\x37\xd3\x19\x10\x3\'\xf6\xbe\xe0\x85\x43~@x\xccu\xd4" 
  "\xb6\r\xc0\xc1\x5\x1c\xec\xe9O\x94\xa6\xb7\xbfW\x9c\x83\x38\x12\xc3K\xba" 
  "\x14\x17\x99\xc2\xbd\f\x19\x1\x39\x8a\xa0\xd0\xd2\x87`\x5\xab\x16\x6\x80" 
  "\xd4l\x1c\xc4\x9e\xdal\xa3=\xd3\x11\x87\xe\x81\xe0\xc1\xe8l0\x83\xd1\xc3" 
  "\xcc\x1bVC\x80\x19\x35@\x89\xa4i\xc0\x4\xa1\xc6\x10T\x94p|\xec\x80\x0" 
  "\x94XxE\xbb\xe4 L\xf\x62\xfe\aF\xb0\x65\xc3^m\xe2\x36\xe3q\xcb*H\x4\x80" 
  "\x0\x91\x46@\xef\xc9\x10\x1aw\x0\x8c_8\xf1\x8dP\x84\a1\xa2\x37\x93\x3" 
  "\xa8$Iw\x82\x92\x1\xd4\x34\x98\x88\xfc\xb1I\xef\xa3\xd7\x10\x35\x33\xb0" 
  "\x0\xd5\x4_\x8d\x9c\x9e\xe5\xf8\xa7\x3\x5\flR\x8d\x94\x8e\x92\x2p$\x8a" 
  "\xcd-(\xbd\x38\x1e\x10\xa6\xc8\x35-\xbd\x41",
  (unsigned char *) "N\xe\x89\x61\x90\x86\xd4\xa5.\xe5\x80\x94\xb6\xc0\xcfP" 
  "\b\x99\x8bU\xbe\xc1\x90\x6\xb0\x43\x9e\xf6\x18\x84rmb9jX\xa4\x14\xe8 @ " 
  "\xbc\xc3\a\xdb\x80\x14\xa2|9\x12\"=\x5^\xc0\xf4S\x10\x44\xc6\xad\x64\xc1" 
  "\xf2iI\x80\x65\x1f\xb2@\xcdj\x96\nF<\xc0U\xeb\xa6\x0NYD\xcb\x9b\xe8<\x4" 
  "\x33\xa7p\xacO\xf1\x31\x9d\xf0\x8cg\xec\xba\x65\aaj\xe1\\R\xc0g\x13\xf4" 
  "\xd9\xa8\x45\xacS\x9ek\xe0\xe3v\xa4\'\xcb-dlg9\xb0\xa7\xf\x34v\x99!0\xf4" 
  "\x15/q\xe6(\x10Q+.<\xe6>~*\xa8\xfe\x16\x86\x36\x9e$\x94Li\xec\x93\xca" 
  "\x87\xfe\x19\x6U\xb0\x42\xa3WxL_p\x18\x6\xb8\x8d\x8cV \xbdP6\\\x1a\x4" 
  "\xde\x8c\xad\x8d\xdd\x90\x9fS,\xca\xc7\x3\x30\x85\x38\xa9\xd3I=T\x87\x92" 
  "\x9f\xd8O$\x9d\x13\xf\xe8Zg7\xa1,\xd5\x1d\x43\x5\xda.\xff\x36\xc7\xa6\"" 
  "\xf5\xa9>\t\xc9Q\xbb\xe3\x8b\xa2\xad\xd0pF\xa5\f\xde\xa2\x8a\x0\xaf\x11" 
  "\xe0\x19\x65\xddL3\xc5\x33\x93\x92\x9c$\xa8\x1b,\xa2\xb5\xde\xa9\x17\x11" 
  "\xbc\x41|\xb9\xc3kAm\xe7=\x8a\xd8\x1\x31#\xb3\xddh\xf4\xca\bZ8\xc4@}\r" 
  "\xac\x62\x14$\xbd^\x98\x63\x1c$\xfc\xa0`\rw\x83\xdc\x19@&\xad\xc1\xac-" 
  "\xfej\x15\xc1\xe4\x42\xaf\x98\x61\n\x19\xdey\b\x85!\xc0}\xbc\xa2W\x5Wt\"" 
  "\xcd\x9c\xf5=\xad\x45-\xfcz\xf2\x0\x89\xfa\x90\xa3\x8c\xbdm\xa3&\xc2\xb1" 
  "\x13\xc9\x16*\x3\xe8\xc7W\x82\xeb\xc7Z@\xf0\x35\x43\x91\xc3o\aA\t\xca" 
  "\xc4\xd4\t*%N\x8f\xfe<(\xd7\x90\xea\xb6\x39\xba\x5\x62v\xe5\xda\x8a)\x2" 
  "\xe7\x87\xd7]M\rU\x12\x94I\xfd\xe3\x44\x1e,\x0\xd0\xc0\x94\xa1\xf5*\xa3" 
  "\x87\xe1H\x8f\x83z`\x9c\xd1\xfa\x0W\xc5\x41@\x13i\xb5_d\xacj5lt\xa3\x89" 
  "\xc2+\xa0\xfez\x85>\x86P\x13\x8ar\xfb\x46\x2\xc7\xa5\x86\xef\xab",
  (unsigned char *) "\x8a\x19Od`\x95\xfc\xa1+9\xbc\x41W\x2\xbc\rAU\xb8>\x19" 
  "\x42)\x15T\xfa\x89\xa0\x80H\x1c\xb4\x44q\x3\xe6\xd3\x8e\x3\xd8\xe9\xc5" 
  "\xfa\xc8\x91*\x85\x64\x8f@^\xc3\x96*6\t\?\x1c\x81\x10Oh\xa2\x95X\xca\x10" 
  "\x8d\xeb\xe4\xa5\"\xbb\xf2\x43H\xce\x9f\x8b\x8d\x8c\xa5\x41\xae\x98\x1" 
  "\x35qCk`A\x0\x39\xa0RGml\x93\xe5\x9c<\x18\x17\x95\x93\xa7\x89\xda\x43P" 
  "\xf6\x3)\x85\xfe`\x99\xbdL(\x14H:\r\xab\xc0\x92\x10\x87\x30T\x9c\xf7\xc3" 
  "\xeMQ\xaal\x9c\xf8\x93\x18\xba\tP*xU\x94_hUO\xe6\x98\x6>\xf7Y\n\xff\xd8" 
  "\x96\x19l,\b+\xd2\x1e\xfa\xd1\xcf\x32\x34\xa4\'=\nIS\xfa\xd2h\xb0\x34" 
  "\xa6\x37\x1d\x6Ms\xfa\xd3\xd1\xaa\x81\xa8GM\xeaR\x9b\xfa\xd4\xa8\x46u\b" 
  "\x0\x0;",
  NULL } ; /* --- end-of-image9[] --- */
/* ---
 * image10[] contains a 1465-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (10) dvipng ran but failed:\\See mathtex.html\#message10}
 * ---------------------------------------------------------- */
#define	IMAGETYPE10 1			/* 1=gif, 2=png */
#define	IMAGESIZE10 1465		/* #bytes in image10[] */
static	unsigned char *image10[] = {
  (unsigned char *) "GIF89a\xcd\x0(\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0\xff" 
  "\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb\xdb" 
  "\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff==\xff\x1\x1\xff\x16\x16\xff[[" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4\x1\x0\x0" 
  "\x0\x0,\x0\x0\x0\x0\xcd\x0(\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa\xael\xeb" 
  "\xbep,\xcf\x30`\xdfx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\x41\x11r\xc9l:" 
  "\x9f\xd0\xe8P)\xadZ\xaf\xd8\xec\x91\xaa\xedz\xbf\xe0%7L.\x9b\xc1\x63\xde" 
  "\x80 D8\x82\bE\xe1\xcc\x8c\xcf\x9fr\x9f\xfd\xb7\xcf\xa6u\x5\x6\x37\x81" 
  "\x3\x37n\n\xe\b6\x3\v@\x5\t\x82<\tot=\x8f\x91\x41w\x80\t\n\x1;\x93\x0" 
  "\x97\?\xa2~\x9e>\a\x8a\x0\f\f\r\n7\xa8\x0\b\a7\v\x85\?\x6\x98:\x4\xb6" 
  "\x95<\xb8\x43\xb9\x38\xbf\x9a\x38\xbb\x36\xbf\xb7\xc1U\x7f\x38\x3\t9\a" 
  "\xae\x0\x3\xb3\x36\xd1\x8b\x10@\xc8\xbd\x46\xdb\?\xe\xca\xc7\xe1:\xde" 
  "\xbe\xe3P\xcc\x37\xe5\xd7\x0\x6\xd5\x0\a\x98\xa6:\x8c\n\f\x90\xaa\a\xd9" 
  "\x0\t\x10\x11\r\x82\b<\x98\x64 A!\x2\x1\x16\x10Pp\xe0\xe\x83\x5\x6\x16" 
  "\xdc\xcb\x31\xa0\x81\xc2\x0s\x18\x10 \x10\t\xa1\x42\x86\xc4\x8e%\xd8Xk" 
  "\x1a@\x93\x82\xfe\x18<\x88\'\xed\x6\xc3x\xaa\x36\x46Rp\xb2]\xa4\x87\x4" 
  "\x16\xcc\xa9w/R\xb9\'\xe9\xac\xb5\x14z\xec\x1dLk\xbc\f\x5Hu4\xe2\x31\x45" 
  "\xc8\x9c\x86Z\xda\xae\x1a\x32\xaa\x12w\x18h\x0 \x11\xbf\x42\v(\xb9\x13G" 
  "\xae\xd1T\xa8>\xd3\x9a\xb3\x61\x10@X\xb2\x36\x1\b\\\x84\x8a*<\xb5\xcb" 
  "\xe6\xed`\xf7J\xdaXk\x98\xf8\xdep`4R\x1\xaa\f\xe0n;\xf0&j$S",
  (unsigned char *) "\x6(\xe5(\xa7\x80\x0\x4\xbc\?\x17\x37\xc6<n[\xe5\xcb" 
  "\x8a\x5%\x88\xa6\xa0\x13\xe1W\xe7\x80\xea\xd5!\x18\x9e\x34\x6\x46\x13" 
  "\x13\x9d\\\xf8\x6\x84Uw\x1c\xa3\x8e\xcb[!\xc7\xb5\x37\x38\xf1\xd6=9\xb0 " 
  "\xe2\xbf\x86\xc2\x15\x8e\\\xd0\xd1\xa2\xbbK\xf9\xc8\x8a\x83\x1d\x82\a7" 
  "\x1ehz\x90\nG\x1\xec\x80o\fx {\xb8\xd9\xc3s\x88\x97\a\xe\x80\xa1\x8d\xcb" 
  "\xc7\xf1\n3\x8b\x0#o\xd0q\x95%\xaf\x6\x7fx@\xae\x36\x38\xf0]t\x1bY\x11" 
  "\x94\\f\xa9\xfe\x62@\x0\xf8\xa8\xf2\xc6*\x86\x0\xa8\xc3\x43\x95\xad\xd4" 
  "\x12;4\xb5R\xd5\x42#\xb5\xd7@+\x19\xba\x2\xc1\x1$.\xd0\x9d\r\x19\xca&" 
  "\xcb\x0\xf6X\x14\x62\x88\x93\x39\xa0\xc0\x0\x10\xb0\x11\x8a\x41\n$\xa0" 
  "\x61\x1\r8`\xa3K\x1f\x32\xb0\x62\x8b\v\xbc\xf8\xa1+\x6@\xe0@V\x14\ntM\x2" 
  "\xcf\xe4\xf5\xc3;<\x14\x90\xc7\r\x10\xf6\xa0\xc8\x89\xb1\xac\x15\x92\xe" 
  "\vpRY\?p \xf1\xe5\x96\x39p\xb9\x83\x9a\x96\xa4\xd9\xa5\x16\a\xca\xb5\x1e" 
  "\x10\bD\t\xc5O;(tCN\xdc\xf4\x19\x45\x9cr%\xf5\r\x9bH(\x80\x8br<\x94\xa6" 
  "\xa8\x9f\x8c:\x1h(m\x10\xda\xe8\xa4\x94\xf6\xf0h\xa5\x98\x66\xaa\x9a\xa6" 
  "\x9cv*\xa5\xfV\x16\xf2\xa5\x17}<Q*\x12\xa7\xda\x80@*\x92z\xaa\xc3\x81" 
  "\x10\x6\x42\x65\x17w\x90\x92\xc3\xa8\x8e\x34\b\x88\x10\xb6\xd2\x32G\x81" 
  "\x94\x12\x62\x88\x8c^Y\xba\x9aw\xef\xc8\x12\x6&x\xa6\xe6\x3\x9e\xed\x0" 
  "\xa3L\x94\x10\xfe\xb4z\xc6*\x1aZ\xb3\xe5\xac\x39\x4\xa5\x0w\xea\x80\x1" 
  "\x8e:\xca\x8c{\x4\x9e\xe6\x6QN \xef\x65\xca\xe\x35}\x19{\xca\x3\x6\f\x85" 
  "\x93N\xaa(\x84o1\xf|t\x0\x8b \xd9\xa0\xd1o\xaa\xacTo;\xfe\x66\x64\xb0+" 
  "\xf7\x16p\xcf\x33\x4\x1c\x90\xe0\x31\t\v\xbc\xb0@\xfe\x2\xdc\x10\\\x83" 
  "\x15\x32\x80\x64\x18/\xf4oi\x1b\xe7\x9bS\x1\b\xd4",
  (unsigned char *) "kY,*\xef\x33\x30&\xf\x45\x34Q\xc3\xf1V\x15\xdd\xeqn%" 
  "\x2\x1bsMs@\xcf\xf0\xd2\x6\x1dom\xbd\xc5\x9b\xcd\xfe\xd9\x0\xf4,\x15\xc5" 
  "\x31\'\xd2\xdb\x44m\x95Uj\x5\x82K<\xee\xe0\xe2\xd3\xd4\x64-m\x80\x8d\x8d" 
  "\x81\xcd\x16X\x94`\x95\xd8\xd2\x35\xffu\x97\xbct:\xb0\xd4h\x8a\x32HZ\'" 
  "\xe4p\xe6\x92\x65\xf2\x35\xc7\xd6\xdc\xa6\x10\xd0\xc0\x8f\xc2\xe4\xcd" 
  "\xac\xddG\xc7\xb2\x8f\x9d\xa1\x91\x5wi\x1\x8c\xc7\x98\"\x8e\x17\xdb\x1e" 
  "\xde\x36@\xf6\xc6\xe2t\xcf\xa6\xf6s\xaf\x1e\xeb\xd2P\xfe\xadp\xcey\xdd" 
  "\x89\xf3\x83\xa4Z\xa7\'\xce\x90\x32\xb2\xecS\x1c\xc7\xc9%\x9dt\x1c\x88" 
  "\xd4\x9b\xe3\xa2\xb2\xff\xc2y\x1\xe\x8f\x18J\xef\xd5\x30\x17\x89o\x91" 
  "\x8c>\x1bl\xaf<}\x83\xb7\xb9\x34\x80\x80\xdf\x83\x41\x1f \xe9I\xbb\a@" 
  "\x7f\xbf\xc4\x97\xf8\xd7\x12\xbe\x91\xf2\xf5\x94\x0K\\~\xb9\xab\x45;ia" 
  "\xe1\xae\xb7\xf4]\x19p\aW\xee\xdb\xc0\x95\xf5\xfd\xcd\xc9\xbe\x64\xd6" 
  "\x81\a\x80vl\xef\x90\xa3\xed\xb7\x39\x86\x92\xb2\x92\xa4%\xcd\x89! :R" 
  "\x88\x86\xc4\x8a\x46\xf0\xc8GF\xdaQ\x8f\xd8P@\x89\xa8\xa4\x11\x1ey\xc4" 
  "\x33\"(\x8d\a\x8a,\x81 ,\xcd\x91l\xd3.\x1c P\x84!l\xc7\x0\x19\x10\x91" 
  "\x35\x34\xa6\x16\x4\xf0\xde\xc8\x1ax=\x12I\f*+T\x10\x83n\xf2 \xe5-\xcfs" 
  "\xaaRDi\xb8\x14\x12\\\x95I\a\xd6z\x93\r\x8cH\x84$\xee\xe0\x63%4\xc2\x1d" 
  "\xd0\xa4*%V\x91\x16\x62\"\x0\x99\x96\x38\x8a+\xf5\xcfU\x99r;\x80\xc7$" 
  "\x13\x6=)mb\x9b\x2\xa3\xa6\xa4\xe1\x45\x32(\xaa\x34\x6\x2\xa2\x1a\xe7H" 
  "\xc7\x1f\xd6\xf1\x8ex\xac\x9c\x1c\xf3\xc8GL]\xaa\x8f\x80\xec\x5\r\x6I" 
  "\xc8\x42\x1a\xf2\x90\x88L\xa4\fB\x0\x0;",
  NULL } ; /* --- end-of-image10[] --- */
/* ---
 * image11[] contains a 2134-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (11) Can't run dvips program:\\check -DDVIPS=$\backslash$
 * "path$\backslash$", etc.\\See mathtex.html\#message11}
 * ---------------------------------------------------------- */
#define	IMAGETYPE11 1			/* 1=gif, 2=png */
#define	IMAGESIZE11 2134		/* #bytes in image11[] */
static	unsigned char *image11[] = {
  (unsigned char *) "GIF89a\xd3\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff==\xff\x16\x16\xff\x1\x1" 
  "\xff[[\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4\x1" 
  "\x0\x0\x0\x0,\x0\x0\x0\x0\xd3\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcf\xb4\b\xdcx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8fH\xa4-" 
  "\xc9l:\x9f\xd0\xa8\x34\xb9\x9cZ\xaf\xd8\xac\xf6Y\xddz\xbf\xe0p\xb4+.\x9b" 
  "\xcfh2o@\x18\"\x1c\xc2\x82\x62p+\x14\v\b3BaG\xfb\x7fj:\x5\x6\x38\x83t" 
  "\x85\x6\x87\x0\x3\v\?\x3\t\xe\n\x4\v\v\x84\x44\a\t\x85`\x5\t\x96<\x90" 
  "\x7fg\x81\x39\ay\x0\f\f\r\n8\xa8\xaa\x39\v\x8a:\x3\r\xa6\x37\x9dw\f8\x9e" 
  "^\x6\xbb:\x4\xb1\xa1`\xa3\x37\x8f:\a\xab\xa4\xc9\xc5\xf=\a\xb9\x39\x3" 
  "\xbe\x41\xc9\xe\xd3Y\xbd\xc2\xda\x38\xc4\x0\xd9\xca\xc7\xcb\x37\x1<\x5" 
  "\x1\xb5\x38\xab\f\x4\x4\x96\x4\x1\v\x4\n\a}\ny\f\x10\a\x6\xe2\x8b\r\xf1" 
  "\x1\x5\x66\x11\x12\b\xe0]\xbcy}\xa2-P\xc0\xe0\x16\x83\x3\xcd\x0$x\x10" 
  "\xa1\x1!\x2\x10 \x19H@\a\xc1>\x2\x11q`\xd4\xc8\xb1\xdf\?;\xed\xfe\x18" 
  "\xb6\x39UiA\xc3Y\'O\xb1s\a\xe1\xe0\x81\x1\n\x10\xde\xf8\x6\x88\x9c\xf" 
  "\x64\xe1\x82\x92\n\x6@\x81\xcfOt\x16\xc0\xf1v`\xe7\x34\x9e:\f4\x0\xe0 " 
  "\xcf\xb7\xabM\xbd\xf9\x42p\xee\x86\xbe\x9d\x8d\xbcY\xb5\x64 \xac\x39\x8f" 
  "+\x97\xe6([\xa7\xabT\xaa{ \xe0x\xb0\xaa\xab\xcb\x9dS\xabJL\xba\xd4@V\xbf" 
  "N\x3\x3\xe9\x6\x14\x9c\x61\x1c\x85s\x9c\xddQ\xf$\xd9\xc7",
  (unsigned char *) ";\xa0\xae\xddu\x15\xb2V\x1d\xe\xb2\x2\xf8\n`1\xb4\xca" 
  "\x88\x1d\f\xc8\xa7\x37\xaa\xa7\x3px&\b\xeb-\x93O\x3}}Iz`\x19\x34\x11\xc2" 
  "\xfc\x12{\xcd\xcd\xcf+4\x1co$\xae\xb2-\xf9ro\xa8\xc4-\xeb\xd2\xcc\x19" 
  "\xc0\x3T}lo6P\xa0\x0\x83\a\x9au\x9d&\xc4\xf3\x0k\xc0\xf1\xdai\xcf\x91`xm" 
  "\xe5\x42\xba\xdd=\xbc[\a\x4t8f\xa1\x33\xb0\'+m\xee\xe8\x3\?\xa5l\x89\xb6" 
  "`\xc9\x5\xc8\xe5\x95\'\xa3\xfdv\x95Y\x0Q\xfew\xc3TQ!h\aO\xa9\xcc\x95\xcb" 
  "o\xe3\xdd\x30\xcf\r\xf7]\xa6\xe1\x37\xec\x4\xd1\xcd$\xac\x18\x10\xc0-" 
  "\xa7\x88H\"\x0\b0\xb8\x6$\x92\xc0\x82\xe2M\f\xf9\xa3@\x3\xaa\xcc\xe8\x8a" 
  "\x62\r8\xb0R:4\xfe\xc6\tN\t\xd4HcNC\xea\xc0\xc0\x42\x18%V\x98\x8d\xc3" 
  "\x1d O\x2m\x94\xc5\x86Z\xcb=\xd9\x86\x8d\x6>`M\x7f\at\xb9\xc0\x1e=\xde" 
  "\x80\x0\x8c\xa9,t\x80\x90h\xae\x92@&\x83\x1d\xe5\xcc\x11\xa8\x0!G0\xf0" 
  "\xb9\x41\x44\x1eu\x2\x81\xa7\xey^\x96\xd0\x9e<d\x93\x90\xf\t-P\x9e$\x13" 
  "\xf5\xd0\xa7\x13\xdd\x14\x44\x61\x10\b\xb0\xb9\xcd\x19\xc5\xfdP)\x10\xf1" 
  "\x88\xc4\xda\x30n\xf6\x0\f\x11\xa5MZ\x86\x2\xbd\xf4\xd6\x3\xa9\xfb\x1c" 
  "\x91\xd3\xaa\x66\x34Z\x87\x1b\x8b\x8a*\xeb\xac\x43\xb8J\xeb\xad\xb8\x66" 
  "\x61k\xae\xbc\xf6\xda\xc4\xae(\xf2\x61\xc4\x1e\x83\xf6:ggA\f@%\x8av\xe0" 
  "\xd1\x4\xb1\xb2,\x8b@\xb3\xb1\xfeJ\x1,\'\xd7\xfc\x80\xed\x10\xa4\x8eX" 
  "\x96w\xa6t\xdb\xc9\x2\xe0\x9e\xd2@\x0\x9e\xcc\xf8\x80\x1c\v\x4@W\xb7\xf7" 
  "\xf9wC\x9c\x83\x64\xe7\x83\xa4;\x91\x83\t\x12}l\xab\x3\xbe\xde\xe8\vp" 
  "\x1cG\x0\xab\x61\x11\x97\xf6\x10\xc0\x32\x33\xd6\xb2\x30\x8fy\x98\x33" 
  "\xe8.\xf\x8f\xb3\xcc-\x5h6\xa6\x10\xa2\xe5\x10\x9cuHxR\\\xc7\xc0\xc1\x1" 
  "\xb2\x11\xd9\xf6",
  (unsigned char *) "\x84p\xca>$\xcc\x43\xc5\x18z\x2\xb3s\x96\xacV\xc8\x8e" 
  "\x0\xc0\f3`\n\xbc\xa7\x8b\x10\b\x84\x64\xe1\xd0\x46XS\xa1\xc7\x42\x17" 
  "\x45\x34\xa8,+\xdc\xa9,\xe3\xe6R\x96<\xf4\xcc\x1b\xcf\x2v<R\x96\xd4\x17" 
  "\x35\xe7\xc3\xcc\x18q#N\xd8\x5\x1d\xb5\xac\xce\xcb\x38\xe9\x15\x4\xa9" 
  "\x12\xf1\x65!y(2\x92\x35%\xc9$\xde)\xf9\xa4:\xb5N7\xbc]G\xdc\x41\x1c\x39" 
  "\x89uy\xaf\xa2\xf5zN\x13\n\x10U\x99\x0v\x19\xd9\x3\xd0\xb3\xb8\x3\x8d" 
  "\x13\xb2Pz\xe2\x18%v\xe\x9a\xdf\x0\x41.\xfe\xc1\xe5\xa0s$\f\x89#\x95\bm" 
  "\f\xd2\xcb\xea\xab\xf7\x41\xc0\xa3\x91!\x98GIJ\t\xc6\x94\xed\xaf\x1f\x1y" 
  "S\xdfH\xcc\xb8\xca=dfZ`\t \x93S\x0\xc2\xaf\x45\xae\xa9\x38\xe5\xb4y:\x2" 
  "\xe6\x9cy\xf4o1P,\xda\?\xbc\xd1\x95\x10IGv\xdaR\xb3)\'\x9dsG\x14\xbf*9" 
  "\xdf$\xef\xe1\xd3\xcb\r\x7f\x99\xd7\x8e\xebR\x1e-;0\xb0\xfa\xf3}\xcb,N%" 
  "\x85\x4\xa0\xec\xe\xd8\xd3\x81\xf3p\xa0\x8a=\xac\xea\x80\xf6\xd0\x45\xb1" 
  "\xdc\x37\x1d\xe1l\x88\x10\xe6\xb1\x9d\x37\x16\b\x4\xaf\x19\'~mR\x9c)\xa2" 
  "\x4\x19\x2\xa8\xc8\x1\x8b)\xc8\x65\x1c\xd0\xbd\x97-#r\xe;a)r\xf0\x80\x1b" 
  "\x89n\x19\x33\xb3\xd0.ha@\x4\xe\xb0\xe\x9b\x8a][\xe4`\x9fl\xf8\xf0\x81" 
  "\x8a\xc9\xe1/\x82\xe1\x41\x1c\xa4\x86;!lC\x87\x0\xc8>V\xa0&\x11Lb\x92" 
  "\x37\xb4t\x97\x87X\x3\'\r0\xde\x88(h\xa1v\xdd\xa7,\xe1\xf2\xfe\xe2\xea" 
  "\xfc\x6=\x1\xb6\xebP^\xe4\x87\x2:\x91\x93\xe7\x14\xa1\x84UZc\x1b\xc6\x84" 
  "\x93\x32u&G\xf2\x18\x92\x14\xe7\xf2\x83\xe2\x45\x86\x8a\xb9(\x0\x1eO\xf1" 
  "\x44:\xac\xe9\x65M\xf4\x18\xc1\x14\xe9\a.B*\xf\x39\xa9V\xfdp6\xbc\x62" 
  "\xe5I\x92\x32\xf9\x81\xa9\x90\xc5H1\xad\xcfW\xa0\xc4P\xcb\x9a\x86\x4\x38" 
  "\x6K",
  (unsigned char *) "W\x89\f\xa5\xac\x1e\x90\'Tm\x92\t\xac\xec\x1Q\xac\x95J" 
  "UN\n\x1\x98\x94\x2.EQK[\xfa\xf2\x97\xdc\xa8\xe5\xb1\x1c\xa9\x5hE\xc1\x98" 
  "L@&pL\x91K`v\x83^\x18\xf4\x42\xbfN\xa4\x18~Q\xb3\x9aq\xb8&\x0\xb0V\x10Jn" 
  "\xc3\x10\x8aI\x84\x11\x88\x91\x31\xe0\xd8k\v\"\xbb\x6){p\xa9uJ\xd0\x16" 
  "\x18jf\x18Z\xb1\fz\x8e\x33\x91=\xab\x85;\x9f`\xb4wRe\x9f\f\xcc\x41\?\x85" 
  "\x0\xa0\xfe\xe0J7\x9bye\xe2~\xc2\x36q\b\x8e\x9b\xf-\x16\x46l\xd2\xbc\xaa" 
  "\xd9\xcd\x12\xf8\xd0\xc7\xfeplb\x87\x8c\xa6*\xa2\r\xc9\x4\x1\xbc\xd3 " 
  "\xaa\xf5\xc1\xa3\x92\xa8\t\xd5*\x1a\x1d_t\xec\x7f\x37\x98\xe8Jsb\xd1\x88" 
  "zd6(\xfaHD\xd6q7\x96l-\x13\x11\x45\fo\xee\t\x84\xd3\x5@\x89\x2\x8a\xdc" 
  "\xee\"\xf3\x97\xbf\xd4\x8c/\xb6s\x9cm\x96*\x1f\x86\x30\x35\xaa\"k\xea" 
  "\x7f\b\xa1:\xbf\xf4\x42\x1fX\xd9\x89S\v\x92T}\xa4\xc5\x1bg\xdd\xcb\x36" 
  "\x97\x62\x97\\,\xb5=\xecIO/Q\xe4\x80s\x98\xefxw\xed\xdc\x64\xb6\x9a\xe" 
  "\xc7`\x95\xaf\x12\x31^\xe7<\xe8M \xfe\xd5\xb0P\t\x1a<\xf7\n\xc4\xbc\xfa" 
  "\x8f\x34q\x83l_\xe5\xf5\x1a\x38\x38V\xa8\x42\xb9\r>\xc5\xa1\n\xafY\xd0}" 
  "\xb6)\xf\x10#8\xda\xcf\x8e\xa9\x84\xd2\xc9\x6i\x93\x13,\x5X#\'\x87J\x6k" 
  "\xbdV\x9d\xeb\x34\xa5\xb6\xd8\xb1\x5i\xc3\x63\x89\xcf&4\xb3\xb5\xc2\xe7" 
  "\f\x11P\xc4\x1b\xe8\xe8\x83\xde\xe3\xeb\x85h\x86\x1fo \x96;\xc5\xa5JN" 
  "\xda\x9d\xb3\x94%\xa6\x96;\xcf\r\x8c\x1\x8d\xa7\x14Ve7\xba\xd6\xe8\xc3T" 
  "\x14\x4\x80\xa9,7C\x8f\x2/f\xe3\xfa\xc9S\xb1Q\x1n\x9c\xa2\x3\xee\x62\x0@" 
  "\n\xf0LDJ\x13\x1d\x63\xd4\bA\xea(\x8a\x45\xf2o\x94\x0\x89\x8f\x46\x18" 
  "\x84\x13\x99\x0\xf0\x8d\x4<\x8f\x34)x\x19\x11I",
  (unsigned char *) "Z\x83\xf3Ka\xf9\xba\x44J\x4H\r,2\xfc\xa2:\xfa\xc3\x39]" 
  "*W}\xe7;!\x13\x61\xd4\xc4\x45 \xc6.#)\x88\x16\'\xe1\x92\x90\xc2\xa6\x13" 
  "\xe4\x19\x9f\xa5\x98RN\x9e\xac\x5\xa0\x80\xf3\x8a\x43\x11 Q\xaf\xba\x82" 
  "\xc1\x80\t\x86\x97.\v\f\x99\x8a\xa9\x10\xad\x30\x64\"{!\x19\xc2:\x3\x2" 
  "\xbf\xd0\x64\'[YVU\xbe\xb2\x96\x85\x91\xe5-{\x99\x97_\xe\x33\xaf\xba," 
  "\xe6\x32k\xa1\x6hN\xb3\x9a\xd7\xcc\xe6\x36\xbb\x19\x6!\x0\x0;",
  NULL } ; /* --- end-of-image11[] --- */
/* ---
 * image12[] contains a 1426-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (12) dvips ran but failed:\\See mathtex.html\#message12}
 * ---------------------------------------------------------- */
#define	IMAGETYPE12 1			/* 1=gif, 2=png */
#define	IMAGESIZE12 1426		/* #bytes in image12[] */
static	unsigned char *image12[] = {
  (unsigned char *) "GIF89a\xcd\x0(\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0\xff" 
  "\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb\xdb" 
  "\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff\x16\x16\xff==\xff\x1\x1\xff[[" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4\x1\x0\x0" 
  "\x0\x0,\x0\x0\x0\x0\xcd\x0(\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa\xael\xeb" 
  "\xbep,\xcf\x30`\xdfx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\x41\x11r\xc9l:" 
  "\x9f\xd0\xe8P)\xadZ\xaf\xd8\xec\x91\xaa\xedz\xbf\xe0%7L.\x9b\xc1\x63\xde" 
  "\x80 D<\x82\bE\xe1\f\x97\?\xed\xbd\xf8\xdc\xa7\xa7\xa7u\x5\x6\x37\x81\x3" 
  "\x83\x6\x6\v\b6\x3\v@\x5\t\x82<\tot\x8f\x91\x41{9\x8f\n\x1;\x93\x0\x96\?" 
  "\xa1g\x7f\x39\a\x8a\x0\f\f\r\n6\b\xe\x36\xf\r7\v\x85\?\x87=\x4\xb6t\xb8" 
  "\x42\x97\x38\xb8\x99\x38\xba\x36\xbd>\xc6\x65\xa5\x37\x3\t\xa6\xad\x0" 
  "\x9c\x37\x1\xcf\x3\xb0\xb7\xbft=\xc8>\xf\xd8\xc5\xde;\xdb\xe1\xe0_\xca" 
  "\xdf\xce\xcb\x36\x5\x1\x99\x9d;\x8c\n\f\x90\xa9\a\xd6\t\xe\x11\r\x82\x4" 
  "\x10\x93\x6\t\x85\x10\x18P@\xc0\xda\xb2\x6\v\b\xb0KE\x80@$\x85\t\x15\x1c" 
  "\x10v\xe3_\xc3Z\x0\x6\xe8\xcb\xb8\x91\x1\x84\x3\x3qH\x4\xc9\xd0\xa1\r\x5" 
  "\x1b\xfe\x1\xf4\x62\x90p\xc1\x1cx\xf2\"\x89\xd3\x62\xe\xc0\x81g7n\xeaX" 
  "\xd0(\xe7\xae\x1b\b\x2\xa0\"\xa9\xb2\xa7\x1\x45\xbd\x10\xa9\x13j\x80\r" 
  "\x0J\xc0\x66=P\x4\x10\xc0\x2J\x6\xe\x9c\xd3\xa1\x14\x94P\x95\x32\xc3\x8e" 
  "\xb3Q\xf5\xeaV\\\xfc\x16\x9d\xfajSl\x98\x9a:q\xc4\xbd\xc1\xc0\xa0\x8d" 
  "\xb9\x37\x1eh\xbd\x1bi\x9d\"\x6g/\x1dx0\xe0\xe3T\xae\xd8\b:p;\xd3\xd8`" 
  "\xb0",
  (unsigned char *) "\x81\xc7\x9e,\xc8XP\x82\x9b\n8\xe9\xcdI\xce\v\\\x9cwA" 
  "\xf\x10T \x13\xde\x62{\xdb\xdep\xa0jOR\xc1\x6J\xd7M]\xf1W\x82V\xaf\xb7" 
  "\xe6p,(7d\xd0\x90\x1\xdc\xe\x9e\x9b(j\xce~\xdc\xf1X\x0X.\xce\x35\x36\bd" 
  "\x82\x80\nG\x1\b\xc8\x17\x41hN\xbc\xe7\xba@{f\xed\xbe$\xd1\xc6\xe2\xdenw" 
  "\xf7\f:\xa7\xd7\xe2s\xd8p\x95\ap\x9e\xf8>\xf1O\xafgoH\xa6&\x81\x9e\xa9" 
  "\x18\x10\xc0<\xeb\x90\x0\x14~9\xb0\xfe\x44\xd0G8\xc5\x85\x12+*\x1d@\x80" 
  "\x2\t\xb0\x81\xc8\x1aP\x9d\xd4@\x3\xcd!p\xc0\x0\xf1 \xf4`f\x1b\x2\xa7" 
  "\xd2\x3\nT\xe3\xd4# &\x0\x61\x1\r<\xe0\x94\x86\x1cz\b\xe2*\v\x8c\x38\xa2" 
  "J\xe<\xc0\\*9\xf2\xa3S\x2\xcd\xbc\xa5\x1c\xf\xb4\t\xa1\n\x1f\x0T\xe7\n" 
  "\xf\xc1\x0\xd5\xe4\x10N\x16\x41\xd1\x94UV\xa9\x83\x96=P\xa4\b\x97h\x1c" 
  "\xb9\x3\x1\xdc\xc1Q$\x14\x33\x65\xa3\x66r@\x10#\xc4\x61P(p\x88\x89k\xd6" 
  "\xd9\x9f\x98<\\\xc9\x3\x2`\xda\xe9\xe7\x9fS\xe0\t\xe8\xa0\x84\x86Y\xe8" 
  "\xa1\x88vQ\x13()\x82\x62\x46\x1fP@\xba\x84\xa4@\xa1\xd2g\xa2<\xd4\xb4" 
  "\x64 Ij\xb1\xc7(\x9a\x1c\x1j\xa8\x98\xcc\x93\x83K\x0\xf0\x37(!\x86 r\xa9" 
  "\x39\x5\xa4\xe6\x61\x18\x97\x34\x86\x44\x9a\x9d!\xa6\x43\x91\xe\\z\x86*" 
  "\x10\x36i\x8d,>\x98\xa3\x0u\x15\x81\xd1Mm:,{\xc4L\xce\x6\xb1M \xe6\xfe" 
  "\x1d\xea\xa0r\xd3\xf4\x0\x17\x4!\xd1\xd5\xd2\x1c,\xfdG\x11\?\x11}\x98" 
  "\xd9\x44\x36\x30\xd0P$\x1e\x81\x84[\xb9\xe0~\x14R\xb8.\xc9\xd3\f\x1\a\x0" 
  "X\f\xbc\xe9\xca\xbb`\xb9 J\xe4\x1a\x36\x84\x65\x4\x15\xb9\x13\x9a+p\xba" 
  "\xdf\n\xa4X\x93\x3\x15\x94\xee\xba\xde\"\"\xf\x90\xe2\xe6\xf4\xdcRz\xda" 
  "\xb0\xa8\x1\r\x88\xc0\x46Z\x19I\x88]\xc9\\\xed",
  (unsigned char *) "\x95\xd5VeaU\xab\xcan\x91<\x80V\x1a\xc5Q\xe6q\xc1\xe5" 
  "\xbcr\x84\x91\x5r\bHY\x1d\"\x93\xca\x30\xa7z\xf2\xccM\xc5\xa2\x92S\x94" 
  "\xb4\xec\xb1\"\?\xca\x9c\xdaiV\xe9\xab\xc3\xa2\xae< \xd4\x65\x99q\xc2ufx" 
  "\xfa\x66\x8c\x62\xe9\x89\x1d\xc9\xd7\xd1\xa4\xda\xc0\x8c\xc0\x94]ke\xba" 
  "\tK\xd6x\x91\xa1\x1d@a\x83)\x82\x37\x9c\xd0P\xe6q1o\xd8\xadq\x82v\xed`,h" 
  "\xac\x18\xa7\x9a\x36p\v\x87\x9bX\x8fG&\x91\x37\x1e\x16\x1e\xd9\x39\x91" 
  "\xdbwN\x1c\nt\x93\xd9m\xfe\x99]\x8e\x8b\xe2\xb2\x39\xa0U\xe9{\r\xd7KB&-" 
  "\x8e\xce\x32\xa4u\f\x80\xb1\xbf\x34\x80\x0\x1\xf8\xc9\x98\xbb\xae\x9a" 
  "\xcfW\x1f.\xe8\x45\xd6\xd4\xee\x2\xd1G\x89\xaa\xbe\x41\x16\xbc\xe6\x90q" 
  "\x8e\xd9U]\x8b~_^\xb1\xd9\x30K\xf5\x0\xcc\xe2;.7\xe3\x9e\xd7\xe0\x8b\x38" 
  "%\x9d\xb6\x82\x9e\x4If\xac\x15\xd3\xe3\x8f\x6\xac\x7f\xb3\x44\xac\xe8X" 
  "\xa2\x8d!6\x2\xa3\x8c\xf2\xbf\x18\xa3\x85\xee{\xd4\bD\x8fhF\xfe\x9eq\xbf" 
  "\x84\xc5\xaf\x44\x3\\M\xb5\x44r\x80\x3:\x10\x37\xee\xbb\x10\x1\xde \xc1" 
  "\x37\xd0\xfG\xf4\x39\x80\x6\x13\xc1#\x1f\x1\x86\x1\x2\"P\t\x8aU\xbe&)\"3" 
  "U\xa2\x88\xec\x80\xc0%_Mi\x10Op\xe1;(a9!\xec\xe1KR\xca\x12\xe\x16\x0:\x2" 
  "\xdc\x3\x86N\xc0\x1a\xa6\xecT\xb0\x1\x64\b\f\t\xb9\xc1\x7f\xaa \xc4!\xae" 
  "\xe9\x19x(C\xd7\x42\xc7\xc4\x12:\xf1\x8aX\xcc\x94\x15\xb3\xc8\xc5,6\xb1" 
  "\x8b`<\x14\xd4\x17\xc3H\xc6\?\xd1\xe0\x8chL\xa3\x1a\xd7\xc8\xc6\x36\xca " 
  "\x4\x0;",
  NULL } ; /* --- end-of-image12[] --- */
/* ---
 * image13[] contains a 2307-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (13) Can't run convert program:\\check -DCONVERT=$\backslash$
 * "path$\backslash$", etc.\\See mathtex.html\#message13}
 * ------------------------------------------------------------- */
#define	IMAGETYPE13 1			/* 1=gif, 2=png */
#define	IMAGESIZE13 2307		/* #bytes in image13[] */
static	unsigned char *image13[] = {
  (unsigned char *) "GIF89a\xef\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff==\xff\x1\x1\xff\x16\x16" 
  "\xff\x32\x32\xff\v\v\xff>>\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xef\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcft\x9d\x2x\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\xc8\xa4" 
  "r\xc9\x13\x31\x9f\xd0\xa8tJ\xadZs\xce\xabv\xcb\xedz\xbb\xd9\xafxL.\x93" 
  "\xc3\xe6\xb4z\xcd&\xa2}\x3\x2\x11\xe1\x18\x16\x14\x3\\\xc1X@\xb4\xff\x80" 
  "Ro<\x5\x6\x39\x85yz\n\n\x6\x89\x3\v@\x3\t\xe\n\x4\v\v\x86\x45\a\t\x87" 
  "\x81Q{\x9e\x62\x83;\a~\x0\f\f\r\n9\r{\n\x1\x39\v\x89<\x3\r\xa6\x38\t\x99" 
  "\x44\x5\f9\xba\xa1J\xbf\xc0[\xa3\x39\x92\xa4\xab\x38\xe~\xaf\xc6\x10>\a" 
  "\xbd:\x3\xc2\x42\xc9\xe\xd5\xc3\x44\xd8\xda`\xb0\?\x6\xc2\a\xc9:\t\xd2" 
  "\x38\xdf;\x5\x1\xb7\x39\xab\f\x4\x4\x99\x4\x1\v\x4\n\a\xa0\n~\f\xf\a\x6" 
  "\xe4p\xd4\xb2\x17\xa0@-C\a\x1\xd0\xb3\x87\xf\xd4\xb4\\\vz\xc9S\x0Oa\xbd{" 
  "\xf9N\x1dx\x6 \x1\x4^\xf6\x16\x18l@\x90\x97\?\x80;\xfe\b<\x98\x64 A\x9e" 
  "\x81\xf4\xf6L\xacx\nSD\x97$c\x9e\x8a\x37\xef\x1\xc3\x3\x3\x16\x65\x4\x10" 
  "nJ1\x1c\xe3\x90Ms\x90\xc0!\x0\xa0<\x9a\xf9p\t`A\x1d\xa2\ap\x14\xdd\xb1" 
  "\x95\x87\x81\x6\x0\x96\x11\xcd\xb4\xd5@\xd6\xb1\xea\n\x86M\xa0\xe0\x41" 
  "\xe\b\xab\xccj%\v\x89(\x2\x95\x2\xb3~\r\xeb\xa7+\xd7\xba\xeb\xfa\x82]" 
  "\xd6\xf6\xed*vU\xa5\xed\x15K\xd5\xaa\xd6\xb3",
  (unsigned char *) "r\xd1J\x8er\xf4i@\xcb<\x10<p\x98\x34m;=8*A K\xdak\xb6" 
  "\xc9\x92\xcb\x96\xd6\xe1\xe0,\xae\xba\x44\x39\xa9\xd6\x83\xb8W\x82q\x8b`" 
  "\xf9\xf5\xab\xa3\xeb\x81:]\x13\xc0n\t\xe0\x9b\x81\xab\xbc\x45\xaf\x9em" 
  "\xa5r\xe7\x1c\x9d\x11\x9c\xfb\a\xfd\x32\xd2s8\xe8t\x8c\xbb\xbcZQ\xeb\xbb" 
  "\xbb\xcf\xe5\xea\xfa\xe9p\xbd\xab\x1@@\xb5\x87z\xef_\xdfMC7\xe4\xfb|U" 
  "\x9e\xbe~\xb1M-\xbey\xba\x1e\x11)u\x8a[84p\xce\x3\x9f\t\xfe\x64Ko\b\xe0" 
  "\x83\xc3h\xf4\xa5\x97\x1fQ\xf2M\xa8^\x7f\x87 \xa6P*o\xf5\xc2\x1c\x0\x3< " 
  "\r\x1`)\x83ZQ\xde\x1\xa6VW\x1c>\xd8\vv\xe3\x85v\x16\x84\xfc\xc5\x18\x8fQ" 
  "\xff\xf1`I\xe\f\x18\x10@.\x0\xd0\xb1\a\x3\x1c\x5Yb\xf\x92PbI\x1e\b\x0" 
  "\x45\x11I\n4\xa0J\x94\xaa\xa8\xd3\x80\x3r\xe8@\xe5\x39\x5\xb8\xa4@\x2SJ" 
  "\xb9\x88\x98;0\xf0[#DA\x80\x8d!T\x8eY%R\xe4\x18\xa0\x66\x44[\x1ere\x96" 
  "\xbd\x1dpO\x2r\xd4\xa9\x95\x9a[Ap\xc0\xa0\v4(\xa5\x34M\x6\x95\xca\x2\xf8" 
  "\x84\xe9\xe8*\tp\"H\x8e<\x94\x87\xa4\x2N\xa1\x12\xc4\x1d\xb3\x64\x97\x44" 
  "\x82\?\xf8\x1*\x10\x9f\x39\x45*!A\x80Z\x94\xa9=8\xb4\x0[\x95x\xe4\xc3" 
  "\xa8\xa2P\x9a\x12\x8c\xa9J\xda\xcd\xae\xe0\x9c\x6\x84=9\xec\x38Le8\x10" 
  "\xd0i\x10\x62\xf1\xaa\xec\xe\x8c\xa0t\xc4\"\xd0vC,hC\xfe @\xeb\xb2\xd8" 
  "\x66[\xc4\xb4\xdav\xeb-1\xb6~+\xee\xb8Up\x9b\x1d\xa6G4\xc8\xea\x13\x9cR+" 
  "\x10\x1e\xde\xepU\xe\b\xec\xd1\a\x13\xea\xee \xef\xe\xf5\x2p\xef\x17\xe6" 
  "\xfa\v$\x1f\x3[\xe3#D\a\x14\xfa\x90\x92\x97\x64\x32@4\x14Q\x5\x80\x2\xe" 
  "\x4\x90I\x1\v\xd4sJ\x3\x16\xbb\xd3\xc0G\nd\f\xa1\x1\xf\xb0\xe9#\x84p\xb5",
  (unsigned char *) "\x15\xce\x1%\x9b\xe5k\xe\xbaj\x5\xcb&I\x80\xd2\x65\x35" 
  "\x31\x13\x35s\xce\xbb \x11\x30jD\xf0\x16\x44\x0\xe4\x44iJ-\xed\x0\x89" 
  "\x34\xbdP\xe1\x90q\x9c\x19:\xf5\v\xd1\xf4\xc2\x46u\x90\xf\x44\x90Hd\xda!" 
  "\xdb\xa9v\xbc$\xa1\x8b\xd0\xe|]G\xd8H\xbc\xec\xc3\xcf\x42\v\xd1\xf6\xfW" 
  "\?\x98I4\xfa\x1a\xf2\x0\x9e\xc5\xba\x6\x90\x86\xfa\xc1V\x0\xdeW\xbf\x83" 
  "\x5\x39\aH\xe0\x8b\xde\x42 Pdh\x8c\x1f\xc1M\x8c:(\xcel\xe3\x46<nDe\x92" 
  "\x18\x10\xa0\xe6\x18\x81\xc2@H\xfe{d\xbe\xb9!\x4\xb8\aD\xdc\n\xb9\x15XT" 
  "\xab\xef\xa0\x16\x85\xafj\xa5\x3=9\xcc\x8b\xce*\xd4\xb8\x9e\xcc\xd2\x8f" 
  "\x1d\xa1\xb0\x1e~\xcc\xa2\x12K\x12\xc3#\xf\xe\xfd\xfc\x13\xd7O\xae\xder" 
  "\xef\xb1>|n\x89I\xca\x83\b\x11\xae:\x1c\xb5\xce\x1eLa5\x1e^ \xe6\xa3V" 
  "\xf7\x45\x31:\x4\xea\xcdH\x15\x95\xadW\x1b\x82\xc0\x95\x14\xea b\x90\xb6" 
  "\x17\x37Z\xc1\xe8P\xe2\x0\x82y\xeaPH8\x0\x4 (\b\x80\xbd\xde\xa8\xc8\xf" 
  "\x8d\x41\xce\xd8 \xa3\v\x2&\x1|\xf\x93\xcc\xf6\xd6r\xbap\x85\xc5R\xb3" 
  "\xb9\r\xb4\x2\xd0\x9a\xbf<g\x1a\xd1\xba\x9d\x96T\xa7!\xffM0r\xafsX\x0r" 
  "\xd7\x1b\xb0\x30\xc0T\xed\xf3\x17(\xdaW\x9e\xc8\x18\x61q=\xf0\xcdU\x94" 
  "\x3\xb9\xf\xa9\'\t\x1a\xcc\x8d\x64:x>\v\xda\x30\x46\x45\x31\x9d\xf7z\xc3" 
  "\x96\x5\x95\t\x80\x83\xd3\x1&\xae\xc3\xaf:\xd0M\af\xf2\x45\xedH\x92\x96}" 
  "\xe9\xe\x8b\xa6\b\xfe\xdc\x7f\x8e\xd8 h\x99q\x1f\xbeX\x97\x85\x9e\x62" 
  "\x88\xfd\xcc\x86;\x90#\x8a\x1a\x81\xa0\x44\xb4\x30\xc2Rp\xb3`\xeb\xe4" 
  "\x30\x1b\x12\xd5n\x8fhq\x0\xe\xd7\x46\x8e\x87\x1d\xcd\x89Z\t\x1e\xff\xb2" 
  "\xd3\x80Y\xfc\x62P<\x80\xc0\x9b\xb2\x17\x90\"\x89\xd1\x15K<\xd7\x19\x43" 
  "\xa8\a\xd8\xe4PEw\x98\x11\x8a\xe8S\xa3\x43xR",
  (unsigned char *) "G\xd0\xf3\xa3\x89P\x4\xc8\x1b\x35\xc1\x82\x1a\xc1\x46P" 
  "\xc4\xd4\xa6\x34\x39 @f\x92\x65\x94p\xf3\xa3\x39\x86,\x0#\xfb\x9d@&Q\tY" 
  "\x18\xc3@\x14i\xda\x97\x2\xc0%\x9e\x15\x46K\"\x3\xa0\?&\x96\xb1\xfd\xbc" 
  "\x8f\x1\n\x98\xc0W,f\x9d \f2O{\x92\x43\xa2\x9e\x4\x89\x2\xdc\xa9M\xb5|\v" 
  "\x10n\x93\xc3\x39\xf5\xc2\x9cX\x8a%\x9a\"\xd5\x83i]\xab\x13\x91\xe3\x42" 
  "\xbbh\x1\xaf\x9a=\xa1\x9fK\xa0I\xe\ra*P\xdd\x13yx\x8b\xca\xf\n\x9a\xcf" 
  "\xa1\xc1\x92\\\x10\xfd\xa1\xf\xde\xc6\x84o\x9e\v\\\x11\xcdh\xfe\xf \x0" 
  "\xaa\x66u\xb3\xa2\xa3\x82\x1e\x15~\xa6QlY\x8b\f\'5\x3IK\xca\xd2\x88\x12" 
  "\xab]s\xdc\x42\xbe\xa4\x30\xd3%\xd4\x94^\xa6\x38hK\x97P\x19M\x15\x2\x8f[" 
  "\xb0\x19\xfe\xf0y\x84\x9b\xf9 \xa6\xfe\x1bjUd\x92P@ \xe2\x10\x8b@S\x1a" 
  "\xb4\xe7\x9a&\x8d\x61l\xd9P[\xaf&Z\x4\xa1I\x8a\xa3\xc0@\xc5$[1\xb1\x87" 
  "\x62\xd4\am\xb9\x85V\xa5`9\xb2\xadu\xa0=\xb0\x9c\xdb\x84Q\x88\au\xe3\x39" 
  "\x62Q_\x19\x9cS\xb2\x80HO$5\x99^J|\x82\x91\xa0\x34\x4\xa1\xc7\x1bP\xf5" 
  "\x38w\xd8\xe4\xa1\xe4\xaf\xbc\xa0g\xe9N\xc9\xd8\xa1\x38\xb6\x12\x84\xc5" 
  "\x87\x61\x87\xc2\x9b\xb2\x81h^*\xf9\xc9\x66=\a:\x4\x0\x84\x0\xcf\x30\xad" 
  "h\x10\xab\x8b\xcfi\x8e\x1\x9c\x80lux`\xe\x35\x10k\x9b\x1\x90\x3\x4\xf5" 
  "\x44\xa0\b\x92\xa7w\x92I`\xf\x19h\xa3\xde\x66\x5i\x14\xf1\nq\x87\v\xdc" 
  "\xd9\xfc\xcf\x65\xd0%\vd\xfe\x88\xbb[\x3\x64\t8\xd7\xc5\x45\x1e\x1cS\x1c" 
  "\?\x4h\xb7\xb3\x35\x6S\x90z\xd6TU\f\x1\x41|Ez)\xc5\x9c\xae\xf0p2\xed\xcd" 
  "\xc4z\x8b\xd5\x80\xa6\x96\x12\xbe\xfd\xf1\x8b\xe4:\xc2\x15\xf1\xac\x37" 
  "\x44\xbfQd\x80\xdd\x81\xdaL\x18\xa7\xe\xf3\x85Sf63U\v.B\a\xaaP",
  (unsigned char *) "b\x1d\xfb\x8b\x44\xf9\xc2\xd1\x8e\xa5\xfc\xce\x84\x9b" 
  "\xf4\xcd\xf\xc5\'\xbe\xe3)#6\x16\x1\xab\x64\x80X\x89\x5\xe0\x85\xa0\x64H" 
  "\xa4\xb3\xb8\x31\x13\xf6H\xec\x84\x31\x13\xa4\xe9\xbc\xb5\\\xe\xfe\x85-T" 
  "\x19\x16\x1e\xd7/\xc3l\x12\x65\x84(\x4\x62\xeb\x1e\xa9\xe\xa6U\xcfU\\" 
  "\xe9\x61R\x82\x18-e\xc4\x8dUB\bb\x1f\x1b\x0\x14`\xb9r\x81&&\xe4S\xa4\xe4" 
  "\xc8\xe1\xed\a+\n\xe8\x8d\x1f|\t \nX\xcf\x9fn\xe9!w2\xeb\x0\x8fj\xd3\x38" 
  "\x17\xe5\xafs\xd2\x92L\xf0\xe4\xa3;\xfb\x1\x89\x85t\x89\x13\xe8$S\x9d" 
  "\xb1\xd4(7\x19:\x9d\x12\xc5\x61\xa1\x3\x88]%9\xb1Ysq\x0\x8e,\b\x80\x64\'" 
  "\xd1YP\x84\xea\x8b\x9b{\xf4#\xf7\x39`H\x16\xf5\xc2QN\xba\x88R\xa9\xc3" 
  "\xa6=8h;\xc8[\xad$x1\xd4\x9b\xf2\xd4-D\xc5/)\xc2\x8a\x0\xb2r\x17\x1c\xd0" 
  "\x65[\xb3\xee\xf4\n\x9e\xf5\"\x19\x80U\xacS\xf2j\xa5\xbf\x86\x42\x32x]" 
  "\x86\x33v\v\xd9\xc9\x8e\xb6\xb2\xa0-\xedj\xf\xcb\xd7\xd6\xce\xf6\xae\xa8" 
  "\xad\xedn\xaf\x81\xdb\xde\xe\xf7\x19l@\xeer\x9b\xfb\xdc\xe8N\xb7\xba\xd7" 
  "]\x82\x10\x0\x0;",
  NULL } ; /* --- end-of-image13[] --- */
/* ---
 * image14[] contains a 1444-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (14) convert ran but failed:\\See mathtex.html\#message14}
 * ---------------------------------------------------------- */
#define	IMAGETYPE14 1			/* 1=gif, 2=png */
#define	IMAGESIZE14 1444		/* #bytes in image14[] */
static	unsigned char *image14[] = {
  (unsigned char *) "GIF89a\xcd\x0(\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0\xff" 
  "\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb\xdb" 
  "\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff\x1\x1\xff==\xff\x16\x16\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4\x1\x0" 
  "\x0\x0\x0,\x0\x0\x0\x0\xcd\x0(\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa\xael\xeb" 
  "\xbep,\xcf\x30`\xdfx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\x41\x11r\xc9l:" 
  "\x9f\xd0\xe8P)\xadZ\xaf\xd8\xec\x91\xaa\xedz\xbf\xe0%7L.\x9b\xc1\x63\xde" 
  "\x80 D<\xce\x65\x84\xa2\x0\x9d\xfb\xe4\xf4\xbb\xdd\x9a\xd6\x15\f7\x7f\x3" 
  ":\v\n6\x3\vp~X\x5\t\x80\x42y~\t\n\x1;\to\x8d\x8f=\x99W}9\a\b6\f\f\r\x86" 
  "\x38\x3\xe\xa6\x0\v\x83\x8a\x37\x9aV\x6\xb0\?\xb3\xaf\x80\x91\x38\x4\xad" 
  "\xb2@\xbc|\x95=\x3\t\x9f\xaa\x0\b\f\a\xaa\x3\x10\xae\x36\xf\xb5Q\xbe@" 
  "\xcf<\xd2>\xd6\xd5\xd0N\x9e\xb6\xc4\x38o\xc9\x38\xc0:\xc2\x6\v\f\x0\x4" 
  "\x6\n\fl\x4\x1\v\x4\n\at\xc8\xcc\x0\t\x10\x5\f\xf1\v\x5\x3\r\xe2\x5\xd8" 
  "\xe7\xe0\xc0\xba\x1c\x0\x5\xd6#\xa0\xce\xc6\xbbx\xf3p\xd9\x30\x90\x80!+" 
  "\x0\x0\x1\x65\x4\xc0\xa0\xe0\x41\x1c\xf3\frd\xf8HA\x83G\xbe\xfe\xf8\x11" 
  "\xf0\x87\xb1\x10\x3G\x13\xb5m\x19\xb7#\x1c\xe\x9b\xe9\x42\xe1\x4p\xa0" 
  "\x15\x8e\x2\x3\x1<\x98\xe4\xe0\x6\x4\x43\x6\xe\xc4\x9c\x98\b\x80\x1\x4" 
  "\x4\x8a\x62Tj\xa0\x81\xd0P\xd8^Y}\x10*\xc1\xa0\x5o\x9c*uZ\xcb\x9c\r\xa0X" 
  "Q\xaa\xcd\x66\xc3\xeb\xaa\xb0\xbexE=\x4*@(\x9ek\xa1p\xb3\xb1\x93\xa7\xa9" 
  "\x2\xa6v\xf6\x15:\xb6mS\xa7\xc3\xe2>B\xcb\x11_2\x5",
  (unsigned char *) "\x94\xc8\xe2\xc8\xba\x14$\x1\by\xb3J;\xf0\x46qe\x1d" 
  "\xd2\x14\\\xce\f(\xc1\x63J\xf\n\x8b\xfc\xe5\xa3\xafMu\xb2\x1c@@\xc7\xb7" 
  "\xd8\xc4\xc2<\xf\'\x95\xcc\x1b\xc0l\x6tVw\xeb\x66\xbb\x37>\xa4\xa4\x41k" 
  "\x12\xe9Yrq_\x93x{\x16.\xf6\x6\xf5({W\xd1\xb6^|\xa7\x83\xbb\?\xed:$e\x14" 
  "]s\x8c\xeh\x13\xb0\xea\xcc\x38\xaf\xb2\x9a\xe6\xd9\xc0\f\xe8\xfc\xab\xa6" 
  "\b\x82\xfa\xc2\xbc\x14>\x0\xf9\xbe\xbd\xb7\xd6z7<P\x80Tx9\xfe\xc4\x86^4" 
  "\xe9\xb0\xd2\r\f\x18\x10\x0LgI\x98\x0m\b\xb0\xa7\x3\x32\xcf\fb\x0\x4\xcf" 
  "\x0\x62R)#\xaa\x82\xd3\x87\xf\x9c\x33\xe2v\x5\x34\xf0\xc0\x82\x37\xach" 
  "\x3\x2=\xb1\x13P\x89%\xe6`\xc0\x3\n,\xb3`#\x3(\x90@)\x0\xb4\xf8\x62\xe+" 
  "\xd2\x18$)\x85\x34@\xa2\x93H\x81x\xeG\x85\x44\x15N\x2\xc3\x30\xf8\x3nB" 
  "\x8crG\xe\x12\xf5\x0^ \?\x8c\xf9\xe5\x11\x61\x86\x62\xa6\x99;\xb0\xb9I" 
  "\xejb\x91]:\xdb\x5\x81@\x96\xcd\xe4\xa9\xa7\x96\?\xe8\x32\x4W{\x6*\xe8LA" 
  "\x84\xc9\x3\x2n\xe\xaa\xe8\xa2\xe2\x34\xc8\xe8\xa3\x90\x62\xe7h\xa4\x94V" 
  "Z\xc4\x9c\x80\rbh\x17xD\xd1)\x13\x9f\xe2\x80\xe8\x8c\x96&1)\x84\xe8\xfc" 
  "\xc1\xa5\x16yp\xb2\x88\x11\xae\xbe\nD\xac\x37\xb0\xc4\x90\xa2\x82\x10R\\" 
  "\xa3\x9b\x14\x46\x63\x18\x9aP&\x13-\xda\f\xab\x63-YB\x90\xa8\"\xa3\x10yJ" 
  "*>\xec\xa5\xc0w\xaf\xfe\x80\x41\xcdg\x5\x1a\xdb\x3\x65\xd7\x6\x81\xcd" 
  "\x1f\xf3\x31\xba\xd3\x31\x83\xf1\xda\xc3\x1\xe|$J\?\xf5\xb0\x9b\x43T\x10" 
  "\xd5\x18\x91($\x89\xe2\x11R\xf1\xd6s/\x95+\xed\x83\x65:\a\x1c\xc6\x94<" 
  "\xf4\xd8k\x90h\xe\xc4\x1b\xe4\xbc\xc6\t5\xc8\x0\x61\xa5\x93\x30\xc1\v" 
  "\x17\xcc\xaf\?\b\xacs\x99\x31\x1a\xdf\xd3NC\xeb\x9a\xf3\xd2\xc5\x91\xec" 
  "\x4\xce\xae\x37\xcc",
  (unsigned char *) "Y\x95\b\xeeH5\xc0\x1sM\x5\xdaX\xbb\xf1\xe6\x16X\x9f" 
  "\xd5\xdc\\\xcc/c\xd4\x80\x1cu\xde\x96s\xb0\x34\xd3\xbc\xd6\x1f\xb2\x18" 
  "\x94\x94,(\x15\xbd\x14\xcf\x6-\xd8\x99\xd4m}\x15\x96xSB\xcd\xdd\r\x4\xe8" 
  "\x84\xb2\rs\xce\xf8\x80]\xa6\x41\x46I\xd9\x90\x39\xda\\h\xa3\r]\x19t\xa7" 
  "\x1\xb3\x1e\x8c\x93\xe5\xd5\xdb\xdav\x1bs\xf\x9eo\xaf\x85\x36%\xa8p\x16J" 
  "\xe0\x80\xda \x1a\x7f\x0\x0\xb3\xa3\x63\x66\x8f\x63\x13`\xb5\x45{\xea" 
  "\x7f\xc5\x94\x42\xddu\xc7\xf6\xdd\x16rKq.\x9d\x88\xfe\x98\xd3xO\xe6w\x8b" 
  "\xf8\xb9\xe6r(\xf0\fd\x93@\xa6\xb9\x64\xd4\x15\xb0\xf\x4J\xc9\xce\x0\xed" 
  "\x9b\xf3\x16\xf\xc8\x98\xfb\xe5\x10\xd3\xb2\x5m\xee\xe\n\xc0\xf2\x33\x81" 
  "\xce /\x94r\x9a\x3H\x9f\x64\xf5%g\x80\xf2od\xec[X\xb7\x9e\xde\x9f\xf6" 
  "\x9e\xa5\xfe\x18Xf\xbf.\x97\x86\xcf\xe4\x61\x95\x1\xe6\xff\x37\xd6\xf3" 
  "\x41S\xbf\xb5\x37=H\xeb\bd\xb3M$\xa5y\xf7#y\xc0\x93\xfc+\xa0\xa4\x8d\x89" 
  "\x30\x92<\xa0\x94#\x1:\xe5~\x1dI\xc4\x43\x1a\x31\f\x1c\x41\xe9,.\"X\xff" 
  "\x1c\xe8,\xdf\x84\v$\xfb\x83\f\x1\x1f\x88\xa2s\x98\x63\r\x9d\x61\x5\x1" 
  "\xaaW#&\xf9\xe6\x0(\\\x0V\xf2\x17\xa1\ti\xe2\xf\x13\x12^\xca&7*\xc8\x98I" 
  "\"\x9b\xb2S\x9b\x80\x30\xa6\x1c\x12\x61Y>\x80\xd8\x5\x61\x45*\xf0\xc4IT8" 
  "X@\xeb\b\x90\xf\x32mcr\xa5\xca\xd3\x3\x1e\x16\xb1\x30\xc4\x83k\x2{B\xd8" 
  "\xa2\b\aS\xec\xa1\ffs&]\x15\xb6\xc8\xc5\x32\x46\x8a\x8c\x66L\xa3\xa2\xd0" 
  "\xa8\xc6\x36\xea\x89\x8dn\x8c#\x1ch@\xc7:\xda\xf1\x8ex\xcc\xa3\x1e\x65" 
  "\x10\x2\x0;",
  NULL } ; /* --- end-of-image14[] --- */
/* ---
 * image15[] contains a 1870-byte gif rendering of expression
 * \usepackage{color}\color{red}\footnotesize\fparbox{
 * (15) Can't emit cached image:\\check permissions.\\
 * See mathtex.html\#message15}
 * ---------------------------------------------------------- */
#define	IMAGETYPE15 1			/* 1=gif, 2=png */
#define	IMAGESIZE15 1870		/* #bytes in image15[] */
static	unsigned char *image15[] = {
  (unsigned char *) "GIF89a\xcd\x0\x38\x0\x84\x0\x0\xff\xff\xff\xff\x0\x0" 
  "\xff\xff\xff\xff\x99\x99\xff\x64\x64\xff\xb8\xb8\xff--\xff\b\b\xff\xdb" 
  "\xdb\xff\xe\xe\xff}}\xff  \xffOO\xff\x3\x3\xff\x16\x16\xff==\xff\x1\x1" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0" 
  "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0!\xf9\x4" 
  "\x1\x0\x0\x0\x0,\x0\x0\x0\x0\xcd\x0\x38\x0\x0\x5\xfe` \x8e\x64i\x9eh\xaa" 
  "\xael\xeb\xbep,\xcf\x30`\xdfx\xae\xef|\xef\xff\xc0\xa0pH,\x1a\x8f\x41" 
  "\x11r\xc9l:\x9f\xd0\xe8P)\xadZ\xaf\xd8\xec\x91\xaa\xedz\xbf\xe0%7L.\x9b" 
  "\xc1\x63\xde\x80 D<\x82\x5\xc5\xc0V \x16\x10g$BQo\xf3\xf3<i:\x5\x6\x37" 
  "\x84s6\f\xe\x6\v\f6\x3\v>\x3\t\xf\n\x4\v\v\x85\x43\a\t\x86P\x94\x9eP\x5" 
  "\t\x9ap\xa4:\xa0g\x82\x39\ax\x0\f\f\r\n7\x6\t\ao7\v\x88:\x3\r\xae\x36" 
  "\xa7\x43\x5\x8e\x36\xa5M\x4\xbb\xc6N\x6\xca\?\xcc:\xc8y\xab\x37\x93\xac" 
  "\xb3\xc5;\x3\xe<\a\xc4\xd4\xcd\?\xd7\xf\xe0M\xe3R\xcf\x43\xe8\x80\x39" 
  "\xd3\xc5\xca\a\xd7\x0\x6\n\x96\xec;\x5\x1\xbf\x37\xb3\f\x4\x4\x9a\x4\x2," 
  " \xa0\xe0@\x1f\x5x\x18@80O\a\x83\x81\v\n\x10\x80\x30\xb0\xe0\x0z\x6\x1(h" 
  "PH!\xc3x8&1r\xd4\xef\x1f\x35R\x8d\xfe\xe4U\xcc\xf8\nb\x1dH\n\x18\x4\xdb" 
  "\xc7\x11\xc0\xc4\x95\x17\v\xf6)Y\xea\xe1\xc8N\xf/\xd5Q\xc7.\x80\xfx\xd6n" 
  "0\xa8\xa3 \xd2\x8d\x3\xbb\xf6\x19\xe5\x91`\xce\x2\\\x6\xe\xb8\xd3\x41" 
  "\xf4\xc6\xc4GZ\xb3\x16\xd3*O\x13\xba\xae\x86\x2\xd4y\xd0\xa9*\x80\xab\x0" 
  "\xf0\xad\xed$\xb6\xacM\b`\x11\xe4\xb3\xc1\x90\xabY\xb2u\xd1\xb9\x85\v`o" 
  "\xca\xaf\x0\x6\x84%\xd7\xe\x0R\x1c",
  (unsigned char *) "\x8f\xd9\xf5q\f\x92\xce\xde\x1c\a\t,\xdaj7\aZ\x0\xb6" 
  "\xe8)0z\xd6\xaci\xce:\x1e\x90\xc5\x61i\xb3j\xcf\xa7\x43\xd3\v\xf0\x9ao" 
  "\xb3\xd2\x9c\xd5\xb5\xd6\x34\xd5\xc0\x1b\xd9\xa3\x7f\x34\x8e\xcc\xf7\xda" 
  "\xa8\x1b\x1\xe2\x11\x7f\xea\xcd\x86\x1b\xd0\xb3pw\xc6\xf1\xacr_\xea\xa7;" 
  "\xe3\xae,o5\xb0\xe8\x85\xea\xd2:}}\xec\xd3\xdb\xd9\xa5\'\x0oc\xa0I\xc7" 
  "\xe4v4N\t\xf9\x9a\x36\xe7\x97\x1@\xd0G\xcd\x17\xf5=d-\x12^v\xd8\xc9\x93" 
  "\x3\x1\r\xdc\xfe\xf0\x86t\f\x86\x37\xc8\x65\x4\x5\xc8\f>\xae\xb0\x81\x1b" 
  "\x82\n\x16\x80\x97m~\xe5vZA6\b\xf8\xca\x81\t\xda\xf0\x86\?\x81L\xc5\xc3%" 
  "J\x19\x10@0\xf\xd4\x41\x1f\x0\b\x94\x98\r%\x96\xe8\x42#T15\xb0\xc0\x46" 
  "\xb2\x0YY\x1\r<\xc0\x86g\xe<\xd0HAA6\xd0\xe4\x93\xb3\x10i\xe4\xe\f\xdc" 
  "\x62\xc0\x0\b\xf0\x18K$U\x8es\x91\x93\xf4\x80)O\x92)=d\xc9\x42 \t\xc9" 
  "\x64\x98Pfy\xd1\x96\x0\x38p\xc0\x9c\v\xe0\x61\x0\x99\x8e$\xd0\x89|*r\xf3" 
  "\xc3\x45\xfa\xc0\xf2\x43\x1cQ\xd1x\x4\x7f\x38Lf\x4\xa2\x38\xe8\xc3(\xa3" 
  "\x83\xe4\x80\a\xa4\x44\xe8\xb3\xc0z\x96$\xb0\r\x1dI\xf4\xb9\x3\x1\xcd\x1" 
  "\x81\xc0\x9e\xeb\x94jj\xe\x3y\xe5\xd4\x14\x9e~Z\xa8\xf\xfPz\xea\xac\x65" 
  "\x88\x46\x8f\x11\x8d\x85\"\xaa\xac\xb4\xf6\xea+\x9f\xbf\x6+,\x1a\xad\xek" 
  "\xec\xb1M\xe4\xda\xe8\x1f\x95\x32\x8b\xec\xb3\x66(k\xc8LB\xfe\x8c\x12" 
  "\x9f\x16\xa9\xfc\x90-\xb4\x64H;\x9e\x11\x9fy\x11\r\x10\xe3r\xdbm\xb1=" 
  "\x84\xeb\x83\xba\xe6\xb6\x1b\x45\x63\"\xa5\xc4H\x84;\xb9\x94\x18J\x8e<C@" 
  "y6LDI-\xbb\x4\x15Q/\x3\xa9uS\x84\x39\x65\xb4Q!\b\xcc\xa3\x19\x8d\xe;\xb0" 
  "p\xbf\xf3\xf4\x63\x93@\xf4\x42\xdc\x9a\xbb\xb8\xa2\x1b\x97Z\x0\xb0\xd5" 
  "\xddV\x88)&W\xc8t\x15",
  (unsigned char *) "\xf2\xe3\xe\x8cX\x86G\xc9\x61%\x18\xeb\xc8\x34\xe3\x66" 
  "\xc0\x91\v\xe2l\x97\x2\x1b\xc6\x19\x1d`\xe1\xe9\xcc\x31\x11\xed\xd4\xf6" 
  "\xad]\xc0\xd1\xe6\x9dJ\xcb\x1d\xed\xd8o\xf0\xcc\x36\x9dv\xe9\x15\x32\xc0" 
  "\x42\x33_}\x8b\x9d\x85$\xb0j-T\'\x86\x35\xaf\x43\x17\x95\xee\xd2\xb8\xf1" 
  "+^1\xeb\xf9\xd7!\x87\xfcN\xdd\xe0V\x5\f#g\\v/\xe6\xd8\xd7z\xdbU\xb7\"K" 
  "\x97\xed\x43;\x14\xf6\x1b\x36\x86&\x16n\x93]\xfl\xea\x99S\'#\x1e\xb2\xdc" 
  "Uoe@\x1f\t^nC\xe6\x1d\xd9\xe8@\xbe\xfe\xa7i\xe@\x89(\n\xde\x43\x63]^\xa9" 
  "\xa6\x98w*I\x92\x95_F\xfd\xa2\xa2\xdd\x11\x94\xc0\x91\x63\xba\xe$1k\xae" 
  "\xe%#k,\xa8\v\x1\x95\xb0\x9e\x64u`\n\t<\xf1\xc0\x90j\xba\xe\xca\x92\x1d" 
  "\x97\xa4\xe9\x14\x42;\xa7MLz\x83\xf6<\\O\xbd\xf4\xcf\x17\xe6q\x18\xec" 
  "\x86/\xb8\xb7Y(\xc0\fw\xe6\?\x8f~\xfb\xf0\x7f\xf1~\xfc\xf4\x63\x91+\xa1" 
  "\xd3\x97\xb1\x87\xf7z8\xdb\xff\xf5\bp\x5\xf8\x9e\x85:G\x10\"pY\xe8\x83" 
  "\xb5\xeeq\x84\x5\x32\xd0\x14\xcd\x88\x88MpG\xab\x43(e\x11\x33\x2V\xf7V" 
  "\x93%\xf2\x39\x8d:H\b\xd7\xb5`\x83\x8a\x10\r\x10\f\xb0\x90\x5-l\x81\x8b" 
  "\xd3y\x8cg\xbf\x18\x61\x14\xcc\x81\x1a\x5\xc9\x90\a\x9f\xa1\x61\x10\xba" 
  "\x42\x88\x10\t+27\x14\xdfQ \xd0\x10\xa5\xd8K`\xb4;\x98\x45\x30\xb2\x13" 
  "\x7fh\xc2#\r\x99\x97N^\xb1\x90\x86 Q&\x9d\xd8\xd7\xaa\x8a\xb1\x92\x9dT" 
  "\xf1L8a\xfe\x62\rC6\x87\x1\xb4P\x89<\x9a\x62K\x84\xd2\xb0\x8d\xb5\xf1" 
  "\x61\xafp\xa2\x11\x7f\xb2\x46\t\x16\x87\x16\xf4\xa0\xa0\x6\xd3\xd5\x0" 
  "\x11\xb0\x1\x66\x30\xe3\n`\x80\x6\f\xab`\xa5\x14\x81\xc9N {\xb1\x87P\xd5" 
  "\f\x91\x88\x1c\xa4\x87\xe2\xc2\x8c\xac\x30\x83!g\x91\xa4]`v3\x13\xc9\x43" 
  "h\x83\xc1\x85\x61\x1c\x11\xc8;&\x82",
  (unsigned char *) ")[\x84\xde\xf8\xb6\xf7\x80|$-io\x93\x8e\x46\x34\x43" 
  "\xa0\xb9\x81&j\xc1\xb1I\x3\xf4\x38I\xd4\xd8\x92(\b\xd8\x94\xf3\xc2\x86" 
  "\x34\\\x6@kY\x1b\xdb>hi\x83\xde@M4*jZa\xf8\'D\x1e\xdc\xea\x6\xb2\xe0W" 
  "\xdcHH\xcc\xf5\x84\x8d=\xdf\xdc\x66\x96\x1cW\xa0\xe9T\x87\x98\xb8\xd9" 
  "\x83\x2\xc6\x41\xfL]cn\xfc\xfa\xdb\xdd\xe4I\x16o\xa2\xc3=\x9a\xd8&e\xe8@" 
  "\xaa\xe4\xb8\xb0\a\xea\xc3\x81/$g$\x1b\xb5\xf0h\xdb\x91\xd0\x80\f4\xb7" 
  "\x9b\x19\x14\x62q\xc2\x45\xe9\x64\xf9\x8c\x85\xa2\x93\x61\x18\xa1\xc7" 
  "\xd1UD\xd3K}\x19Tt\x99\xc3\x9c\x46\x14:\"\x1c\x10\xf4)\xf6\xd9\x94^(\xd5" 
  "\xe\x5\x90\x82\x1e\x9f+\x6\x9er\x97\xc1\x91\x42IHn\xeaQ$\xa4\x44\x90\xe4" 
  "\x89\x89\xa7\x34\x85\x5\x45.\x16\x11=i\xc4\xa7*\x8cK\x91\"tS\xa4\xc6\x63" 
  "S\xe4\xb4)\x9b\xa6\x1a\xd4\xe5\t/x;z\x93\x8f\xe2\x34\xa7\x3\xd4)\xa8\xaf" 
  "p\x11\x8c\x64\xe4H\x1c\xb4#\x80\x1a\x41\bf\xd6\xaa\x87\x1d\x90M\x1f\xd4" 
  "\xac\xd4\x11\xcc\xe8\xc3\x6:\xc7Pw\xe5\x8f\xa5\x30\x45\x0M\xe9J\rj\x1d" 
  "\xdc*\xebg\x85\a\x94\xf1\xa0`HU\xbfR\xe9\x84\xf9\x11\xb6\t\xd7\xf0_\x18l" 
  "\xc5\xbe\x64\r\xf6\xb1\x98\x95\x82\x63\x33\xcb\xd9\x8eu\xf6\xb3\xf6\xbb," 
  "hG\xcb*\xd2\x9a\xb6\xb1\x34H\xadjW\xcb\xda\xd6\xba\xf6\xb5\x31\b\x1\x0;",
  NULL } ; /* --- end-of-image15[] --- */
/* --------------------------------------------------------------------------
Other Allocations and Declarations
-------------------------------------------------------------------------- */
/* ---
 * aggregate array of embedded images
 * ---------------------------------- */
static	unsigned char **imagetable[] = { NULL,
  image1,     image2,     image3,     image4,     image5,     image6,
  image7,     image8,     image9,     image10,    image11,    image12,
  image13,    image14,    image15,    NULL };
int	imagesizes[] = { 0,
  IMAGESIZE1, IMAGESIZE2, IMAGESIZE3, IMAGESIZE4, IMAGESIZE5, IMAGESIZE6,
  IMAGESIZE7, IMAGESIZE8, IMAGESIZE9, IMAGESIZE10,IMAGESIZE11,IMAGESIZE12,
  IMAGESIZE13,IMAGESIZE14,IMAGESIZE15,0 };
int	imagetypes[] = { 0,
  IMAGETYPE1, IMAGETYPE2, IMAGETYPE3, IMAGETYPE4, IMAGETYPE5, IMAGETYPE6,
  IMAGETYPE7, IMAGETYPE8, IMAGETYPE9, IMAGETYPE10,IMAGETYPE11,IMAGETYPE12,
  IMAGETYPE13,IMAGETYPE14,IMAGETYPE15,0 };
/* ---
 * other variables
 * --------------- */
static	unsigned char image[8192];	/* returned image */
unsigned char **imagestrings = NULL;	/* image1, image2, etc */
int	istring = 0,			/* imagestrings[] index */
	imagesz = 0;			/* sizeof entire image */
/* ---
 * look up requested image (if we have it)
 * --------------------------------------- */
if ( nbytes != NULL ) *nbytes = 0;	/* init for error */
if ( imagenum<1 || imagenum>MAXEMBEDDED ) imagenum=1; /*out-of-bounds check*/
imagestrings = imagetable[imagenum];	/* ptr to array of image strings */
imagesz = imagesizes[imagenum];		/* total #bytes in image */
if ( imagestrings == NULL ) imagesz = 0; /* sanity check */
if ( nbytes != NULL ) *nbytes = imagesz; /* caller wants #bytes in image */
if ( imgtype != NULL ) *imgtype = imagetypes[imagenum]; /* and image type */
/* ---
 * build up images from constituent strings
 * ---------------------------------------- */
if ( imagesz > 8192 ) imagesz = 8192;	/* don't overflow buffer */
memset(image,0,imagesz);		/* zero out returned image buffer */
while ( imagesz > 0 ) {			/* still need more bytes in image */
  unsigned char *string = imagestrings[istring]; /*so get next image string*/
  int	thissz = min2(stringsz,imagesz); /*entire string or image's tail end*/
  if ( string == NULL ) break;		/* looks like a program error */
  memcpy(image+(istring*stringsz),string,thissz); /* concat string to image*/
  imagesz -= thissz;			/* fewer remaining bytes */
  istring++;				/* get them from remaining strings */
  } /* --- end-of-while(imagesz>0) --- */
return ( image );
} /* --- end-of-function embeddedimages() --- */
/* --- end-of-file mathtex.c --- */
