diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/mathtex/mathtex.c |
Initial commit
Diffstat (limited to 'support/mathtex/mathtex.c')
-rw-r--r-- | support/mathtex/mathtex.c | 6620 |
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 < 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 $ 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... + ---------------------------------------- */ + { """, ";", "\"" }, /* " is first, " */ + { "&", ";", "&" }, + { "<", ";", "<" }, + { ">", ";", ">" }, + { "&backslash",";", "\\" }, + { " ", ";", " " /*"~"*/ }, + { "¡", ";", "{\\mbox{!`}}" }, + { "¦", ";", "|" }, + { "±", ";", "\\pm" }, + { "²", ";", "{{}^2}" }, + { "³", ";", "{{}^3}" }, + { "µ", ";", "\\mu" }, + { "¹", ";", "{{}^1}" }, + { "¼", ";", "{\\frac14}" }, + { "½", ";", "{\\frac12}" }, + { "¾", ";", "{\\frac34}" }, + { "¿", ";", "{\\mbox{?`}}" }, + { "Â", ";", "{\\rm\\hat A}" }, + { "Ã", ";", "{\\rm\\tilde A}" }, + { "Ä", ";", "{\\rm\\ddot A}" }, + { "Å", ";", "{\\overset{o}{\\rm A}}" }, + { "ã", ";", "{\\rm\\tilde a}" }, + { "ÿ", ";", "{\\rm\\ddot y}" }, /* ÿ is last, ÿ */ + { "&#", ";", "{[\\&\\#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, "\"" }, /* " */ + { 35, "#" }, /* hash mark */ + { 36, "$" }, /* dollar */ + { 37, "%" }, /* percent */ + { 38, "&" }, /* & */ + { 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, "<" }, /* < */ + { 61, "=" }, /* = */ + { 62, ">" }, /* > */ + { 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, "~" }, /* (use tilde for latex) */ + { 166, "|" }, /* ¦ (broken vertical bar) */ + { 173, "-" }, /* ­ (soft hyphen) */ + { 177, "{\\pm}" }, /* ± (plus or minus) */ + { 215, "{\\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 --- */ |