summaryrefslogtreecommitdiff
path: root/support/mathtex/mathtex.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/mathtex/mathtex.c
Initial commit
Diffstat (limited to 'support/mathtex/mathtex.c')
-rw-r--r--support/mathtex/mathtex.c6620
1 files changed, 6620 insertions, 0 deletions
diff --git a/support/mathtex/mathtex.c b/support/mathtex/mathtex.c
new file mode 100644
index 0000000000..787ea227e0
--- /dev/null
+++ b/support/mathtex/mathtex.c
@@ -0,0 +1,6620 @@
+/****************************************************************************
+ *
+ * Copyright(c) 2007-2012, 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
+ * presentwd(nsub) determines pwd, nsub dirs up
+ * rrmdir(path) rm -r path
+ * rewritecache(cachefile,maxage) write cachefile with imageinfo
+ * 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
+ * isnumeric(s) determine if s is an integer
+ * evalterm(store,term) evaluate numeric value of expression
+ * getstore(store,identifier)return value corresponding to ident
+ * timewaitfor(whundredths)delay execution for hundredths of sec
+ * 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
+ * calendar(year,month,day) formats one-month calendar string
+ * 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
+ * -DPDFLATEX=\"/usr/share/texmf/bin/pdflatex\" path to pdflatex
+ * -DDVIPNG=\"/usr/share/texmf/bin/dvipng\" path to dvipng
+ * -DDVIPS=\"/usr/share/texmf/bin/dvips\" path to dvips
+ * -DPS2EPSI=\"/usr/bin/ps2epsi\" path to ps2epsi
+ * -DCONVERT=\"/usr/bin/convert\" path to convert
+ * -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
+ * 04/06/11 J.Forkosh Version 1.04
+ * 11/15/11 J.Forkosh Version 1.05
+ * 10/26/14 J.Forkosh Most recent change (see REVISIONDATE below)
+ *
+ ****************************************************************************/
+
+/* -------------------------------------------------------------------------
+Program ID
+-------------------------------------------------------------------------- */
+#define VERSION "1.05" /* mathTeX version number */
+#define REVISIONDATE "26 Oct 2014" /* date of most recent revision */
+#define COPYRIGHTDATE "2007-2014" /* copyright date */
+
+/* -------------------------------------------------------------------------
+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(PDFLATEX)
+ #define ISPDFLATEXSWITCH 1 /* have -PDFDLATEX=\"path/latex\" */
+#else
+ #define ISPDFLATEXSWITCH 0 /* no -PDFDLATEX switch */
+ #define PDFLATEX "/usr/share/texmf/bin/pdflatex" /* default pdflatex path*/
+#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(PS2EPSI)
+ #define ISPS2EPSISWITCH 1 /* have -DPS2EPSI=\"path/ps2epsi\" */
+#else
+ #define ISPS2EPSISWITCH 0 /* no -DPS2EPSI switch */
+ #define PS2EPSI "/usr/bin/ps2epsi" /* default path to ps2epsi */
+#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
+#if !defined(WAIT) /* -DWAIT=\"50\" for half-second */
+ #define WAIT "\000" /* default to no wait */
+#endif
+#if !defined(NOWAIT) /* comma-separated list of referer's*/
+ #define NOWAIT "\000" /* default to everyone waits */
+#endif
+/* --- paths, as specified by -D switches, else from whichpath() --- */
+static char latexpath[256] = LATEX, pdflatexpath[256] = PDFLATEX,
+ dvipngpath[256] = DVIPNG, dvipspath[256] = DVIPS,
+ ps2epsipath[256] = PS2EPSI, convertpath[256] = CONVERT,
+ timelimitpath[256] = TIMELIMIT;
+/* --- source of path info: 0=default, 1=switch, 2=which, 3=locate --- */
+static int islatexpath=ISLATEXSWITCH, ispdflatexpath=ISPDFLATEXSWITCH,
+ isdvipngpath=ISDVIPNGSWITCH, isdvipspath=ISDVIPSSWITCH,
+ isps2epsipath=ISPS2EPSISWITCH, isconvertpath=ISCONVERTSWITCH,
+ istimelimitpath=ISTIMELIMITSWITCH;
+/* ---
+ * home path pwd of running executable image,
+ * and http_referer,etc information
+ * ------------------------------------------- */
+static char homepath[256] = "\000"; /* path to executable image */
+static char this_referer[256];
+/* ---
+ * 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 */
+/* ---
+ * working directory for temp files -DWORK=\"path/\"
+ * ------------------------------------------------- */
+#if !defined(WORK)
+ #define WORK "\000" /* relative to mathtex.cgi */
+#endif
+static char workpath[256] = WORK; /* path to temp file working dir */
+/* ---
+ * latex method info specifying latex,pdflatex
+ * ------------------------------------------- */
+#if ISLATEXSWITCH==0 && ISPDFLATEXSWITCH==1
+ #define LATEXMETHOD 2
+#elif !defined(LATEXMETHOD)
+ #define LATEXMETHOD 1
+#endif
+static int latexmethod = LATEXMETHOD; /* 1=latex, 2=pdflatex */
+static int ispicture = 0; /* true for picture environment */
+/* ---
+ * 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 */
+/* ---
+ * emit depth below baseline (for vertical centering)
+ * -------------------------------------------------- */
+#if defined(DEPTH)
+ #define ISDEPTH 1
+#else
+ #define ISDEPTH 0
+#endif
+static int isdepth = ISDEPTH; /* true to emit depth */
+/* ---
+ * 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 */
+#if !defined(HOST_SHOWAD)
+ #define HOST_SHOWAD "\000" /* show ads on all hosts */
+#endif
+/* ---
+ * 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
+
+/* ---
+ * latex wrapper document template (default, isdepth=0, without depth)
+ * ------------------------------------------------------------------- */
+static char latexdefaultwrapper[MAXEXPRSZ+16384] =
+ "%%% url: %%referer%%\n" /* http_referer submitting request */
+ "\\documentclass[10pt]{article}\n" /*[fleqn] omitted*/
+ "\\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"
+ "%%pagestyle%%\n"
+ "%%previewenviron%%\n"
+ "\\begin{document}\n"
+ /*"\\setlength{\\mathindent}{0pt}\n"*/ /* only with [fleqn] option */
+ "\\setlength{\\parindent}{0pt}\n"
+ #if 0
+ "%%%\\renewcommand{\\input}[1]" /* don't let users \input{} */
+ "{\\mbox{[[$\\backslash$input\\{#1\\} illegal]]}}\n"
+ #endif
+ #if defined(NEWCOMMAND) /* cc -DNEWCOMMAND=\"filename\" */
+ #include NEWCOMMAND /* filename with \newcommand{}'s */
+ #endif /* or anything for the document */
+ "\\newcommand{\\amsatop}[2]{{\\genfrac{}{}{0pt}{1}{#1}{#2}}}\n"
+ "\\newcommand{\\twolines}[2]{{\\amsatop{\\mbox{#1}}{\\mbox{#2}}}}\n"
+ "\\newcommand{\\fs}{{\\eval{fs}}}\n" /* \eval{} test */
+ "%%fontsize%%\n"
+ "%%setlength%%\n"
+ "%%beginmath%% "
+ "%%expression%% \n" /* \n in case expression contains %*/
+ " %%endmath%%\n"
+ "\\end{document}\n";
+
+/* ---
+ * latex wrapper document template (optional, isdepth=1, with depth)
+ * see http://www.mactextoolbox.sourceforge.net/articles/baseline.html
+ * for discussion of this procedure
+ * ------------------------------------------------------------------- */
+static char latexdepthwrapper[MAXEXPRSZ+16384] =
+ "%%% url: %%referer%%\n" /* http_referer submitting request */
+ "\\documentclass[10pt]{article}\n" /*[fleqn] omitted*/
+ "\\usepackage[latin1]{inputenc}\n"
+ "\\usepackage{amsmath}\n"
+ "\\usepackage{amsfonts}\n"
+ "\\usepackage{amssymb}\n"
+ "%%%\\usepackage{calc}\n"
+ #if defined(USEPACKAGE) /* cc -DUSEPACKAGE=\"filename\" */
+ #include USEPACKAGE /* filename with \usepackage{}'s */
+ #endif /* or anything for the preamble */
+ "%%usepackage%%\n"
+ #if defined(NEWCOMMAND) /* cc -DNEWCOMMAND=\"filename\" */
+ #include NEWCOMMAND /* filename with \newcommand{}'s */
+ #endif /* or anything for the document */
+ "\\newcommand{\\amsatop}[2]{{\\genfrac{}{}{0pt}{1}{#1}{#2}}}\n"
+ "\\newcommand{\\twolines}[2]{{\\amsatop{\\mbox{#1}}{\\mbox{#2}}}}\n"
+ "\\newcommand{\\fs}{{\\eval{fs}}}\n" /* \eval{} test */
+ "%%pagestyle%%\n"
+ "%%previewenviron%%\n"
+ "\\newsavebox{\\mybox}\n"
+ "\n"
+ "\\newlength{\\mywidth}\n"
+ "\\newlength{\\myheight}\n"
+ "\\newlength{\\mydepth}\n"
+ "\n"
+ /*"\\setlength{\\mathindent}{0pt}\n"*/ /* only with [fleqn] option */
+ "\\setlength{\\parindent}{0pt}\n"
+ "%%fontsize%%\n"
+ "%%setlength%%\n"
+ "\n"
+ "\\begin{lrbox}{\\mybox}\n"
+ "%%beginmath%% "
+ "%%expression%% \n" /* \n in case expression contains %*/
+ " %%endmath%%\n"
+ "\\end{lrbox}\n"
+ "\n"
+ "\\settowidth {\\mywidth} {\\usebox{\\mybox}}\n"
+ "\\settoheight{\\myheight} {\\usebox{\\mybox}}\n"
+ "\\settodepth {\\mydepth} {\\usebox{\\mybox}}\n"
+ "\n"
+ "\\newwrite\\foo\n"
+ "\\immediate\\openout\\foo=\\jobname.info\n"
+ " \\immediate\\write\\foo{depth = \\the\\mydepth}\n"
+ " \\immediate\\write\\foo{height = \\the\\myheight}\n"
+ " \\addtolength{\\myheight} {\\mydepth}\n"
+ " \\immediate\\write\\foo{totalheight = \\the\\myheight}\n"
+ " \\immediate\\write\\foo{width = \\the\\mywidth}\n"
+ "\\closeout\\foo\n"
+ "\n"
+ "\\begin{document}\n"
+ "\\usebox{\\mybox}\n"
+ "\\end{document}\n";
+/* ---
+ * latex wrapper used
+ * ------------------ */
+static char *latexwrapper = /* with or without depth */
+ ( ISDEPTH? latexdepthwrapper : latexdefaultwrapper );
+/* ---
+ * elements from \jobname.info to be prepended to graphics file
+ * ------------------------------------------------------------ */
+#define IMAGEINFO struct imageinfo_struct /*"typedef" for imageinfo struct*/
+#define MAXIMAGEINFO 32 /* max 32 image info elements */
+IMAGEINFO {
+ char *identifier; /* identifier in \jobname.info */
+ char *format; /* format to write in graphics file*/
+ double value; /* value of identifier */
+ char units[32]; /* units of value, e.g., "pt" */
+ int algorithm; /* value conversion before writing */
+ } ; /* --- end-of-store_struct --- */
+static IMAGEINFO imageinfo[MAXIMAGEINFO] = {
+ { "depth", "Vertical-Align:%dpx\n", -9999., "", 1 }, /* below baseline */
+ { NULL, NULL, -9999., "", -9999 } /* end-of-imageinfo */
+ } ; /* --- end-of-imageinfo[] --- */
+
+/* -------------------------------------------------------------------------
+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 plastchar(s) (isempty(s)?NULL:((s)+(strlen(s)-1)))
+#define lastchar(s) (isempty(s)?'\000':*(plastchar(s)))
+/* --- 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)++
+/* --- 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'; } }
+/* --- 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 ) \
+ {strsqueeze((thisstr),thislen);} } else
+/* --- strcpy(s,s+n) using memmove() (also works for negative n) --- */
+#define strsqueeze(s,n) if((n)!=0) { if(!isempty((s))) { \
+ int thislen3=strlen(s); \
+ if ((n) >= thislen3) *(s) = '\000'; \
+ else memmove((s),(s)+(n),1+thislen3-(n)); }} else /*user supplies ;*/
+/* --- strsqueeze(s,t) with two pointers --- */
+#define strsqueezep(s,t) if(!isempty((s))&&!isempty((t))) { \
+ int sqlen=strlen((s))-strlen((t)); \
+ if (sqlen>0 && sqlen<=999) {strsqueeze((s),sqlen);} } else
+/* --- 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" };
+
+/* -------------------------------------------------------------------------
+store for evalterm() [n.b., these are stripped-down funcs from nutshell]
+-------------------------------------------------------------------------- */
+#define STORE struct store_struct /* "typedef" for store struct */
+#define MAXSTORE 100 /* max 100 identifiers */
+STORE {
+ char *identifier; /* identifier */
+ int *value; /* address of corresponding value */
+ } ; /* --- end-of-store_struct --- */
+static STORE mathtexstore[MAXSTORE] = {
+ { "fontsize", &fontsize }, { "fs", &fontsize }, /* font size */
+ /*{ "mytestvar", &mytestvar },*/
+ { NULL, NULL } /* end-of-store */
+ } ; /* --- end-of-mimestore[] --- */
+
+
+/* ==========================================================================
+ * 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,etc*/
+ *pdirective = NULL; /* ptr to char after \directive */
+int validate(); /* remove \input, etc */
+int advertisement(), crc16(); /*wrap expression in advertisement*/
+int evalterm(); /* preprocess \eval{expression} */
+char *adtemplate = NULL; /* usually use default message */
+char *host_showad = HOST_SHOWAD; /* show ads only on this host */
+char *nomath(); /* remove math chars from string */
+/* --- referer initialization variables --- */
+char *http_referer = getenv("HTTP_REFERER"), /* referer using mathTeX */
+ *mathtex_host = getenv("HTTP_HOST"), /* http host for mathTeX */
+ *server_name = getenv("SERVER_NAME"), /* server hosting mathTeX */
+ *http_host = (!isempty(mathtex_host)?mathtex_host: /*match host*/
+ (!isempty(server_name)?server_name:(NULL))); /* or server_name */
+int isvalidreferer = 1; /* can this referer use mathTeX? */
+int whundredths = 0; /* #hundredths-secs to delay image */
+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)*/
+ *calendar(); /* for \calendar{yyyy,mm,dd} string*/
+int emitembedded(); /* in case latex can't run */
+int timelimit(); /* just to check stub or built-in */
+int timewaitfor(); /* impose a delay on query replies */
+int iscolorpackage = 0, /* true if \usepackage{color} found*/
+ iseepicpackage = 0, /* true if \usepackage{eepic} found*/
+ ispict2epackage = 0, /* true if \usepackage{pict2e}found*/
+ ispreviewpackage = 0; /* true if \usepackage{preview} */
+/* --- image rendering --- */
+int mathtex(); /* generate new image using LaTeX */
+/* --- image caching --- */
+int rewritecache(); /* rewrite cachefile with imageinfo*/
+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 */
+char *presentwd(), *pwdpath=NULL; /* home pwd for relative file paths */
+int mathlog(); /* log requests */
+/* --- messages --- */
+char *copyright1 = /* copyright, gnu/gpl notice */
+ "+-----------------------------------------------------------------------+\n"
+ "|mathTeX vers " VERSION ", Copyright(c) " COPYRIGHTDATE
+ ", 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 $\\twolines{mathTeX version " VERSION
+ ",\\ \\ revised " REVISIONDATE "}{Copyright (c) " COPYRIGHTDATE
+ ", John Forkosh Associates, Inc.}$}\\\\ \\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{$\\twolines{\\textbf{%%referer%%}}"
+ "{\\textbf{is not authorized to use mathTeX on this server}}$}",
+ /* --- message#1 ("provide http_referer" message) --- */
+ "\\parstyle\\usepackage{color}\\small\\color{red}\\noindent "
+ "\\fbox{$\\twolines{\\textbf{To use the public math\\TeX{} server,}}"
+ "{\\textbf{please provide your HTTP\\_REFERER}}$}",
+ /* --- message#2 ("production use" message) --- */
+ "\\parstyle\\usepackage{color}\\small\\color{red}\\noindent "
+ "\\fbox{$\\twolines{\\textbf{For production use,"
+ " please install mathtex.cgi on}}"
+ "{\\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 */
+if ( (pwdpath = presentwd(0)) /* pwd where exectuable resides */
+!= NULL ) /* got it */
+ strcpy(homepath,pwdpath); /* save it for mathtex() later */
+strninit(this_referer,((!isempty(http_referer))?http_referer:">>none<<"),255);
+strreplace(this_referer,"\n"," ",0,0); /* get rid of newlines */
+strreplace(this_referer,"\r"," ",0,0); /* ditto cr's, just in case */
+/* ---
+ * 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 *addr = getenv("SERVER_ADDR"); /* additional getenv("") results */
+ if ( !isempty(http_host) || 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 */
+ {strsqueeze(expression,((int)(delim-expression)+1));} /*squeeze name=*/
+ 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 for http://>>none<< */
+ { 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 invalid 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 */
+/* --- wait or substitute invalid referer message if referer is invalid --- */
+whundredths = 0; /* no wait specified yet */
+if ( !isvalidreferer ) { /* invalid referer detected */
+ if ( msgnumber > 100 ) { /* wait msgnumber-100 tenths sec */
+ whundredths = 10*(msgnumber-100); /* hundredths = 10*tenths */
+ isvalidreferer = 1; } /* reset valid referer, but wait */
+ else { /* or don't process request at all */
+ 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 */
+/* ---
+ * query delay
+ * -------------- */
+if ( isquery ) /* have a query */
+ if ( !isempty(WAIT) || whundredths>0 ) { /* wait imposed on queries */
+ if ( whundredths < 1 ) whundredths = atoi(WAIT); /*#hundredths of a sec*/
+ if ( !isempty(NOWAIT) ) /* have -DNOWAIT=\",,,\" referers */
+ if ( isstrstr(http_referer,NOWAIT,0) ) /* no wait for this refererer */
+ whundredths = 0; /* so reset wait time */
+ if ( whundredths > 0 ) /* if we have a wait */
+ timewaitfor(whundredths); /* return after waiting */
+ } /* --- end-of-if(!isempty(WAIT)) --- */
+/* ---
+ * 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 */
+ setpaths(0); /* show _all_ 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), /* pdflatex path */
+ "-DPDFLATEX=$\\backslash$\"%s$\\backslash$\" \\ (%s)\\\\ \n",
+ pdflatexpath,pathsource[ispdflatexpath]);
+ 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), /* ps2epsi path */
+ "-DPS2EPSI=$\\backslash$\"%s$\\backslash$\" \\ (%s)\\\\ \n",
+ ps2epsipath,pathsource[isps2epsipath]);
+ 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(10*latexmethod+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 picture environment, i.e., \begin{picture}, but don't remove it
+ * ----------------------------------------------------------------------- */
+if ( strstr(expression,"picture") != NULL ) /* picture environment used */
+ ispicture = 1; /* signal picture environment */
+if ( strreplace(expression,"\\nopicture","",0,0) /* remove \nopicture */
+>= 1 ) ispicture = 0; /* user wants to handle picture */
+if ( ispicture ) { /* set picture environment defaults*/
+ imagemethod = 2; /* must use convert, not dvipng */
+ mathmode = 2; /* must be in paragraph mode */
+ isdepth = 0; /* reset default in case it's true */
+ if ( !ISGAMMA ) strcpy(gamma,CONVERTGAMMA); /* default convert gamma */
+ } /* --- end-of-if(ispicture) --- */
+/* ---
+ * check for embedded directives, remove them and set corresponding values
+ * ----------------------------------------------------------------------- */
+/* --- first (re)set default modes required for certain environments --- */
+if ( strstr(expression,"gather") != NULL ) /* gather environment used */
+ mathmode = 2; /* need paragraph style for gather */
+if ( strstr(expression,"eqnarray") != NULL ) /* eqnarray environment used */
+ mathmode = 2; /*need paragraph style for eqnarray*/
+/* --- check for explicit 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 */
+/* --- check for program paths --- */
+if ( getdirective(expression,"\\convertpath",1,0,1,argstring) /*convert path*/
+!= NULL ) { /* \convertpath{/path/to/convert} */
+ strcpy(convertpath,argstring); /*interpret arg as /path/to/convert*/
+ if ( strstr(convertpath,"convert") == NULL ) { /* just path without name */
+ if ( lastchar(convertpath) != '/' ) /* not even a / at end of path */
+ strcat(convertpath,"/"); /* so add a / */
+ strcat(convertpath,"convert"); } /* add name of convert program */
+ isconvertpath = 1; } /* treat like -DCONVERT switch */
+/* --- check for fontsize directives (\tiny ... \Huge) --- */
+if ( 1 || mathmode != 2 ) /*latex sets font size in \parstyle*/
+ for (irep=1; !isempty(sizedirectives[irep]); irep++) /*1=\tiny...10=\Huge*/
+ if ( strstr(expression,sizedirectives[irep]) != NULL ) { /*found \size*/
+ if ( mathmode != 2 ) /* not in paragraph mode */
+ strreplace(expression,sizedirectives[irep],"",1,0); /*remove \size*/
+ fontsize = irep; } /* found \size so set fontsize */
+/* --- check for \depth or \nodepth directive --- */
+if ( strreplace(expression,"\\depth","",0,0) /* \depth requested */
+>= 1 ) { /* found \depth */
+ if ( 1 ) { /* guard */
+ /* ---
+ * note: curl_init() stops at the first whitespace char in $url argument,
+ * so php functions using \depth replace blanks with tildes
+ * ---------------------------------------------------------------------- */
+ /*int ntilde = 0;*/ /* # ~ chars replaced */
+ /*ntilde =*/ strreplace(expression,"~"," ",0,0); }
+ isdepth = 1; /* so reset flag */
+ latexwrapper = latexdepthwrapper; } /* and wrapper */
+if ( strreplace(expression,"\\nodepth","",0,0) /* \nodepth requested */
+>= 1 ) { /* found \nodepth */
+ isdepth = 0; /* so reset flag */
+ latexwrapper = latexdefaultwrapper; } /* and wrapper */
+/* --- 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 */
+/* --- replace \thisyear directive with 2012 --- */
+if ( strstr(expression,"\\thisyear") != NULL ) /* user wants current year */
+ strreplace(expression,"\\thisyear",timestamp(TZDELTA,5),0,0);/*insert year*/
+/* --- replace \calendar directive with calendar string --- */
+while ( strstr(expression,"\\calendar") != NULL ) { /* user wants calendar */
+ int yy=0, mm=0, dd=0; /* current or user-specified cal */
+ mathmode = 2; /* typeset in paragraph mode */
+ strreplace(expression,"\\calendar",calendar(yy,mm,dd),0,1);
+ maxage = 5; /* re-render after 5 secs */
+ iscaching = 0; /* don't cache \calendar */
+ } /* --- end-of-while("\\calendar") --- */
+/* --- check for explicit usepackage directives in expression --- */
+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],127); } /*copy the first*/
+ /* --- check for particular packages --- */
+ if ( strstr(packages[npackages],"color") != NULL ) /*\usepackage{color}*/
+ iscolorpackage = 1; /* set color package flag */
+ if ( strstr(packages[npackages],"eepic") != NULL ) /*\usepackage{eepic}*/
+ iseepicpackage = 1; /* set eepic package flag */
+ if ( strstr(packages[npackages],"pict2e") != NULL ) /* {pict2e} */
+ ispict2epackage = 1; /* set pict2e package flag */
+ if ( strstr(packages[npackages],"preview") != NULL ) /* {preview} */
+ ispreviewpackage = 1; /* set preview package flag */
+ npackages++; } /* bump package count */
+/* --- check for advertisement host and directive (\advertisement) --- */
+if ( !isempty(host_showad) ) /*ad messages only for this referer*/
+ if ( !isempty(http_host) ) /* have HTTP_HOST or SERVER_NAME */
+ if ( strstr(http_host,host_showad) /* see if this host sees ad */
+ == NULL ) /* not mathtex host for ad message */
+ adfrequency = 0; /* turn off advertisements */
+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 latex method directives (\latex or \pdflatex) --- */
+if ( strreplace(expression,"\\latex","",1,0) /*remove occurrences of \latex*/
+>= 1 ) latexmethod = 1; /* found \latex so set latex method */
+if ( strreplace(expression,"\\pdflatex","",0,0) /* remove \pdflatex */
+>= 1 ) latexmethod = 2; /* found \pdflatex so set pdflatex */
+/* --- 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 \eval{}'s in (1)submitted expressions, (2)\newcommand's--- */
+for ( irep=1; irep<=2; irep++ ) { /* 1=expression, 2=latexwrapper */
+ char *thisrep = (irep==1?expression:latexwrapper); /* choose 1 or 2 */
+ while ( (pdirective=getdirective(thisrep,"\\eval",1,0,1,argstring))
+ != NULL ) { /* found \eval{} directive */
+ int ival = (isempty(argstring)?0:evalterm(mathtexstore,argstring));
+ char aval[256]; /* buffer to convert ival to alpha */
+ sprintf(aval,"%d",ival); /* convert ival to alpha */
+ strchange(0,pdirective,aval); } /* replace \eval{} with result */
+ } /* --- end-of-for(irep) --- */
+/* --- 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 */
+if ( npackages < 9 /* have room for one more package */
+&& ispicture ) { /* and using picture environment */
+ if ( latexmethod == 1 ) /* using latex with eepic */
+ if ( !iseepicpackage ) { /* \usepackage{eepic} not specified*/
+ strcpy(packages[npackages],"eepic"); /* \usepackage{eepic} needed */
+ *(packargs[npackages]) = '\000'; /* no optional args */
+ npackages++; } /* bump package count */
+ if ( latexmethod == 2 /* using pdflatex with pict2e */
+ && npackages < 8 ) { /* have room for two more packages */
+ if ( !ispict2epackage ) { /*\usepackage{pict2e} not specified*/
+ strcpy(packages[npackages],"pict2e"); /* \usepackage{pict2e} needed */
+ *(packargs[npackages]) = '\000'; /* no optional args */
+ npackages++; } /* bump package count */
+ if ( !ispreviewpackage ) { /*\usepackage{preview} not specified*/
+ strcpy(packages[npackages],"preview"); /*\usepackage{preview} needed*/
+ strcpy(packargs[npackages],"active,tightpage"); /* set optional args */
+ npackages++; } /* bump package count */
+ } /* --- end-of-if(latexmethod==2) --- */
+ } /* --- end-of-if(ispicture) --- */
+/* ---
+ * 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(4,"home directory",homepath); /* and pwd of executable image */
+ 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 */
+ nbytes = 999; /* signal rewritecache() success */
+ /* --- rewrite dvipng or convert cachefile with extra imageinfo --- */
+ if ( isdepth ) nbytes = /* we have extra imageinfo */
+ rewritecache(makepath(NULL,md5hash,extensions[imagetype]),maxage);
+ /* --- emit the newly-generated image --- */
+ if ( nbytes > 0 ) /* mathtex() and rewritecache() ok */
+ 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 --- */
+ isdepth = 0; /* no imageinfo in embedded images */
+ 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
+-------------------------------------------------------------------------- */
+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 */
+ { " \\noindent $\\displaystyle ", " \\noindent $ ", " " },
+ *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" */
+char *presentwd(), *pwdpath=NULL; /* pwd for file paths */
+int isworkpath = 0; /* true if cd'ed to working dir */
+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 cd to ~workpath/tempdir/
+-------------------------------------------------------------------------- */
+msgnumber = 0; /* no error to report yet */
+if ( !isempty(workpath) ) /*have a working dir for temp files*/
+ if ( isdexists(workpath) ) /* if working directory exists */
+ if ( chdir(workpath) /* cd to working directory */
+ == 0 ) isworkpath=1; /* signal cd to workpath succeeded */
+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
+-------------------------------------------------------------------------- */
+/* --- embed http_referer submitting request --- */
+strreplace(latexwrapper,"%%referer%%",this_referer,1,0);
+/* --- usually replace %%pagestyle%% with \pagestyle{empty} --- */
+ if ( !ispicture /* not \begin{picture} environment */
+ || latexmethod == 1 ) /* or using latex/dvips/ps2epsi */
+ strreplace(latexwrapper,"%%pagestyle%%","\\pagestyle{empty}",1,0);
+/* --- replace %%previewenviron%% if a picture and using pfdlatex --- */
+ if ( ispicture /* have \begin{picture} environment */
+ && latexmethod == 2 ) /* and using pdflatex/convert */
+ strreplace(latexwrapper,"%%previewenviron%%",
+ "\\PreviewEnvironment{picture}",1,0);
+/* --- 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 %%setlength%% in template for pictures when necessary --- */
+ if ( ispicture /* have \begin{picture} environment */
+ && strstr(expression,"\\unitlength") == NULL ) /* but no \unitlength */
+ strreplace(latexwrapper,"%%setlength%%", /* so default it to 1 inch */
+ "\\setlength{\\unitlength}{1.0in}",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(10*latexmethod+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 --- */
+if ( latexmethod != 2 ) /* not explicitly using pdflatex */
+ strcpy(subcommand,makepath("",latexpath,NULL)); /* running latex program */
+else /* explicitly using pdflatex */
+ strcpy(subcommand,makepath("",pdflatexpath,NULL)); /* running pdflatex */
+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 ( latexmethod != 2 ) /* ran latex */
+ if ( !isfexists(makepath("","latex",".dvi")) ) /* but no latex dvi */
+ sys_stat = (-1); /* signal that latex failed */
+if ( latexmethod == 2 ) /* ran pdflatex */
+ if ( !isfexists(makepath("","latex",".pdf")) ) /* but no pdflatex pdf */
+ sys_stat = (-1); /* signal that pdflatex failed */
+if ( sys_stat == (-1) ) { /* system() or pdf/latex failed */
+ if ( !iserror ) { /* don't recurse if errormsg fails */
+ iserror = 1; /* set error flag */
+ isdepth = ispicture = 0; /* reset depth, picture mode */
+ 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()) --- */
+/* -------------------------------------------------------------------------
+Extract image info from latex.info (if available)
+-------------------------------------------------------------------------- */
+if ( isdepth ) /* image info requested */
+ if ( isfexists(makepath("","latex",".info")) ) { /* and have latex.info */
+ FILE *info = fopen(makepath("","latex",".info"),"r"); /*open it for read*/
+ char infoline[256]; /* read a line from latex.info */
+ if ( info != NULL ) { /* open succeeded */
+ while ( fgets(infoline,255,info) != NULL ) { /* read until eof or error */
+ int i = 0; /* imageinfo[] index */
+ char *delim = NULL; /* find '=' in infoline */
+ trimwhite(infoline); /*remove leading/trailing whitespace*/
+ for ( i=0; imageinfo[i].format!=NULL; i++ ) /* all imageinfo[] fields */
+ if ( strstr(infoline,imageinfo[i].identifier) == infoline ) {
+ imageinfo[i].value = (-9999.); /* init value to signal error */
+ *(imageinfo[i].units) = '\000'; /* init units to signal error */
+ if ( (delim=strchr(infoline,'=')) == NULL ) break; /* no '=' delim */
+ memmove(infoline,delim+1,strlen(delim)); /* get value after '=' */
+ trimwhite(infoline); /*remove leading/trailing whitespace*/
+ imageinfo[i].value = strtod(infoline,&delim); /* convert to integer */
+ if ( !isempty(delim) ) { /* units, e.g., "pt", after value */
+ memmove(infoline,delim,strlen(delim)+1); /* get units field */
+ trimwhite(infoline); /*remove leading/trailing whitespace*/
+ strninit(imageinfo[i].units,infoline,16); } /* copy units */
+ break; /* don't check further identifiers */
+ } /* --- end-of-if(strstr(infoline,identifier)) --- */
+ } /* --- end-of-while(fgets()!=NULL) --- */
+ fclose(info); /* close info file */
+ } /* --- end-of-if(info!=NULL) --- */
+ } /* --- end-of-if(isfexists("latex.info")) --- */
+/* -------------------------------------------------------------------------
+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 */
+ *giffile = '\000'; /* start with empty string */
+ if ( isworkpath ) { /* we've cd'ed to a working dir */
+ if ( !isempty(homepath) ) /* have a homepath */
+ strcpy(giffile,homepath); /* so just use it */
+ else { /* home path not available */
+ int nsub = (isworkpath?2:1); /* up two dirs for workdir, else 1 */
+ if ( iserror ) nsub++; /* and another if in error subdir */
+ if ( (pwdpath=presentwd(nsub)) /* get path nsub dirs up from pwd */
+ != NULL ) /* got it */
+ strcpy(giffile,pwdpath); } /* use it as giffile prefix */
+ } /* --- end-of-if(isworkpath) --- */
+ if ( isempty(giffile) ) { /* haven't constructed giffile */
+ if ( iserror ) strcat(giffile,"../"); /*up to temp if in error subdir*/
+ strcat(giffile,"../"); /* up to home or working dir */
+ if ( isworkpath ) /* temp under working dir */
+ strcat(giffile,"../"); /* up from working to home dir */
+ } /* --- end-of-if(isempty(giffile)) --- */
+ gifpathlen = strlen(giffile); /* #chars in ../ or ../../ prefix */
+ } /* --- end-of-if(isempty(outfile)||etc) --- */
+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
+ *------------------------------------------------------- */
+ if ( latexmethod != 2 ) { /* only if not using pdflatex */
+ 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 */
+ if ( !ispicture ) strcat(command," -E"); /*add -E switch if not picture*/
+ strcat(command," "); /* add a blank */
+ strcat(command,makepath("","latex",".dvi")); /* run dvips on latex.dvi */
+ strcat(command," -o "); /* to produce output file in */
+ if ( !ispicture ) /* when not a picture (usually) */
+ strcat(command,makepath("","dvips",".ps")); /*dvips.ps postscript file*/
+ else /*intermediate temp file for ps2epsi*/
+ strcat(command,makepath("","dvitemp",".ps")); /*temp 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) */
+ /* --- run ps2epsi if dvips ran without -E (for \begin{picture}) --- */
+ if ( sys_stat != (-1) /* system(dvips) succeeded */
+ && ispicture ) { /* and we ran dvips without -E */
+ strcpy(command,makepath("",ps2epsipath,NULL)); /* running ps2epsi */
+ if ( isempty(command) ) { /* no program path to ps2epsi */
+ msgnumber = SYPSFAILED; /* set corresponding error message */
+ goto end_of_job; } /* signal failure and emit error */
+ strcat(command," "); /* add a blank */
+ strcat(command,makepath("","dvitemp",".ps")); /*temp postscript file*/
+ strcat(command," "); /* add a blank */
+ strcat(command,makepath("","dvips",".ps")); /*dvips.ps postscript file*/
+ strcat(command," >ps2epsi.out 2>ps2epsi.err");/*redirect stdout,stderr*/
+ showmsg(5,"ps2epsi command executed",command); /* command executed */
+ sys_stat = system(command); /* execute system(ps2epsi) */
+ } /* --- end-of-if(ispicture) --- */
+ 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 */
+ } /* --- end-of-if(latexmethod!=2) --- */
+ /* ---
+ * 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 */
+ if ( latexmethod != 2 ) /* we ran latex and dvips */
+ strcat(command,makepath("","dvips",".ps")); /* convert from postscript */
+ if ( latexmethod == 2 ) /* we ran pdflatex */
+ strcat(command,makepath("","latex",".pdf")); /* convert from pdf */
+ 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 working dir or home*/
+ if ( dir_stat >= 1 ) rrmdir(tempdir/*filename*/);/*rm -r temp working dir*/
+ if ( isworkpath ) /* return from working dir to home */
+ chdir((!isempty(homepath)?homepath:"..")); /* best guess at home */
+ iserror = 0; /* always reset error flag */
+ return ( status );
+} /* --- end-of-function mathtex() --- */
+
+
+/* ==========================================================================
+ * Function: setpaths ( method )
+ * Purpose: try to set accurate paths for
+ * latex,pdflatex,timelimit,dvipng,dvips,convert
+ * --------------------------------------------------------------------------
+ * Arguments: method (I) 10*ltxmethod + imgmethod where
+ * ltxmethod =
+ * 1 for latex, 2 for pdflatex,
+ * 0 for both
+ * imgmethod =
+ * 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*/
+int ltxmethod = method/10, /* divide by 10 */
+ imgmethod = method%10; /* remainder after division by 10 */
+static int islatexwhich=0, ispdflatexwhich=0, /* set true after we try */
+ isdvipngwhich=0, isdvipswhich=0, /*whichpath() for that program*/
+ isps2epsiwhich=0, isconvertwhich=0, istimelimitwhich=0;
+/* ---
+ * set paths, either from -DLATEX=\"path/latex\", etc, or call whichpath()
+ * ----------------------------------------------------------------------- */
+/* --- path for latex program --- */
+if ( ltxmethod==1 || ltxmethod==0 ) /* not needed for pdflatex only */
+ /*if ( !ISLATEXSWITCH && !islatexwhich )*/ /* nb, use islatexpath instead */
+ if ( !islatexpath && !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); } }/* copy path from whichpath() */
+/* --- path for pdflatex program --- */
+if ( ltxmethod==2 || ltxmethod==0 ) /* not needed for latex only */
+ /*if ( !ISPDFLATEXSWITCH && !ispdflatexwhich )*/ /*nb, use ispdflatexpath*/
+ if ( !ispdflatexpath && !ispdflatexwhich ) { /*no -DPDFLATEX=\"pdflatex\"*/
+ ispdflatexwhich = 1; /* signal that which already tried */
+ nlocate = ISLOCATE; /* use locate if which fails??? */
+ if ( (programpath=whichpath("pdflatex",&nlocate)) /*try to find pdflatex*/
+ != NULL ) { /* succeeded */
+ ispdflatexpath = (nlocate==0?2:3); /* set flag signalling which() */
+ strninit(pdflatexpath,programpath,255); } }/*copy path from whichpath()*/
+/* --- path for timelimit program --- */
+if ( 0 ) /* only use explicit -DTIMELIMIT */
+ if ( warntime > 0 ) /* have -DWARNTIME or -DTIMELIMIT */
+ /*if ( !ISTIMELIMITSWITCH*/ /* nb, use istimelimitpath instead */
+ if ( !istimelimitpath /*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 ( imgmethod != 2 ) /* not needed for dvips/convert */
+ /*if ( !ISDVIPNGSWITCH && !isdvipngwhich )*/ /*nb, use isdvipngpath instead*/
+ if ( !isdvipngpath && !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 ( imgmethod != 1 ) /* not needed for dvipng */
+ /*if ( !ISDVIPSSWITCH && !isdvipswhich )*/ /* nb, use isdvipspath instead */
+ if ( !isdvipspath && !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 ps2epsi program --- */
+if ( (ispicture || method==0) /* only needed for \begin{picture} */
+&& imgmethod != 1 /* not needed for dvipng */
+&& ltxmethod != 2 ) /* not needed for pdflatex */
+ /*if ( !ISPS2EPSISWITCH && !isps2epsiwhich )*/ /*use isps2epsipath instead*/
+ if ( !isps2epsipath && !isps2epsiwhich ) { /*no -DPS2EPSI=\"path/ps2epsi\"*/
+ isps2epsiwhich = 1; /* signal that which already tried */
+ nlocate = ISLOCATE; /* use locate if which fails??? */
+ if ( (programpath=whichpath("ps2epsi",&nlocate))/*try to find ps2epsi path*/
+ != NULL ) { /* succeeded */
+ isps2epsipath = (nlocate==0?2:3); /* set flag signalling which() */
+ strninit(ps2epsipath,programpath,255); } } /*copy path from whichpath()*/
+/* --- path for convert program --- */
+if ( imgmethod != 1 ) /* not needed for dvipng */
+ /*if ( !ISCONVERTSWITCH && !isconvertwhich )*/ /*use isconvertpath instead*/
+ if ( !isconvertpath && !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 ( imgmethod != imagemethod /* ignore recursive call */
+&& imgmethod != 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 ( imgmethod == 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 ( imgmethod == 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,*/ /* {arg} format */
+ 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: presentwd ( int nsub )
+ * Purpose: determines pwd, nsub directories "up"
+ * --------------------------------------------------------------------------
+ * Arguments: nsub (I) int containing #subdirectories "up" to
+ * which path is wanted. 0 for pwd
+ * --------------------------------------------------------------------------
+ * Returns: ( char * ) path to pwd, or NULL for any error
+ * --------------------------------------------------------------------------
+ * Notes: o A forward / is always the last character
+ * ======================================================================= */
+/* --- entry point --- */
+char *presentwd ( int nsub )
+{
+/* -------------------------------------------------------------------------
+Allocations and Declarations
+-------------------------------------------------------------------------- */
+static char pathbuff[256]; /* buffer for returned path */
+FILE *pwd = NULL; /* pwd's stdout */
+char *path = NULL; /* either pathbuff or NULL=error */
+int wdmethod = 1; /* 1=getcwd(), 2=popen("pwd","r") */
+/* -------------------------------------------------------------------------
+issue getcwd() call
+-------------------------------------------------------------------------- */
+if ( wdmethod == 1 ) { /* --- getcwd(pathbuff,255) --- */
+ if ( (path = getcwd(pathbuff,255)) /* get cwd */
+ == NULL ) goto end_of_job; /* failed */
+ trimwhite(pathbuff); } /*remove leading/trailing whitesapce*/
+/* -------------------------------------------------------------------------
+issue pwd command and read its output
+-------------------------------------------------------------------------- */
+if ( wdmethod == 2 ) { /* --- popen("pwd","r") --- */
+ /* --- use popen() to invoke pwd --- */
+ if ( (pwd = popen( "pwd", "r" )) /* issue pwd and capture stdout */
+ == NULL ) goto end_of_job; /* failed */
+ *pathbuff = '\000'; /* empty string in case fgets fails */
+ /* --- read the pipe one line at a time --- */
+ while ( fgets(pathbuff,255,pwd) /* get next line */
+ != NULL ) { /* not at eof yet */
+ trimwhite(pathbuff); /*remove leading/trailing whitespace*/
+ if ( strlen(pathbuff) > 0 ) break; } /* try again if empty line */
+ /* --- pclose() waits for command to terminate --- */
+ pclose( pwd ); } /* finish */
+/* -------------------------------------------------------------------------
+strip leading directories
+-------------------------------------------------------------------------- */
+if ( nsub > 0 ) { /* caller wants path above pwd */
+ if ( lastchar(pathbuff) == '/' ) /* have terminating / */
+ *plastchar(pathbuff) = '\000'; /* strip it */
+ while ( nsub > 0 ) { /* still higher path wanted */
+ char *slash = strrchr(pathbuff,'/'); /* last / on path */
+ if ( slash == NULL ) break; /* can't go up any higher */
+ *slash = '\000'; /* truncate "/highestdir" from path */
+ nsub--; } /* we're now one path up */
+ } /* --- end-of-if(nsub>0) --- */
+if ( lastchar(pathbuff) != '/' ) /* need terminating / */
+ strcat(pathbuff,"/"); /* add it */
+/* --- back to caller --- */
+path = pathbuff; /* successful path */
+end_of_job:
+ return ( path ); /* give caller path */
+} /* --- end-of-function presentwd() --- */
+
+
+/* ==========================================================================
+ * 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: rewritecache ( cachefile, maxage )
+ * Purpose: rewrites cached image file with headers and extra image info
+ * --------------------------------------------------------------------------
+ * Arguments: cachefile (I) pointer to null-terminated char string
+ * containing full path to existing image file
+ * written by dvipng or convert
+ * maxage (I) int containing maxage, in seconds, for
+ * http header
+ * --------------------------------------------------------------------------
+ * Returns: ( int ) #bytes in original image (0 signals error)
+ * --------------------------------------------------------------------------
+ * Notes: o
+ * ======================================================================= */
+/* --- entry point --- */
+int rewritecache ( char *cachefile, int maxage )
+{
+/* -------------------------------------------------------------------------
+Allocations and Declarations
+-------------------------------------------------------------------------- */
+int nbytes=0, readcachefile(); /* read cache file */
+FILE *rewriteptr = NULL; /* write cachefile back over itself*/
+unsigned char buffer[MAXGIFSZ+1]; /* bytes from cachefile */
+int i = 0; /* imageinfo[] index */
+/* -------------------------------------------------------------------------
+initialization
+-------------------------------------------------------------------------- */
+/* --- read original image file --- */
+if ( (nbytes = readcachefile(cachefile,buffer)) /* read the file */
+< 1 ) { /* file not read */
+ msgnumber = EMITFAILED; goto end_of_job; } /* signal error to caller */
+/* --- re-open the file for write --- */
+if ( (rewriteptr = fopen(cachefile,"wb")) /*open cachefile for binary write*/
+== NULL ) { /* failed to open for write */
+ nbytes = 0; goto end_of_job; } /* signal error to caller */
+/* --- first emit max-age http header --- */
+fprintf( rewriteptr, "Cache-Control: max-age=%d\n",max2(0,maxage) );
+/* --- now emit our "special" image info http headers --- */
+for ( i=0; imageinfo[i].format!=NULL; i++ ) /* all imageinfo[] fields */
+ if ( (imageinfo[i].value) + 9999. > 1.0 ) { /*this field has actual value*/
+ double value = imageinfo[i].value; /* value from latex.info file */
+ char *units = imageinfo[i].units; /* value units, e.g., "pt" */
+ int algorithm= imageinfo[i].algorithm; /* conversion algorithm */
+ char *format = imageinfo[i].format; /* http header output format */
+ int px = 0; /* depth in px */
+ switch( algorithm ) { /* convert value for http header */
+ default: break;
+ case 1: /* depth in pts converted to px */
+ if ( 1 || (strstr(units,"pt")!=NULL) ) /* units are pts */
+ px = (int)((value/72.)*strtod(density,NULL) + 0.5); /* pts-to-px */
+ if ( algorithm == 1 ) px = (-px); /* vertical alignment is -depth */
+ fprintf( rewriteptr, format, px ); /* write http header for depth */
+ break;
+ } /* --- end-of- switch(algorithm) --- */
+ } /* --- end-of-if(imageinfo[i].value!=-9999) --- */
+/* --- finally emit content length and type http headers --- */
+fprintf( rewriteptr, "Content-Length: %d\n",nbytes );
+fprintf( rewriteptr, "Content-type: image/%s\n\n",extensions[imagetype] );
+/* -------------------------------------------------------------------------
+rewrite bytes from cachefile
+-------------------------------------------------------------------------- */
+/* --- write bytes back to cachefile --- */
+if ( fwrite(buffer,sizeof(unsigned char),nbytes,rewriteptr) /*write buffer*/
+< nbytes ) /* failed to write all bytes */
+ nbytes = 0; /* reset total count to 0 */
+end_of_job:
+ if ( rewriteptr != NULL ) fclose(rewriteptr); /* close cachefile */
+ return ( nbytes ); /* back with #bytes emitted */
+} /* --- end-of-function rewritecache() --- */
+
+
+/* ==========================================================================
+ * 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 ( isdepth == 0 /* http headers not already in file*/
+&& maxage >= 0 ) /* and 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
+ * --------------------------------------------------------------------------
+ * 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,*/ /* {arg} format */
+ 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 */
+ {strsqueeze(pfirst,((int)(plast-pfirst)));} /* squeeze out directive */
+ 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 */
+ strsqueeze(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 \[...\] */
+ strsqueeze(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; strsqueeze(pwhite,1); } /*set flag and squeeze it out*/
+ while ( (pwhite=strchr(whitespace,'I')) != NULL ) /* have an embedded I */
+ { iscase = 0; strsqueeze(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*/
+if ( from == NULL ) goto end_of_job; /* error if no source string */
+/* -------------------------------------------------------------------------
+shift from left or right to accommodate replacement of its nfirst chars by to
+-------------------------------------------------------------------------- */
+if ( tolen < nfirst ) /* shift left is easy */
+ {strsqueeze(from,nshift);} /* squeeze out extra bytes */
+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 */
+end_of_job: 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: isnumeric ( s )
+ * Purpose: determine if s is an integer
+ * --------------------------------------------------------------------------
+ * Arguments: s (I) (char *)pointer to null-terminated string
+ * that's checked for a leading + or -
+ * followed by digits
+ * --------------------------------------------------------------------------
+ * Returns: ( int ) 1 if s is numeric, 0 if it is not
+ * --------------------------------------------------------------------------
+ * Notes: o
+ * ======================================================================= */
+/* --- entry point --- */
+int isnumeric ( char *s )
+{
+/* -------------------------------------------------------------------------
+determine whether s is an integer
+-------------------------------------------------------------------------- */
+int status = 0; /* return 0 if not numeric, 1 if is*/
+char *p = s; /* pointer into s */
+if ( isempty(s) ) goto end_of_job; /* missing arg or empty string */
+skipwhite(p); /*check for leading +or- after space*/
+if ( *p=='+' || *p=='-' ) p++; /* skip leading + or - */
+for ( ; *p != '\000'; p++ ) { /* check rest of s for digits */
+ if ( isdigit(*p) ) continue; /* still got uninterrupted digits */
+ if ( !isthischar(*p,WHITESPACE) ) goto end_of_job; /* non-numeric char */
+ skipwhite(p); /* skip all subsequent whitespace */
+ if ( *p == '\000' ) break; /* trailing whitespace okay */
+ goto end_of_job; /* embedded whitespace non-numeric */
+ } /* --- end-of-for(*p) --- */
+status = 1; /* numeric after checks succeeded */
+end_of_job:
+ return ( status ); /*back to caller with 1=string, 0=no*/
+} /* --- end-of-function isnumeric() --- */
+
+
+/* ==========================================================================
+ * Function: evalterm ( STORE *store, char *term )
+ * Purpose: evaluates a term
+ * --------------------------------------------------------------------------
+ * Arguments: store (I/O) STORE * containing environment
+ * in which term is to be evaluated
+ * term (I) char * containing null-terminated string
+ * with a term like "3" or "a" or "a+3"
+ * whose value is to be determined
+ * --------------------------------------------------------------------------
+ * Returns: ( int ) value of term,
+ * or NOVALUE for any error
+ * --------------------------------------------------------------------------
+ * Notes: o Also evaluates index?a:b:c:etc, returning a if index<=0,
+ * b if index=1, etc, and the last value if index is too large.
+ * Each a:b:c:etc can be another expression, including another
+ * (index?a:b:c:etc) which must be enclosed in parentheses.
+ * ======================================================================= */
+/* --- entry point --- */
+int evalterm ( STORE *store, char *term )
+{
+/* -------------------------------------------------------------------------
+Allocations and Declarations
+-------------------------------------------------------------------------- */
+int termval = 0; /* term value returned to caller */
+char token[2048] = "\000", /* copy term */
+ *delim = NULL; /* delim '(' or '?' in token */
+/*int evalwff(),*/ /* recurse to evaluate terms */
+/* evalfunc();*/ /* evaluate function(arg1,arg2,...)*/
+char *strpspn(); /* span delims */
+int getstore(); /* lookup variables */
+int isnumeric(); /* numeric=constant, else variable */
+static int evaltermdepth = 0; /* recursion depth */
+int novalue = (-89123456); /* dummy (for now) error signal */
+/* -------------------------------------------------------------------------
+Initialization
+-------------------------------------------------------------------------- */
+if ( ++evaltermdepth > 99 ) goto end_of_job; /*probably recursing forever*/
+if ( store==NULL || isempty(term) ) goto end_of_job; /*check for missing arg*/
+skipwhite(term); /* skip any leading whitespace */
+/* -------------------------------------------------------------------------
+First look for conditional of the form term?term:term:...
+-------------------------------------------------------------------------- */
+/* ---left-hand part of conditional is chars preceding "?" outside ()'s--- */
+delim = strpspn(term,"?",token); /* chars preceding ? outside () */
+if ( *delim != '\000' ) { /* found conditional expression */
+ int ncolons = 0; /* #colons we've found so far */
+ if ( *token != '\000' ) /* evaluate "index" value on left */
+ if ( (termval=evalterm(store,token)) /* evaluate left-hand term */
+ == novalue ) goto end_of_job; /* return error if failed */
+ while ( *delim != '\000' ) { /* still have chars in term */
+ delim++; *token='\000'; /* initialize for next "value:" */
+ if ( *delim == '\000' ) break; /* no more values */
+ delim = strpspn(delim,":",token); /* chars preceding : outside () */
+ if ( ncolons++ >= termval ) break; /* have corresponding term */
+ } /* --- end-of-while(*delim!='\000')) --- */
+ if ( *token != '\000' ) /* have x:x:value:x:x on right */
+ termval=evalterm(store,token); /* so evaluate it */
+ goto end_of_job; /* return result to caller */
+ } /* --- end-of-if(*delim!='\000')) --- */
+/* -------------------------------------------------------------------------
+evaluate a+b recursively
+-------------------------------------------------------------------------- */
+/* --- left-hand part of term is chars preceding "/+-*%" outside ()'s --- */
+term = strpspn(term,"/+-*%",token); /* chars preceding /+-*% outside ()*/
+/* --- evaluate a+b, a-b, etc --- */
+if ( *term != '\000' ) { /* found arithmetic operation */
+ int leftval=0, rightval=0; /* init leftval for unary +a or -a */
+ if ( *token != '\000' ) /* or eval for binary a+b or a-b */
+ if ( (leftval=evalterm(store,token)) /* evaluate left-hand term */
+ == novalue ) goto end_of_job; /* return error if failed */
+ if ( (rightval=evalterm(store,term+1)) /* evaluate right-hand term */
+ == novalue ) goto end_of_job; /* return error if failed */
+ switch ( *term ) { /* perform requested arithmetic */
+ default: break; /* internal error */
+ case '+': termval = leftval+rightval; break; /* addition */
+ case '-': termval = leftval-rightval; break; /* subtraction */
+ case '*': termval = leftval*rightval; break; /* multiplication */
+ case '/': if ( rightval != 0 ) /* guard against divide by zero */
+ termval = leftval/rightval; break; /* integer division */
+ case '%': if ( rightval != 0 ) /* guard against divide by zero */
+ termval = leftval%rightval; break; /*left modulo right */
+ } /* --- end-of-switch(*relation) --- */
+ goto end_of_job; /* return result to caller */
+ } /* --- end-of-if(*term!='\000')) --- */
+/* -------------------------------------------------------------------------
+check for parenthesized expression or term of the form function(arg1,arg2,...)
+-------------------------------------------------------------------------- */
+if ( (delim = strchr(token,'(')) != NULL ) { /* token contains a ( */
+ /* --- strip trailing paren (if there hopefully is one) --- */
+ int toklen = strlen(token); /* total #chars in token */
+ if ( token[toklen-1] == ')' ) /* found matching ) at end of token*/
+ token[--toklen] = '\000'; /* remove trailing ) */
+ /* --- handle parenthesized subexpression --- */
+ if ( *token == '(' ) { /* have parenthesized expression */
+ strsqueeze(token,1); /* so squeeze out leading ( */
+ /* --- evaluate edited term --- */
+ trimwhite(token); /* trim leading/trailing whitespace*/
+ termval = evalterm(store,token); } /* evaluate token recursively */
+ /* --- handle function(arg1,arg2,...) --- */
+ else { /* have function(arg1,arg2,...) */
+ *delim = '\000'; /* separate function name and args */
+ /*termval = evalfunc(store,token,delim+1);*/ } /* evaluate function */
+ goto end_of_job; } /* return result to caller */
+/* -------------------------------------------------------------------------
+evaluate constants directly, or recursively evaluate variables, etc
+-------------------------------------------------------------------------- */
+if ( *token != '\000' ) { /* empty string */
+ if ( isnumeric(token) ) /* have a constant */
+ termval = atoi(token); /* convert ascii-to-int */
+ else { /* variable or "stored proposition"*/
+ termval = getstore(store,token); } /* look up token */
+ } /* --- end-of-if(*token!=0) --- */
+/* -------------------------------------------------------------------------
+back to caller with truth value of proposition
+-------------------------------------------------------------------------- */
+end_of_job:
+ /* --- back to caller --- */
+ if ( evaltermdepth > 0 ) evaltermdepth--; /* pop recursion depth */
+ return ( termval ); /* back to caller with value */
+} /* --- end-of-function evalterm() --- */
+
+
+/* ==========================================================================
+ * Function: getstore ( store, identifier )
+ * Purpose: finds identifier in store and returns corresponding value
+ * --------------------------------------------------------------------------
+ * Arguments: store (I) (STORE *)pointer to store containing
+ * the desired identifier
+ * identifier (I) (char *)pointer to null-terminated string
+ * containing the identifier whose value
+ * is to be returned
+ * --------------------------------------------------------------------------
+ * Returns: ( int ) identifier's corresponding value,
+ * or 0 if identifier not found (or any error)
+ * --------------------------------------------------------------------------
+ * Notes: o
+ * ======================================================================= */
+/* --- entry point --- */
+int getstore ( STORE *store, char *identifier )
+{
+/* -------------------------------------------------------------------------
+Allocations and Declarations
+-------------------------------------------------------------------------- */
+int value = 0; /* store[istore].value for identifier */
+int istore=0; /* store[] index containing identifier */
+char seek[512], hide[512]; /* identifier arg, identifier in store */
+/* --- first check args --- */
+if ( store==NULL || isempty(identifier)) goto end_of_job; /* missing arg */
+strninit(seek,identifier,500); /* local copy of caller's identifier */
+trimwhite(seek); /* remove leading/trailing whitespace */
+/* --- loop over store --- */
+for ( istore=0; istore<MAXSTORE; istore++ ) { /* until end-of-table */
+ char *idstore = store[istore].identifier; /* ptr to identifier in store */
+ if ( isempty(idstore) ) /* empty id signals eot */
+ break; /* de-reference any default/error value */
+ strninit(hide,idstore,500); /* local copy of store[] identifier */
+ trimwhite(hide); /* remove leading/trailing whitespace */
+ if ( !strcmp(hide,seek) ) /* found match */
+ break; /* de-reference corresponding value */
+ } /* --- end-of-for(istore) --- */
+if ( store[istore].value != NULL ) /* address of int supplied */
+ value = *(store[istore].value); /* return de-referenced int */
+end_of_job:
+ return ( value ); /* store->values[istore] or NULL */
+} /* --- end-of-function getstore() --- */
+
+
+/* ==========================================================================
+ * Function: timewaitfor ( whundredths )
+ * Purpose: wait for whundredths hundredths of a second
+ * --------------------------------------------------------------------------
+ * 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 --- */
+int timewaitfor( int whundredths )
+{
+/* -------------------------------------------------------------------------
+Allocations and Declarations
+-------------------------------------------------------------------------- */
+int secs = whundredths/100, /* whole seconds */
+ hundredths = whundredths - (100*secs); /* remainder is hundredths */
+long nanos = ((long)hundredths)*((long)10000000); /* times ten million */
+struct timespec waitfor = { 0, 0 }; /* nanosleep arg */
+if ( whundredths>=1 && secs<=999 ) { /* sanity check */
+ waitfor.tv_sec = secs; waitfor.tv_nsec = nanos; /* init nanosleep arg */
+ nanosleep(&waitfor,NULL); } /* impose delay */
+return ( 1 ); /* back to caller after delay */
+} /* --- end-of-function timewaitfor() --- */
+
+
+/* ==========================================================================
+ * 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;
+ case 5: /* --- 2005 --- */
+ sprintf(timebuff,"%d",year);
+ 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: calendar ( year, month, day )
+ * Purpose: returns null-terminated character string containing
+ * \begin{tabular}...\end{tabular} for the one-month calendar
+ * specified by year=1973...2099 and month=1...12.
+ * If either arg out-of-range, today's value is used.
+ * --------------------------------------------------------------------------
+ * Arguments: year (I) int containing 1973...2099 or 0 for current
+ * year
+ * month (I) int containing 1...12 or 0 for current month
+ * day (I) int containing day to emphasize or 0
+ * --------------------------------------------------------------------------
+ * Returns: ( char * ) char ptr to null-terminated buffer
+ * containing \begin{tabular}...\end{tabular}
+ * string that will render calendar for
+ * requested month, or NULL for any error.
+ * --------------------------------------------------------------------------
+ * Notes: o
+ * ======================================================================= */
+/* --- entry point --- */
+char *calendar( int year, int month, int day )
+{
+/* -------------------------------------------------------------------------
+Allocations and Declarations
+-------------------------------------------------------------------------- */
+static char calbuff[4096]; /* calendar returned to caller */
+time_t time_val = (time_t)(0); /* binary value returned by time() */
+struct tm *tmstruct=(struct tm *)NULL, *localtime(); /* interpret time_val */
+int yy=0, mm=0, dd=0; /* today (emphasize today's dd) */
+int idd=1, iday=0, daynumber(); /* day-of-week for idd=1...31 */
+char aval[64]; /* ascii day or 4-digit year */
+char *small = sizedirectives[(fontsize>1?fontsize-1:1)], /* small chars */
+ *smaller=sizedirectives[(fontsize>2?fontsize-2:1)]; /* smaller */
+/* --- calendar data --- */
+static char *monthnames[] = { "?", "January", "February", "March", "April",
+ "May", "June", "July", "August", "September", "October",
+ "November", "December", "?" } ;
+static int modays[] =
+ { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0 };
+/* -------------------------------------------------------------------------
+initialization
+-------------------------------------------------------------------------- */
+/* --- get current date/time --- */
+time((time_t *)(&time_val)); /* get date and time */
+tmstruct = localtime((time_t *)(&time_val)); /* interpret time_val */
+yy = 1900 + (int)(tmstruct->tm_year); /* current four-digit year */
+mm = 1 + (int)(tmstruct->tm_mon); /* current month, 1-12 */
+dd = (int)(tmstruct->tm_mday); /* current day, 1-31 */
+/* --- check args --- */
+if ( year<1973 || year>2099 ) year = yy; /* current year if out-of-bounds */
+if ( month<1 || month>12 ) month = mm; /* current month if out-of-bounds */
+if ( month==mm && year==yy && day==0 ) /* current month and default day */
+ day = dd; /* emphasize current day */
+modays[2] = (year%4==0?29:28); /* Feb has 29 days in leap years */
+/* --- initialize calendar string --- */
+strcpy(calbuff,"{\\begin{center} {"); /* center `month year` above cal */
+strcat(calbuff,small); /* small font size */
+strcat(calbuff,"\\text{"); /* month set in roman */
+strcat(calbuff,monthnames[month]); /* insert month name */
+strcat(calbuff,"}\\ "); /* add a space */
+sprintf(aval,"%d",year); /* convert year to ascii */
+strcat(calbuff,aval); /* add year */
+strcat(calbuff,"}\\vspace*{1pt} \\\\"); /* end top row */
+/* --- now begin calendar array --- */
+strcat(calbuff,"\\begin{tabular}{|c|c|c|c|c|c|c|} \\hline" );
+strcat(calbuff,"{");strcat(calbuff,smaller);strcat(calbuff,"\\text{Sun}} &");
+strcat(calbuff,"{");strcat(calbuff,smaller);strcat(calbuff,"\\text{Mon}} &");
+strcat(calbuff,"{");strcat(calbuff,smaller);strcat(calbuff,"\\text{Tue}} &");
+strcat(calbuff,"{");strcat(calbuff,smaller);strcat(calbuff,"\\text{Wed}} &");
+strcat(calbuff,"{");strcat(calbuff,smaller);strcat(calbuff,"\\text{Thu}} &");
+strcat(calbuff,"{");strcat(calbuff,smaller);strcat(calbuff,"\\text{Fri}} &");
+strcat(calbuff,"{");strcat(calbuff,smaller);strcat(calbuff,"\\text{Sat}}");
+strcat(calbuff," \\\\ \\hline " );
+/* -------------------------------------------------------------------------
+generate calendar
+-------------------------------------------------------------------------- */
+for ( idd=1; idd<=modays[month]; idd++ ) /* run through days of month */
+ {
+ /* --- get day-of-week for this day --- */
+ iday = 1 + (daynumber(year,month,idd)%7); /* 1=Monday...7=Sunday */
+ if ( iday == 7 ) iday = 0; /* now 0=Sunday...6=Saturday */
+ /* --- may need empty cells at beginning of month --- */
+ if ( idd == 1 ) /* first day of month */
+ if ( iday > 0 ) /* need to skip cells */
+ { strcpy(aval,"\\ &\\ &\\ &\\ &\\ &\\ &\\ &\\ &\\ &\\"); /*cells to skip*/
+ aval[3*iday] = '\000'; /*skip cells preceding 1st of month*/
+ strcat(calbuff,aval); } /* add skip string to buffer */
+ /* --- add idd to current cell --- */
+ sprintf(aval,"%d",idd); /* convert idd to ascii */
+ if ( idd == day /* emphasize today's date */
+ /*&& month==mm && year==yy*/ ) /* only if this month's calendar */
+ { strcat(calbuff,"{"); /* emphasize current day */
+ strcat(calbuff,small); /* small */
+ strcat(calbuff,"$\\langle$"); /* enclose curent day in <> */
+ strcat(calbuff,aval); /* put in idd */
+ strcat(calbuff,"$\\rangle$}"); } /* finish emphasis */
+ else /* not today's date */
+ strcat(calbuff,aval); /* so just put in idd */
+ /* --- terminate cell --- */
+ if ( idd < modays[month] ) { /* not yet end-of-month */
+ if ( iday < 6 ) /* still have days left in week */
+ strcat(calbuff,"&"); /* new cell in same week */
+ else /* reached end-of-week */
+ strcat(calbuff,"\\\\ \\hline"); } /* so start new week */
+ else /* --- terminate last week of month --- */
+ if ( iday < 6 ) { /* only if there are empty cells */
+ strcpy(aval,"&\\ &\\ &\\ &\\ &\\ &\\ &\\ &\\ &\\ &");/*empty end cells*/
+ aval[3*(6-iday)] = '\000'; /* cells after last of month */
+ strcat(calbuff,aval); } /* add end-of-week string to buffer*/
+ } /* --- end-of-for(idd) --- */
+strcat(calbuff,"\\\\ \\hline"); /* final underline at end-of-month */
+/* --- return calendar to caller --- */
+strcat(calbuff,"\\end{tabular}\\end{center}}"); /* terminate array */
+if(0) strcpy(calbuff,"testing");
+return ( calbuff ); /* back to caller with calendar */
+} /* --- end-of-function calendar() --- */
+
+
+/* ==========================================================================
+ * 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 --- */