src/cm/media/js/lib/asciimathtml/ASCIIMathML.js
changeset 395 5ff35e8e16e2
child 599 6c2ef083d89f
equal deleted inserted replaced
394:ce92c17cadc5 395:5ff35e8e16e2
       
     1 /*
       
     2 ASCIIMathML.js
       
     3 ==============
       
     4 This file contains JavaScript functions to convert ASCII math notation
       
     5 and LaTeX to Presentation MathML. Simple graphics commands are also
       
     6 translated to SVG images. The conversion is done while the (X)HTML 
       
     7 page loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet 
       
     8 Explorer 6/7 + MathPlayer (http://www.dessci.com/en/products/mathplayer/) +
       
     9 Adobe SVGview 3.03 (http://www.adobe.com/svg/viewer/install/).
       
    10 
       
    11 Just add the next line to your (X)HTML page with this file in the same folder:
       
    12 
       
    13 <script type="text/javascript" src="ASCIIMathML.js"></script>
       
    14 
       
    15 (using the graphics in IE also requires the file "d.svg" in the same folder).
       
    16 This is a convenient and inexpensive solution for authoring MathML and SVG.
       
    17 
       
    18 Version 2.0.1 Sept 27, 2007, (c) Peter Jipsen http://www.chapman.edu/~jipsen
       
    19 This version extends ASCIIMathML.js with LaTeXMathML.js and ASCIIsvg.js.
       
    20 Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js
       
    21 If you use it on a webpage, please send the URL to jipsen@chapman.edu
       
    22 
       
    23 The LaTeXMathML modifications were made by Douglas Woodall, June 2006.
       
    24 (for details see header on the LaTeXMathML part in middle of file)
       
    25 
       
    26 This program is free software; you can redistribute it and/or modify
       
    27 it under the terms of the GNU Lesser General Public License as published by
       
    28 the Free Software Foundation; either version 2.1 of the License, or (at
       
    29 your option) any later version.
       
    30 
       
    31 This program is distributed in the hope that it will be useful, but WITHOUT 
       
    32 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
       
    33 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 
       
    34 (at http://www.gnu.org/licences/lgpl.html) for more details.
       
    35 */
       
    36 
       
    37 var mathcolor = "blue";        // change it to "" (to inherit) or another color
       
    38 var mathfontsize = "1em";      // change to e.g. 1.2em for larger math
       
    39 var mathfontfamily = "serif";  // change to "" to inherit (works in IE) 
       
    40                                // or another family (e.g. "arial")
       
    41 var automathrecognize = false; // writing "amath" on page makes this true
       
    42 var checkForMathML = true;     // check if browser can display MathML
       
    43 var notifyIfNoMathML = true;   // display note at top if no MathML capability
       
    44 var alertIfNoMathML = false;   // show alert box if no MathML capability
       
    45 var translateOnLoad = true;    // set to false to do call translators from js 
       
    46 var translateLaTeX = true;     // false to preserve $..$, $$..$$
       
    47 var translateLaTeXformatting = true; // false to preserve \emph,\begin{},\end{}
       
    48 var translateASCIIMath = true; // false to preserve `..`
       
    49 var translateASCIIsvg = true;  // false to preserve agraph.., \begin{graph}..
       
    50 var avoidinnerHTML = false;   // set true if assigning to innerHTML gives error
       
    51 var displaystyle = true;      // puts limits above and below large operators
       
    52 var showasciiformulaonhover = true; // helps students learn ASCIIMath
       
    53 var decimalsign = ".";        // change to "," if you like, beware of `(1,2)`!
       
    54 var AMdelimiter1 = "`", AMescape1 = "\\\\`"; // can use other characters
       
    55 var AMdocumentId = "wikitext" // PmWiki element containing math (default=body)
       
    56 var checkforprocessasciimathinmoodle = false; // true for systems like Moodle
       
    57 var dsvglocation = ""; // path to d.svg (blank if same as ASCIIMathML.js loc)
       
    58 
       
    59 var isIE = document.createElementNS==null;
       
    60 
       
    61 if (document.getElementById==null) 
       
    62   alert("This webpage requires a recent browser such as\
       
    63 \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
       
    64 
       
    65 // all further ASCIIMathML global variables start with "AM"
       
    66 
       
    67 function AMcreateElementXHTML(t) {
       
    68   if (isIE) return document.createElement(t);
       
    69   else return document.createElementNS("http://www.w3.org/1999/xhtml",t);
       
    70 }
       
    71 
       
    72 function AMnoMathMLNote() {
       
    73   var nd = AMcreateElementXHTML("h3");
       
    74   nd.setAttribute("align","center")
       
    75   nd.appendChild(AMcreateElementXHTML("p"));
       
    76   nd.appendChild(document.createTextNode("To view the "));
       
    77   var an = AMcreateElementXHTML("a");
       
    78   an.appendChild(document.createTextNode("ASCIIMathML"));
       
    79   an.setAttribute("href","http://www.chapman.edu/~jipsen/asciimath.html");
       
    80   nd.appendChild(an);
       
    81   nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));  
       
    82   an = AMcreateElementXHTML("a");
       
    83   an.appendChild(document.createTextNode("MathPlayer"));
       
    84   an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");
       
    85   nd.appendChild(an);
       
    86   nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));
       
    87   nd.appendChild(AMcreateElementXHTML("p"));
       
    88   return nd;
       
    89 }
       
    90 
       
    91 function AMisMathMLavailable() {
       
    92   if (navigator.appName.slice(0,8)=="Netscape") 
       
    93     if (navigator.appVersion.slice(0,1)>="5") return null;
       
    94     else return AMnoMathMLNote();
       
    95   else if (navigator.appName.slice(0,9)=="Microsoft")
       
    96     try {
       
    97         var ActiveX = new ActiveXObject("MathPlayer.Factory.1");
       
    98         return null;
       
    99     } catch (e) {
       
   100         return AMnoMathMLNote();
       
   101     }
       
   102   else return AMnoMathMLNote();
       
   103 }
       
   104 
       
   105 // character lists for Mozilla/Netscape fonts
       
   106 var AMcal = [0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];
       
   107 var AMfrk = [0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];
       
   108 var AMbbb = [0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];
       
   109 
       
   110 var CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4, 
       
   111     RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8,
       
   112     LEFTRIGHT = 9, TEXT = 10; // token types
       
   113 
       
   114 var AMsqrt = {input:"sqrt", tag:"msqrt", output:"sqrt", tex:null, ttype:UNARY},
       
   115   AMroot  = {input:"root", tag:"mroot", output:"root", tex:null, ttype:BINARY},
       
   116   AMfrac  = {input:"frac", tag:"mfrac", output:"/",    tex:null, ttype:BINARY},
       
   117   AMdiv   = {input:"/",    tag:"mfrac", output:"/",    tex:null, ttype:INFIX},
       
   118   AMover  = {input:"stackrel", tag:"mover", output:"stackrel", tex:null, ttype:BINARY},
       
   119   AMsub   = {input:"_",    tag:"msub",  output:"_",    tex:null, ttype:INFIX},
       
   120   AMsup   = {input:"^",    tag:"msup",  output:"^",    tex:null, ttype:INFIX},
       
   121   AMtext  = {input:"text", tag:"mtext", output:"text", tex:null, ttype:TEXT},
       
   122   AMmbox  = {input:"mbox", tag:"mtext", output:"mbox", tex:null, ttype:TEXT},
       
   123   AMquote = {input:"\"",   tag:"mtext", output:"mbox", tex:null, ttype:TEXT};
       
   124 
       
   125 var AMsymbols = [
       
   126 //some greek symbols
       
   127 {input:"alpha",  tag:"mi", output:"\u03B1", tex:null, ttype:CONST},
       
   128 {input:"beta",   tag:"mi", output:"\u03B2", tex:null, ttype:CONST},
       
   129 {input:"chi",    tag:"mi", output:"\u03C7", tex:null, ttype:CONST},
       
   130 {input:"delta",  tag:"mi", output:"\u03B4", tex:null, ttype:CONST},
       
   131 {input:"Delta",  tag:"mo", output:"\u0394", tex:null, ttype:CONST},
       
   132 {input:"epsi",   tag:"mi", output:"\u03B5", tex:"epsilon", ttype:CONST},
       
   133 {input:"varepsilon", tag:"mi", output:"\u025B", tex:null, ttype:CONST},
       
   134 {input:"eta",    tag:"mi", output:"\u03B7", tex:null, ttype:CONST},
       
   135 {input:"gamma",  tag:"mi", output:"\u03B3", tex:null, ttype:CONST},
       
   136 {input:"Gamma",  tag:"mo", output:"\u0393", tex:null, ttype:CONST},
       
   137 {input:"iota",   tag:"mi", output:"\u03B9", tex:null, ttype:CONST},
       
   138 {input:"kappa",  tag:"mi", output:"\u03BA", tex:null, ttype:CONST},
       
   139 {input:"lambda", tag:"mi", output:"\u03BB", tex:null, ttype:CONST},
       
   140 {input:"Lambda", tag:"mo", output:"\u039B", tex:null, ttype:CONST},
       
   141 {input:"mu",     tag:"mi", output:"\u03BC", tex:null, ttype:CONST},
       
   142 {input:"nu",     tag:"mi", output:"\u03BD", tex:null, ttype:CONST},
       
   143 {input:"omega",  tag:"mi", output:"\u03C9", tex:null, ttype:CONST},
       
   144 {input:"Omega",  tag:"mo", output:"\u03A9", tex:null, ttype:CONST},
       
   145 {input:"phi",    tag:"mi", output:"\u03C6", tex:null, ttype:CONST},
       
   146 {input:"varphi", tag:"mi", output:"\u03D5", tex:null, ttype:CONST},
       
   147 {input:"Phi",    tag:"mo", output:"\u03A6", tex:null, ttype:CONST},
       
   148 {input:"pi",     tag:"mi", output:"\u03C0", tex:null, ttype:CONST},
       
   149 {input:"Pi",     tag:"mo", output:"\u03A0", tex:null, ttype:CONST},
       
   150 {input:"psi",    tag:"mi", output:"\u03C8", tex:null, ttype:CONST},
       
   151 {input:"Psi",    tag:"mi", output:"\u03A8", tex:null, ttype:CONST},
       
   152 {input:"rho",    tag:"mi", output:"\u03C1", tex:null, ttype:CONST},
       
   153 {input:"sigma",  tag:"mi", output:"\u03C3", tex:null, ttype:CONST},
       
   154 {input:"Sigma",  tag:"mo", output:"\u03A3", tex:null, ttype:CONST},
       
   155 {input:"tau",    tag:"mi", output:"\u03C4", tex:null, ttype:CONST},
       
   156 {input:"theta",  tag:"mi", output:"\u03B8", tex:null, ttype:CONST},
       
   157 {input:"vartheta", tag:"mi", output:"\u03D1", tex:null, ttype:CONST},
       
   158 {input:"Theta",  tag:"mo", output:"\u0398", tex:null, ttype:CONST},
       
   159 {input:"upsilon", tag:"mi", output:"\u03C5", tex:null, ttype:CONST},
       
   160 {input:"xi",     tag:"mi", output:"\u03BE", tex:null, ttype:CONST},
       
   161 {input:"Xi",     tag:"mo", output:"\u039E", tex:null, ttype:CONST},
       
   162 {input:"zeta",   tag:"mi", output:"\u03B6", tex:null, ttype:CONST},
       
   163 
       
   164 //binary operation symbols
       
   165 //{input:"-",  tag:"mo", output:"\u0096", tex:null, ttype:CONST},
       
   166 {input:"*",  tag:"mo", output:"\u22C5", tex:"cdot", ttype:CONST},
       
   167 {input:"**", tag:"mo", output:"\u22C6", tex:"star", ttype:CONST},
       
   168 {input:"//", tag:"mo", output:"/",      tex:null, ttype:CONST},
       
   169 {input:"\\\\", tag:"mo", output:"\\",   tex:"backslash", ttype:CONST},
       
   170 {input:"setminus", tag:"mo", output:"\\", tex:null, ttype:CONST},
       
   171 {input:"xx", tag:"mo", output:"\u00D7", tex:"times", ttype:CONST},
       
   172 {input:"-:", tag:"mo", output:"\u00F7", tex:"divide", ttype:CONST},
       
   173 {input:"@",  tag:"mo", output:"\u2218", tex:"circ", ttype:CONST},
       
   174 {input:"o+", tag:"mo", output:"\u2295", tex:"oplus", ttype:CONST},
       
   175 {input:"ox", tag:"mo", output:"\u2297", tex:"otimes", ttype:CONST},
       
   176 {input:"o.", tag:"mo", output:"\u2299", tex:"odot", ttype:CONST},
       
   177 {input:"sum", tag:"mo", output:"\u2211", tex:null, ttype:UNDEROVER},
       
   178 {input:"prod", tag:"mo", output:"\u220F", tex:null, ttype:UNDEROVER},
       
   179 {input:"^^",  tag:"mo", output:"\u2227", tex:"wedge", ttype:CONST},
       
   180 {input:"^^^", tag:"mo", output:"\u22C0", tex:"bigwedge", ttype:UNDEROVER},
       
   181 {input:"vv",  tag:"mo", output:"\u2228", tex:"vee", ttype:CONST},
       
   182 {input:"vvv", tag:"mo", output:"\u22C1", tex:"bigvee", ttype:UNDEROVER},
       
   183 {input:"nn",  tag:"mo", output:"\u2229", tex:"cap", ttype:CONST},
       
   184 {input:"nnn", tag:"mo", output:"\u22C2", tex:"bigcap", ttype:UNDEROVER},
       
   185 {input:"uu",  tag:"mo", output:"\u222A", tex:"cup", ttype:CONST},
       
   186 {input:"uuu", tag:"mo", output:"\u22C3", tex:"bigcup", ttype:UNDEROVER},
       
   187 
       
   188 //binary relation symbols
       
   189 {input:"!=",  tag:"mo", output:"\u2260", tex:"ne", ttype:CONST},
       
   190 {input:":=",  tag:"mo", output:":=",     tex:null, ttype:CONST},
       
   191 {input:"lt",  tag:"mo", output:"<",      tex:null, ttype:CONST},
       
   192 {input:"<=",  tag:"mo", output:"\u2264", tex:"le", ttype:CONST},
       
   193 {input:"lt=", tag:"mo", output:"\u2264", tex:"leq", ttype:CONST},
       
   194 {input:">=",  tag:"mo", output:"\u2265", tex:"ge", ttype:CONST},
       
   195 {input:"geq", tag:"mo", output:"\u2265", tex:null, ttype:CONST},
       
   196 {input:"-<",  tag:"mo", output:"\u227A", tex:"prec", ttype:CONST},
       
   197 {input:"-lt", tag:"mo", output:"\u227A", tex:null, ttype:CONST},
       
   198 {input:">-",  tag:"mo", output:"\u227B", tex:"succ", ttype:CONST},
       
   199 {input:"-<=", tag:"mo", output:"\u2AAF", tex:"preceq", ttype:CONST},
       
   200 {input:">-=", tag:"mo", output:"\u2AB0", tex:"succeq", ttype:CONST},
       
   201 {input:"in",  tag:"mo", output:"\u2208", tex:null, ttype:CONST},
       
   202 {input:"!in", tag:"mo", output:"\u2209", tex:"notin", ttype:CONST},
       
   203 {input:"sub", tag:"mo", output:"\u2282", tex:"subset", ttype:CONST},
       
   204 {input:"sup", tag:"mo", output:"\u2283", tex:"supset", ttype:CONST},
       
   205 {input:"sube", tag:"mo", output:"\u2286", tex:"subseteq", ttype:CONST},
       
   206 {input:"supe", tag:"mo", output:"\u2287", tex:"supseteq", ttype:CONST},
       
   207 {input:"-=",  tag:"mo", output:"\u2261", tex:"equiv", ttype:CONST},
       
   208 {input:"~=",  tag:"mo", output:"\u2245", tex:"cong", ttype:CONST},
       
   209 {input:"~~",  tag:"mo", output:"\u2248", tex:"approx", ttype:CONST},
       
   210 {input:"prop", tag:"mo", output:"\u221D", tex:"propto", ttype:CONST},
       
   211 
       
   212 //logical symbols
       
   213 {input:"and", tag:"mtext", output:"and", tex:null, ttype:SPACE},
       
   214 {input:"or",  tag:"mtext", output:"or",  tex:null, ttype:SPACE},
       
   215 {input:"not", tag:"mo", output:"\u00AC", tex:"neg", ttype:CONST},
       
   216 {input:"=>",  tag:"mo", output:"\u21D2", tex:"implies", ttype:CONST},
       
   217 {input:"if",  tag:"mo", output:"if",     tex:null, ttype:SPACE},
       
   218 {input:"<=>", tag:"mo", output:"\u21D4", tex:"iff", ttype:CONST},
       
   219 {input:"AA",  tag:"mo", output:"\u2200", tex:"forall", ttype:CONST},
       
   220 {input:"EE",  tag:"mo", output:"\u2203", tex:"exists", ttype:CONST},
       
   221 {input:"_|_", tag:"mo", output:"\u22A5", tex:"bot", ttype:CONST},
       
   222 {input:"TT",  tag:"mo", output:"\u22A4", tex:"top", ttype:CONST},
       
   223 {input:"|--",  tag:"mo", output:"\u22A2", tex:"vdash", ttype:CONST},
       
   224 {input:"|==",  tag:"mo", output:"\u22A8", tex:"models", ttype:CONST},
       
   225 
       
   226 //grouping brackets
       
   227 {input:"(", tag:"mo", output:"(", tex:null, ttype:LEFTBRACKET},
       
   228 {input:")", tag:"mo", output:")", tex:null, ttype:RIGHTBRACKET},
       
   229 {input:"[", tag:"mo", output:"[", tex:null, ttype:LEFTBRACKET},
       
   230 {input:"]", tag:"mo", output:"]", tex:null, ttype:RIGHTBRACKET},
       
   231 {input:"{", tag:"mo", output:"{", tex:null, ttype:LEFTBRACKET},
       
   232 {input:"}", tag:"mo", output:"}", tex:null, ttype:RIGHTBRACKET},
       
   233 {input:"|", tag:"mo", output:"|", tex:null, ttype:LEFTRIGHT},
       
   234 //{input:"||", tag:"mo", output:"||", tex:null, ttype:LEFTRIGHT},
       
   235 {input:"(:", tag:"mo", output:"\u2329", tex:"langle", ttype:LEFTBRACKET},
       
   236 {input:":)", tag:"mo", output:"\u232A", tex:"rangle", ttype:RIGHTBRACKET},
       
   237 {input:"<<", tag:"mo", output:"\u2329", tex:null, ttype:LEFTBRACKET},
       
   238 {input:">>", tag:"mo", output:"\u232A", tex:null, ttype:RIGHTBRACKET},
       
   239 {input:"{:", tag:"mo", output:"{:", tex:null, ttype:LEFTBRACKET, invisible:true},
       
   240 {input:":}", tag:"mo", output:":}", tex:null, ttype:RIGHTBRACKET, invisible:true},
       
   241 
       
   242 //miscellaneous symbols
       
   243 {input:"int",  tag:"mo", output:"\u222B", tex:null, ttype:CONST},
       
   244 {input:"dx",   tag:"mi", output:"{:d x:}", tex:null, ttype:DEFINITION},
       
   245 {input:"dy",   tag:"mi", output:"{:d y:}", tex:null, ttype:DEFINITION},
       
   246 {input:"dz",   tag:"mi", output:"{:d z:}", tex:null, ttype:DEFINITION},
       
   247 {input:"dt",   tag:"mi", output:"{:d t:}", tex:null, ttype:DEFINITION},
       
   248 {input:"oint", tag:"mo", output:"\u222E", tex:null, ttype:CONST},
       
   249 {input:"del",  tag:"mo", output:"\u2202", tex:"partial", ttype:CONST},
       
   250 {input:"grad", tag:"mo", output:"\u2207", tex:"nabla", ttype:CONST},
       
   251 {input:"+-",   tag:"mo", output:"\u00B1", tex:"pm", ttype:CONST},
       
   252 {input:"O/",   tag:"mo", output:"\u2205", tex:"emptyset", ttype:CONST},
       
   253 {input:"oo",   tag:"mo", output:"\u221E", tex:"infty", ttype:CONST},
       
   254 {input:"aleph", tag:"mo", output:"\u2135", tex:null, ttype:CONST},
       
   255 {input:"...",  tag:"mo", output:"...",    tex:"ldots", ttype:CONST},
       
   256 {input:":.",  tag:"mo", output:"\u2234",  tex:"therefore", ttype:CONST},
       
   257 {input:"/_",  tag:"mo", output:"\u2220",  tex:"angle", ttype:CONST},
       
   258 {input:"\\ ",  tag:"mo", output:"\u00A0", tex:null, ttype:CONST},
       
   259 {input:"quad", tag:"mo", output:"\u00A0\u00A0", tex:null, ttype:CONST},
       
   260 {input:"qquad", tag:"mo", output:"\u00A0\u00A0\u00A0\u00A0", tex:null, ttype:CONST},
       
   261 {input:"cdots", tag:"mo", output:"\u22EF", tex:null, ttype:CONST},
       
   262 {input:"vdots", tag:"mo", output:"\u22EE", tex:null, ttype:CONST},
       
   263 {input:"ddots", tag:"mo", output:"\u22F1", tex:null, ttype:CONST},
       
   264 {input:"diamond", tag:"mo", output:"\u22C4", tex:null, ttype:CONST},
       
   265 {input:"square", tag:"mo", output:"\u25A1", tex:null, ttype:CONST},
       
   266 {input:"|__", tag:"mo", output:"\u230A",  tex:"lfloor", ttype:CONST},
       
   267 {input:"__|", tag:"mo", output:"\u230B",  tex:"rfloor", ttype:CONST},
       
   268 {input:"|~", tag:"mo", output:"\u2308",  tex:"lceiling", ttype:CONST},
       
   269 {input:"~|", tag:"mo", output:"\u2309",  tex:"rceiling", ttype:CONST},
       
   270 {input:"CC",  tag:"mo", output:"\u2102", tex:null, ttype:CONST},
       
   271 {input:"NN",  tag:"mo", output:"\u2115", tex:null, ttype:CONST},
       
   272 {input:"QQ",  tag:"mo", output:"\u211A", tex:null, ttype:CONST},
       
   273 {input:"RR",  tag:"mo", output:"\u211D", tex:null, ttype:CONST},
       
   274 {input:"ZZ",  tag:"mo", output:"\u2124", tex:null, ttype:CONST},
       
   275 {input:"f",   tag:"mi", output:"f",      tex:null, ttype:UNARY, func:true},
       
   276 {input:"g",   tag:"mi", output:"g",      tex:null, ttype:UNARY, func:true},
       
   277 
       
   278 //standard functions
       
   279 {input:"lim",  tag:"mo", output:"lim", tex:null, ttype:UNDEROVER},
       
   280 {input:"Lim",  tag:"mo", output:"Lim", tex:null, ttype:UNDEROVER},
       
   281 {input:"sin",  tag:"mo", output:"sin", tex:null, ttype:UNARY, func:true},
       
   282 {input:"cos",  tag:"mo", output:"cos", tex:null, ttype:UNARY, func:true},
       
   283 {input:"tan",  tag:"mo", output:"tan", tex:null, ttype:UNARY, func:true},
       
   284 {input:"sinh", tag:"mo", output:"sinh", tex:null, ttype:UNARY, func:true},
       
   285 {input:"cosh", tag:"mo", output:"cosh", tex:null, ttype:UNARY, func:true},
       
   286 {input:"tanh", tag:"mo", output:"tanh", tex:null, ttype:UNARY, func:true},
       
   287 {input:"cot",  tag:"mo", output:"cot", tex:null, ttype:UNARY, func:true},
       
   288 {input:"sec",  tag:"mo", output:"sec", tex:null, ttype:UNARY, func:true},
       
   289 {input:"csc",  tag:"mo", output:"csc", tex:null, ttype:UNARY, func:true},
       
   290 {input:"log",  tag:"mo", output:"log", tex:null, ttype:UNARY, func:true},
       
   291 {input:"ln",   tag:"mo", output:"ln",  tex:null, ttype:UNARY, func:true},
       
   292 {input:"det",  tag:"mo", output:"det", tex:null, ttype:UNARY, func:true},
       
   293 {input:"dim",  tag:"mo", output:"dim", tex:null, ttype:CONST},
       
   294 {input:"mod",  tag:"mo", output:"mod", tex:null, ttype:CONST},
       
   295 {input:"gcd",  tag:"mo", output:"gcd", tex:null, ttype:UNARY, func:true},
       
   296 {input:"lcm",  tag:"mo", output:"lcm", tex:null, ttype:UNARY, func:true},
       
   297 {input:"lub",  tag:"mo", output:"lub", tex:null, ttype:CONST},
       
   298 {input:"glb",  tag:"mo", output:"glb", tex:null, ttype:CONST},
       
   299 {input:"min",  tag:"mo", output:"min", tex:null, ttype:UNDEROVER},
       
   300 {input:"max",  tag:"mo", output:"max", tex:null, ttype:UNDEROVER},
       
   301 
       
   302 //arrows
       
   303 {input:"uarr", tag:"mo", output:"\u2191", tex:"uparrow", ttype:CONST},
       
   304 {input:"darr", tag:"mo", output:"\u2193", tex:"downarrow", ttype:CONST},
       
   305 {input:"rarr", tag:"mo", output:"\u2192", tex:"rightarrow", ttype:CONST},
       
   306 {input:"->",   tag:"mo", output:"\u2192", tex:"to", ttype:CONST},
       
   307 {input:"|->",  tag:"mo", output:"\u21A6", tex:"mapsto", ttype:CONST},
       
   308 {input:"larr", tag:"mo", output:"\u2190", tex:"leftarrow", ttype:CONST},
       
   309 {input:"harr", tag:"mo", output:"\u2194", tex:"leftrightarrow", ttype:CONST},
       
   310 {input:"rArr", tag:"mo", output:"\u21D2", tex:"Rightarrow", ttype:CONST},
       
   311 {input:"lArr", tag:"mo", output:"\u21D0", tex:"Leftarrow", ttype:CONST},
       
   312 {input:"hArr", tag:"mo", output:"\u21D4", tex:"Leftrightarrow", ttype:CONST},
       
   313 
       
   314 //commands with argument
       
   315 AMsqrt, AMroot, AMfrac, AMdiv, AMover, AMsub, AMsup,
       
   316 {input:"hat", tag:"mover", output:"\u005E", tex:null, ttype:UNARY, acc:true},
       
   317 {input:"bar", tag:"mover", output:"\u00AF", tex:"overline", ttype:UNARY, acc:true},
       
   318 {input:"vec", tag:"mover", output:"\u2192", tex:null, ttype:UNARY, acc:true},
       
   319 {input:"dot", tag:"mover", output:".",      tex:null, ttype:UNARY, acc:true},
       
   320 {input:"ddot", tag:"mover", output:"..",    tex:null, ttype:UNARY, acc:true},
       
   321 {input:"ul", tag:"munder", output:"\u0332", tex:"underline", ttype:UNARY, acc:true},
       
   322 AMtext, AMmbox, AMquote,
       
   323 {input:"bb", tag:"mstyle", atname:"fontweight", atval:"bold", output:"bb", tex:null, ttype:UNARY},
       
   324 {input:"mathbf", tag:"mstyle", atname:"fontweight", atval:"bold", output:"mathbf", tex:null, ttype:UNARY},
       
   325 {input:"sf", tag:"mstyle", atname:"fontfamily", atval:"sans-serif", output:"sf", tex:null, ttype:UNARY},
       
   326 {input:"mathsf", tag:"mstyle", atname:"fontfamily", atval:"sans-serif", output:"mathsf", tex:null, ttype:UNARY},
       
   327 {input:"bbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"bbb", tex:null, ttype:UNARY, codes:AMbbb},
       
   328 {input:"mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"mathbb", tex:null, ttype:UNARY, codes:AMbbb},
       
   329 {input:"cc",  tag:"mstyle", atname:"mathvariant", atval:"script", output:"cc", tex:null, ttype:UNARY, codes:AMcal},
       
   330 {input:"mathcal", tag:"mstyle", atname:"mathvariant", atval:"script", output:"mathcal", tex:null, ttype:UNARY, codes:AMcal},
       
   331 {input:"tt",  tag:"mstyle", atname:"fontfamily", atval:"monospace", output:"tt", tex:null, ttype:UNARY},
       
   332 {input:"mathtt", tag:"mstyle", atname:"fontfamily", atval:"monospace", output:"mathtt", tex:null, ttype:UNARY},
       
   333 {input:"fr",  tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"fr", tex:null, ttype:UNARY, codes:AMfrk},
       
   334 {input:"mathfrak",  tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"mathfrak", tex:null, ttype:UNARY, codes:AMfrk}
       
   335 ];
       
   336 
       
   337 function compareNames(s1,s2) {
       
   338   if (s1.input > s2.input) return 1
       
   339   else return -1;
       
   340 }
       
   341 
       
   342 var AMnames = []; //list of input symbols
       
   343 
       
   344 function AMinitSymbols() {
       
   345   var texsymbols = [], i;
       
   346   for (i=0; i<AMsymbols.length; i++)
       
   347     if (AMsymbols[i].tex) 
       
   348       texsymbols[texsymbols.length] = {input:AMsymbols[i].tex, 
       
   349         tag:AMsymbols[i].tag, output:AMsymbols[i].output, ttype:AMsymbols[i].ttype};
       
   350   AMsymbols = AMsymbols.concat(texsymbols);
       
   351   AMsymbols.sort(compareNames);
       
   352   for (i=0; i<AMsymbols.length; i++) AMnames[i] = AMsymbols[i].input;
       
   353 }
       
   354 
       
   355 var AMmathml = "http://www.w3.org/1998/Math/MathML";
       
   356 
       
   357 function AMcreateElementMathML(t) {
       
   358   if (isIE) return document.createElement("m:"+t);
       
   359   else return document.createElementNS(AMmathml,t);
       
   360 }
       
   361 
       
   362 function AMcreateMmlNode(t,frag) {
       
   363 //  var node = AMcreateElementMathML(name);
       
   364   if (isIE) var node = document.createElement("m:"+t);
       
   365   else var node = document.createElementNS(AMmathml,t);
       
   366   node.appendChild(frag);
       
   367   return node;
       
   368 }
       
   369 
       
   370 function define(oldstr,newstr) {
       
   371   AMsymbols = AMsymbols.concat([{input:oldstr, tag:"mo", output:newstr, 
       
   372                                  tex:null, ttype:DEFINITION}]);
       
   373   AMsymbols.sort(compareNames);
       
   374   for (i=0; i<AMsymbols.length; i++) AMnames[i] = AMsymbols[i].input;
       
   375 }
       
   376 
       
   377 function AMremoveCharsAndBlanks(str,n) {
       
   378 //remove n characters and any following blanks
       
   379   var st;
       
   380   if (str.charAt(n)=="\\" && str.charAt(n+1)!="\\" && str.charAt(n+1)!=" ") 
       
   381     st = str.slice(n+1);
       
   382   else st = str.slice(n);
       
   383   for (var i=0; i<st.length && st.charCodeAt(i)<=32; i=i+1);
       
   384   return st.slice(i);
       
   385 }
       
   386 
       
   387 function AMposition(arr, str, n) { 
       
   388 // return position >=n where str appears or would be inserted
       
   389 // assumes arr is sorted
       
   390   if (n==0) {
       
   391     var h,m;
       
   392     n = -1;
       
   393     h = arr.length;
       
   394     while (n+1<h) {
       
   395       m = (n+h) >> 1;
       
   396       if (arr[m]<str) n = m; else h = m;
       
   397     }
       
   398     return h;
       
   399   } else
       
   400     for (var i=n; i<arr.length && arr[i]<str; i++);
       
   401   return i; // i=arr.length || arr[i]>=str
       
   402 }
       
   403 
       
   404 function AMgetSymbol(str) {
       
   405 //return maximal initial substring of str that appears in names
       
   406 //return null if there is none
       
   407   var k = 0; //new pos
       
   408   var j = 0; //old pos
       
   409   var mk; //match pos
       
   410   var st;
       
   411   var tagst;
       
   412   var match = "";
       
   413   var more = true;
       
   414   for (var i=1; i<=str.length && more; i++) {
       
   415     st = str.slice(0,i); //initial substring of length i
       
   416     j = k;
       
   417     k = AMposition(AMnames, st, j);
       
   418     if (k<AMnames.length && str.slice(0,AMnames[k].length)==AMnames[k]){
       
   419       match = AMnames[k];
       
   420       mk = k;
       
   421       i = match.length;
       
   422     }
       
   423     more = k<AMnames.length && str.slice(0,AMnames[k].length)>=AMnames[k];
       
   424   }
       
   425   AMpreviousSymbol=AMcurrentSymbol;
       
   426   if (match!=""){
       
   427     AMcurrentSymbol=AMsymbols[mk].ttype;
       
   428     return AMsymbols[mk]; 
       
   429   }
       
   430 // if str[0] is a digit or - return maxsubstring of digits.digits
       
   431   AMcurrentSymbol=CONST;
       
   432   k = 1;
       
   433   st = str.slice(0,1);
       
   434   var integ = true;
       
   435   while ("0"<=st && st<="9" && k<=str.length) {
       
   436     st = str.slice(k,k+1);
       
   437     k++;
       
   438   }
       
   439   if (st == decimalsign) {
       
   440     st = str.slice(k,k+1);
       
   441     if ("0"<=st && st<="9") {
       
   442       integ = false;
       
   443       k++;
       
   444       while ("0"<=st && st<="9" && k<=str.length) {
       
   445         st = str.slice(k,k+1);
       
   446         k++;
       
   447       }
       
   448     }
       
   449   }
       
   450   if ((integ && k>1) || k>2) {
       
   451     st = str.slice(0,k-1);
       
   452     tagst = "mn";
       
   453   } else {
       
   454     k = 2;
       
   455     st = str.slice(0,1); //take 1 character
       
   456     tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi");
       
   457   }
       
   458   if (st=="-" && AMpreviousSymbol==INFIX) {
       
   459     AMcurrentSymbol = INFIX;  //trick "/" into recognizing "-" on second parse
       
   460     return {input:st, tag:tagst, output:st, ttype:UNARY, func:true};
       
   461   }
       
   462   return {input:st, tag:tagst, output:st, ttype:CONST};
       
   463 }
       
   464 
       
   465 function AMremoveBrackets(node) {
       
   466   var st;
       
   467   if (node.nodeName=="mrow") {
       
   468     st = node.firstChild.firstChild.nodeValue;
       
   469     if (st=="(" || st=="[" || st=="{") node.removeChild(node.firstChild);
       
   470   }
       
   471   if (node.nodeName=="mrow") {
       
   472     st = node.lastChild.firstChild.nodeValue;
       
   473     if (st==")" || st=="]" || st=="}") node.removeChild(node.lastChild);
       
   474   }
       
   475 }
       
   476 
       
   477 /*Parsing ASCII math expressions with the following grammar
       
   478 v ::= [A-Za-z] | greek letters | numbers | other constant symbols
       
   479 u ::= sqrt | text | bb | other unary symbols for font commands
       
   480 b ::= frac | root | stackrel         binary symbols
       
   481 l ::= ( | [ | { | (: | {:            left brackets
       
   482 r ::= ) | ] | } | :) | :}            right brackets
       
   483 S ::= v | lEr | uS | bSS             Simple expression
       
   484 I ::= S_S | S^S | S_S^S | S          Intermediate expression
       
   485 E ::= IE | I/I                       Expression
       
   486 Each terminal symbol is translated into a corresponding mathml node.*/
       
   487 
       
   488 var AMnestingDepth,AMpreviousSymbol,AMcurrentSymbol;
       
   489 
       
   490 function AMparseSexpr(str) { //parses str and returns [node,tailstr]
       
   491   var symbol, node, result, i, st,// rightvert = false,
       
   492     newFrag = document.createDocumentFragment();
       
   493   str = AMremoveCharsAndBlanks(str,0);
       
   494   symbol = AMgetSymbol(str);             //either a token or a bracket or empty
       
   495   if (symbol == null || symbol.ttype == RIGHTBRACKET && AMnestingDepth > 0) {
       
   496     return [null,str];
       
   497   }
       
   498   if (symbol.ttype == DEFINITION) {
       
   499     str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   500     symbol = AMgetSymbol(str);
       
   501   }
       
   502   switch (symbol.ttype) {
       
   503   case UNDEROVER:
       
   504   case CONST:
       
   505     str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   506     return [AMcreateMmlNode(symbol.tag,        //its a constant
       
   507                              document.createTextNode(symbol.output)),str];
       
   508   case LEFTBRACKET:   //read (expr+)
       
   509     AMnestingDepth++;
       
   510     str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   511     result = AMparseExpr(str,true);
       
   512     AMnestingDepth--;
       
   513     if (typeof symbol.invisible == "boolean" && symbol.invisible) 
       
   514       node = AMcreateMmlNode("mrow",result[0]);
       
   515     else {
       
   516       node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
       
   517       node = AMcreateMmlNode("mrow",node);
       
   518       node.appendChild(result[0]);
       
   519     }
       
   520     return [node,result[1]];
       
   521   case TEXT:
       
   522       if (symbol!=AMquote) str = AMremoveCharsAndBlanks(str,symbol.input.length);
       
   523       if (str.charAt(0)=="{") i=str.indexOf("}");
       
   524       else if (str.charAt(0)=="(") i=str.indexOf(")");
       
   525       else if (str.charAt(0)=="[") i=str.indexOf("]");
       
   526       else if (symbol==AMquote) i=str.slice(1).indexOf("\"")+1;
       
   527       else i = 0;
       
   528       if (i==-1) i = str.length;
       
   529       st = str.slice(1,i);
       
   530       if (st.charAt(0) == " ") {
       
   531         node = AMcreateElementMathML("mspace");
       
   532         node.setAttribute("width","1ex");
       
   533         newFrag.appendChild(node);
       
   534       }
       
   535       newFrag.appendChild(
       
   536         AMcreateMmlNode(symbol.tag,document.createTextNode(st)));
       
   537       if (st.charAt(st.length-1) == " ") {
       
   538         node = AMcreateElementMathML("mspace");
       
   539         node.setAttribute("width","1ex");
       
   540         newFrag.appendChild(node);
       
   541       }
       
   542       str = AMremoveCharsAndBlanks(str,i+1);
       
   543       return [AMcreateMmlNode("mrow",newFrag),str];
       
   544   case UNARY:
       
   545       str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   546       result = AMparseSexpr(str);
       
   547       if (result[0]==null) return [AMcreateMmlNode(symbol.tag,
       
   548                              document.createTextNode(symbol.output)),str];
       
   549       if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
       
   550         st = str.charAt(0);
       
   551         if (st=="^" || st=="_" || st=="/" || st=="|" || st==",") {
       
   552           return [AMcreateMmlNode(symbol.tag,
       
   553                     document.createTextNode(symbol.output)),str];
       
   554         } else {
       
   555           node = AMcreateMmlNode("mrow",
       
   556            AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
       
   557           node.appendChild(result[0]);
       
   558           return [node,result[1]];
       
   559         }
       
   560       }
       
   561       AMremoveBrackets(result[0]);
       
   562       if (symbol.input == "sqrt") {           // sqrt
       
   563         return [AMcreateMmlNode(symbol.tag,result[0]),result[1]];
       
   564       } else if (typeof symbol.acc == "boolean" && symbol.acc) {   // accent
       
   565         node = AMcreateMmlNode(symbol.tag,result[0]);
       
   566         node.appendChild(AMcreateMmlNode("mo",document.createTextNode(symbol.output)));
       
   567         return [node,result[1]];
       
   568       } else {                        // font change command
       
   569         if (!isIE && typeof symbol.codes != "undefined") {
       
   570           for (i=0; i<result[0].childNodes.length; i++)
       
   571             if (result[0].childNodes[i].nodeName=="mi" || result[0].nodeName=="mi") {
       
   572               st = (result[0].nodeName=="mi"?result[0].firstChild.nodeValue:
       
   573                               result[0].childNodes[i].firstChild.nodeValue);
       
   574               var newst = [];
       
   575               for (var j=0; j<st.length; j++)
       
   576                 if (st.charCodeAt(j)>64 && st.charCodeAt(j)<91) newst = newst +
       
   577                   String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);
       
   578                 else newst = newst + st.charAt(j);
       
   579               if (result[0].nodeName=="mi")
       
   580                 result[0]=AMcreateElementMathML("mo").
       
   581                           appendChild(document.createTextNode(newst));
       
   582               else result[0].replaceChild(AMcreateElementMathML("mo").
       
   583           appendChild(document.createTextNode(newst)),result[0].childNodes[i]);
       
   584             }
       
   585         }
       
   586         node = AMcreateMmlNode(symbol.tag,result[0]);
       
   587         node.setAttribute(symbol.atname,symbol.atval);
       
   588         return [node,result[1]];
       
   589       }
       
   590   case BINARY:
       
   591     str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   592     result = AMparseSexpr(str);
       
   593     if (result[0]==null) return [AMcreateMmlNode("mo",
       
   594                            document.createTextNode(symbol.input)),str];
       
   595     AMremoveBrackets(result[0]);
       
   596     var result2 = AMparseSexpr(result[1]);
       
   597     if (result2[0]==null) return [AMcreateMmlNode("mo",
       
   598                            document.createTextNode(symbol.input)),str];
       
   599     AMremoveBrackets(result2[0]);
       
   600     if (symbol.input=="root" || symbol.input=="stackrel") 
       
   601       newFrag.appendChild(result2[0]);
       
   602     newFrag.appendChild(result[0]);
       
   603     if (symbol.input=="frac") newFrag.appendChild(result2[0]);
       
   604     return [AMcreateMmlNode(symbol.tag,newFrag),result2[1]];
       
   605   case INFIX:
       
   606     str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   607     return [AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str];
       
   608   case SPACE:
       
   609     str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   610     node = AMcreateElementMathML("mspace");
       
   611     node.setAttribute("width","1ex");
       
   612     newFrag.appendChild(node);
       
   613     newFrag.appendChild(
       
   614       AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
       
   615     node = AMcreateElementMathML("mspace");
       
   616     node.setAttribute("width","1ex");
       
   617     newFrag.appendChild(node);
       
   618     return [AMcreateMmlNode("mrow",newFrag),str];
       
   619   case LEFTRIGHT:
       
   620 //    if (rightvert) return [null,str]; else rightvert = true;
       
   621     AMnestingDepth++;
       
   622     str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   623     result = AMparseExpr(str,false);
       
   624     AMnestingDepth--;
       
   625     var st = "";
       
   626     if (result[0].lastChild!=null)
       
   627       st = result[0].lastChild.firstChild.nodeValue;
       
   628     if (st == "|") { // its an absolute value subterm
       
   629       node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
       
   630       node = AMcreateMmlNode("mrow",node);
       
   631       node.appendChild(result[0]);
       
   632       return [node,result[1]];
       
   633     } else { // the "|" is a \mid
       
   634       node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
       
   635       node = AMcreateMmlNode("mrow",node);
       
   636       return [node,str];
       
   637     }
       
   638   default:
       
   639 //alert("default");
       
   640     str = AMremoveCharsAndBlanks(str,symbol.input.length); 
       
   641     return [AMcreateMmlNode(symbol.tag,        //its a constant
       
   642                              document.createTextNode(symbol.output)),str];
       
   643   }
       
   644 }
       
   645 
       
   646 function AMparseIexpr(str) {
       
   647   var symbol, sym1, sym2, node, result, underover;
       
   648   str = AMremoveCharsAndBlanks(str,0);
       
   649   sym1 = AMgetSymbol(str);
       
   650   result = AMparseSexpr(str);
       
   651   node = result[0];
       
   652   str = result[1];
       
   653   symbol = AMgetSymbol(str);
       
   654   if (symbol.ttype == INFIX && symbol.input != "/") {
       
   655     str = AMremoveCharsAndBlanks(str,symbol.input.length);
       
   656 //    if (symbol.input == "/") result = AMparseIexpr(str); else ...
       
   657     result = AMparseSexpr(str);
       
   658     if (result[0] == null) // show box in place of missing argument
       
   659       result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1"));
       
   660     else AMremoveBrackets(result[0]);
       
   661     str = result[1];
       
   662 //    if (symbol.input == "/") AMremoveBrackets(node);
       
   663     if (symbol.input == "_") {
       
   664       sym2 = AMgetSymbol(str);
       
   665       underover = (sym1.ttype == UNDEROVER);
       
   666       if (sym2.input == "^") {
       
   667         str = AMremoveCharsAndBlanks(str,sym2.input.length);
       
   668         var res2 = AMparseSexpr(str);
       
   669         AMremoveBrackets(res2[0]);
       
   670         str = res2[1];
       
   671         node = AMcreateMmlNode((underover?"munderover":"msubsup"),node);
       
   672         node.appendChild(result[0]);
       
   673         node.appendChild(res2[0]);
       
   674         node = AMcreateMmlNode("mrow",node); // so sum does not stretch
       
   675       } else {
       
   676         node = AMcreateMmlNode((underover?"munder":"msub"),node);
       
   677         node.appendChild(result[0]);
       
   678       }
       
   679     } else {
       
   680       node = AMcreateMmlNode(symbol.tag,node);
       
   681       node.appendChild(result[0]);
       
   682     }
       
   683   }
       
   684   return [node,str];
       
   685 }
       
   686 
       
   687 function AMparseExpr(str,rightbracket) {
       
   688   var symbol, node, result, i, nodeList = [],
       
   689   newFrag = document.createDocumentFragment();
       
   690   do {
       
   691     str = AMremoveCharsAndBlanks(str,0);
       
   692     result = AMparseIexpr(str);
       
   693     node = result[0];
       
   694     str = result[1];
       
   695     symbol = AMgetSymbol(str);
       
   696     if (symbol.ttype == INFIX && symbol.input == "/") {
       
   697       str = AMremoveCharsAndBlanks(str,symbol.input.length);
       
   698       result = AMparseIexpr(str);
       
   699       if (result[0] == null) // show box in place of missing argument
       
   700         result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1"));
       
   701       else AMremoveBrackets(result[0]);
       
   702       str = result[1];
       
   703       AMremoveBrackets(node);
       
   704       node = AMcreateMmlNode(symbol.tag,node);
       
   705       node.appendChild(result[0]);
       
   706       newFrag.appendChild(node);
       
   707       symbol = AMgetSymbol(str);
       
   708     } 
       
   709     else if (node!=undefined) newFrag.appendChild(node);
       
   710   } while ((symbol.ttype != RIGHTBRACKET && 
       
   711            (symbol.ttype != LEFTRIGHT || rightbracket)
       
   712            || AMnestingDepth == 0) && symbol!=null && symbol.output!="");
       
   713   if (symbol.ttype == RIGHTBRACKET || symbol.ttype == LEFTRIGHT) {
       
   714 //    if (AMnestingDepth > 0) AMnestingDepth--;
       
   715     var len = newFrag.childNodes.length;
       
   716     if (len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 &&
       
   717       newFrag.childNodes[len-2].nodeName == "mo" &&
       
   718       newFrag.childNodes[len-2].firstChild.nodeValue == ",") { //matrix
       
   719       var right = newFrag.childNodes[len-1].lastChild.firstChild.nodeValue;
       
   720       if (right==")" || right=="]") {
       
   721         var left = newFrag.childNodes[len-1].firstChild.firstChild.nodeValue;
       
   722         if (left=="(" && right==")" && symbol.output != "}" || 
       
   723             left=="[" && right=="]") {
       
   724         var pos = []; // positions of commas
       
   725         var matrix = true;
       
   726         var m = newFrag.childNodes.length;
       
   727         for (i=0; matrix && i<m; i=i+2) {
       
   728           pos[i] = [];
       
   729           node = newFrag.childNodes[i];
       
   730           if (matrix) matrix = node.nodeName=="mrow" && 
       
   731             (i==m-1 || node.nextSibling.nodeName=="mo" && 
       
   732             node.nextSibling.firstChild.nodeValue==",")&&
       
   733             node.firstChild.firstChild.nodeValue==left &&
       
   734             node.lastChild.firstChild.nodeValue==right;
       
   735           if (matrix) 
       
   736             for (var j=0; j<node.childNodes.length; j++)
       
   737               if (node.childNodes[j].firstChild.nodeValue==",")
       
   738                 pos[i][pos[i].length]=j;
       
   739           if (matrix && i>1) matrix = pos[i].length == pos[i-2].length;
       
   740         }
       
   741         if (matrix) {
       
   742           var row, frag, n, k, table = document.createDocumentFragment();
       
   743           for (i=0; i<m; i=i+2) {
       
   744             row = document.createDocumentFragment();
       
   745             frag = document.createDocumentFragment();
       
   746             node = newFrag.firstChild; // <mrow>(-,-,...,-,-)</mrow>
       
   747             n = node.childNodes.length;
       
   748             k = 0;
       
   749             node.removeChild(node.firstChild); //remove (
       
   750             for (j=1; j<n-1; j++) {
       
   751               if (typeof pos[i][k] != "undefined" && j==pos[i][k]){
       
   752                 node.removeChild(node.firstChild); //remove ,
       
   753                 row.appendChild(AMcreateMmlNode("mtd",frag));
       
   754                 k++;
       
   755               } else frag.appendChild(node.firstChild);
       
   756             }
       
   757             row.appendChild(AMcreateMmlNode("mtd",frag));
       
   758             if (newFrag.childNodes.length>2) {
       
   759               newFrag.removeChild(newFrag.firstChild); //remove <mrow>)</mrow>
       
   760               newFrag.removeChild(newFrag.firstChild); //remove <mo>,</mo>
       
   761             }
       
   762             table.appendChild(AMcreateMmlNode("mtr",row));
       
   763           }
       
   764           node = AMcreateMmlNode("mtable",table);
       
   765           if (typeof symbol.invisible == "boolean" && symbol.invisible) node.setAttribute("columnalign","left");
       
   766           newFrag.replaceChild(node,newFrag.firstChild);
       
   767         }
       
   768        }
       
   769       }
       
   770     }
       
   771     str = AMremoveCharsAndBlanks(str,symbol.input.length);
       
   772     if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
       
   773       node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
       
   774       newFrag.appendChild(node);
       
   775     }
       
   776   }
       
   777   return [newFrag,str];
       
   778 }
       
   779 
       
   780 function AMparseMath(str) {
       
   781   var result, node = AMcreateElementMathML("mstyle");
       
   782   if (mathcolor != "") node.setAttribute("mathcolor",mathcolor);
       
   783   if (displaystyle) node.setAttribute("displaystyle","true");
       
   784   if (mathfontfamily != "") node.setAttribute("fontfamily",mathfontfamily);
       
   785   AMnestingDepth = 0;
       
   786   node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false)[0]);
       
   787   node = AMcreateMmlNode("math",node);
       
   788   if (showasciiformulaonhover)                      //fixed by djhsu so newline
       
   789     node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko
       
   790   var fnode = AMcreateElementXHTML("span");
       
   791   fnode.style.fontSize = mathfontsize;
       
   792   if (mathfontfamily != "") fnode.style.fontFamily = mathfontfamily;
       
   793   fnode.appendChild(node);
       
   794   return fnode;
       
   795 }
       
   796 
       
   797 function AMstrarr2docFrag(arr, linebreaks) {
       
   798   var newFrag=document.createDocumentFragment();
       
   799   var expr = false;
       
   800   for (var i=0; i<arr.length; i++) {
       
   801     if (expr) newFrag.appendChild(AMparseMath(arr[i]));
       
   802     else {
       
   803       var arri = (linebreaks ? arr[i].split("\n\n") : [arr[i]]);
       
   804       newFrag.appendChild(AMcreateElementXHTML("span").
       
   805       appendChild(document.createTextNode(arri[0])));
       
   806       for (var j=1; j<arri.length; j++) {
       
   807         newFrag.appendChild(AMcreateElementXHTML("p"));
       
   808         newFrag.appendChild(AMcreateElementXHTML("span").
       
   809         appendChild(document.createTextNode(arri[j])));
       
   810       }
       
   811     }
       
   812     expr = !expr;
       
   813   }
       
   814   return newFrag;
       
   815 }
       
   816 
       
   817 function AMautomathrec(str) {
       
   818 //formula is a space (or start of str) followed by a maximal sequence of *two* or more tokens, possibly separated by runs of digits and/or space.
       
   819 //tokens are single letters (except a, A, I) and ASCIIMathML tokens
       
   820   var texcommand = "\\\\[a-zA-Z]+|\\\\\\s|";
       
   821   var ambigAMtoken = "\\b(?:oo|lim|ln|int|oint|del|grad|aleph|prod|prop|sinh|cosh|tanh|cos|sec|pi|tt|fr|sf|sube|supe|sub|sup|det|mod|gcd|lcm|min|max|vec|ddot|ul|chi|eta|nu|mu)(?![a-z])|";
       
   822   var englishAMtoken = "\\b(?:sum|ox|log|sin|tan|dim|hat|bar|dot)(?![a-z])|";
       
   823   var secondenglishAMtoken = "|\\bI\\b|\\bin\\b|\\btext\\b"; // took if and or not out
       
   824   var simpleAMtoken = "NN|ZZ|QQ|RR|CC|TT|AA|EE|sqrt|dx|dy|dz|dt|xx|vv|uu|nn|bb|cc|csc|cot|alpha|beta|delta|Delta|epsilon|gamma|Gamma|kappa|lambda|Lambda|omega|phi|Phi|Pi|psi|Psi|rho|sigma|Sigma|tau|theta|Theta|xi|Xi|zeta"; // uuu nnn?
       
   825   var letter = "[a-zA-HJ-Z](?=(?:[^a-zA-Z]|$|"+ambigAMtoken+englishAMtoken+simpleAMtoken+"))|";
       
   826   var token = letter+texcommand+"\\d+|[-()[\\]{}+=*&^_%@/<>,\\|!:;'~]|\\.(?!(?:\x20|$))|"+ambigAMtoken+englishAMtoken+simpleAMtoken;
       
   827   var re = new RegExp("(^|\\s)((("+token+")\\s?)(("+token+secondenglishAMtoken+")\\s?)+)([,.?]?(?=\\s|$))","g");
       
   828   str = str.replace(re," `$2`$7");
       
   829   var arr = str.split(AMdelimiter1);
       
   830   var re1 = new RegExp("(^|\\s)([b-zB-HJ-Z+*<>]|"+texcommand+ambigAMtoken+simpleAMtoken+")(\\s|\\n|$)","g");
       
   831   var re2 = new RegExp("(^|\\s)([a-z]|"+texcommand+ambigAMtoken+simpleAMtoken+")([,.])","g"); // removed |\d+ for now
       
   832   for (i=0; i<arr.length; i++)   //single nonenglish tokens
       
   833     if (i%2==0) {
       
   834       arr[i] = arr[i].replace(re1," `$2`$3");
       
   835       arr[i] = arr[i].replace(re2," `$2`$3");
       
   836       arr[i] = arr[i].replace(/([{}[\]])/,"`$1`");
       
   837     }
       
   838   str = arr.join(AMdelimiter1);
       
   839   str = str.replace(/(\([a-zA-Z]{2,}.*?)\)`/g,"$1`)");  //fix parentheses
       
   840   str = str.replace(/`(\((a\s|in\s))(.*?[a-zA-Z]{2,}\))/g,"$1`$3");  //fix parentheses
       
   841   str = str.replace(/\sin`/g,"` in");
       
   842   str = str.replace(/`(\(\w\)[,.]?(\s|\n|$))/g,"$1`");
       
   843   str = str.replace(/`([0-9.]+|e.g)`(\\.)/gi,"$1$2");
       
   844   str = str.replace(/`([0-9.]:)`/g,"$1");
       
   845   return str;
       
   846 }
       
   847 
       
   848 function AMprocessNodeR(n, linebreaks) {
       
   849   var mtch, str, arr, frg, i;
       
   850   if (n.childNodes.length == 0) {
       
   851    if ((n.nodeType!=8 || linebreaks) &&
       
   852     n.parentNode.nodeName!="form" && n.parentNode.nodeName!="FORM" &&
       
   853     n.parentNode.nodeName!="textarea" && n.parentNode.nodeName!="TEXTAREA" &&
       
   854     n.parentNode.nodeName!="pre" && n.parentNode.nodeName!="PRE") {
       
   855     str = n.nodeValue;
       
   856     if (!(str == null)) {
       
   857       str = str.replace(/\r\n\r\n/g,"\n\n");
       
   858       str = str.replace(/\x20+/g," ");
       
   859       str = str.replace(/\s*\r\n/g," ");
       
   860       mtch = false;
       
   861       str = str.replace(new RegExp(AMescape1, "g"),
       
   862               function(){mtch = true; return "AMescape1"});
       
   863       str = str.replace(/\\?end{?a?math}?/i,
       
   864               function(){automathrecognize = false; mtch = true; return ""});
       
   865       str = str.replace(/amath|\\begin{a?math}/i,
       
   866               function(){automathrecognize = true; mtch = true; return ""});
       
   867       arr = str.split(AMdelimiter1);
       
   868       if (automathrecognize)
       
   869         for (i=0; i<arr.length; i++)
       
   870           if (i%2==0) arr[i] = AMautomathrec(arr[i]);
       
   871       str = arr.join(AMdelimiter1);
       
   872       arr = str.split(AMdelimiter1);
       
   873       for (i=0; i<arr.length; i++) // this is a problem ************
       
   874         arr[i]=arr[i].replace(/AMescape1/g,AMdelimiter1);
       
   875       if (arr.length>1 || mtch) {
       
   876         if (checkForMathML) {
       
   877           checkForMathML = false;
       
   878           var nd = AMisMathMLavailable();
       
   879           AMnoMathML = nd != null;
       
   880           if (AMnoMathML && notifyIfNoMathML) 
       
   881             if (alertIfNoMathML)
       
   882               alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\n\
       
   883                 or Firefox/Mozilla/Netscape");
       
   884             else AMbody.insertBefore(nd,AMbody.childNodes[0]);
       
   885         }
       
   886         if (!AMnoMathML) {
       
   887           frg = AMstrarr2docFrag(arr,n.nodeType==8);
       
   888           var len = frg.childNodes.length;
       
   889           n.parentNode.replaceChild(frg,n);
       
   890           return len-1;
       
   891         } else return 0;
       
   892       }
       
   893     }
       
   894    } else return 0;
       
   895   } else if (n.nodeName!="math") {
       
   896     for (i=0; i<n.childNodes.length; i++)
       
   897       i += AMprocessNodeR(n.childNodes[i], linebreaks);
       
   898   }
       
   899   return 0;
       
   900 }
       
   901 
       
   902 function AMprocessNode(n, linebreaks, spanclassAM) {
       
   903   var frag,st;
       
   904   if (spanclassAM!=null) {
       
   905     frag = document.getElementsByTagName("span")
       
   906     for (var i=0;i<frag.length;i++)
       
   907       if (frag[i].className == "AM")
       
   908         AMprocessNodeR(frag[i],linebreaks);
       
   909   } else {
       
   910     try {
       
   911       st = n.innerHTML; // look for AMdelimiter on page
       
   912     } catch(err) {}
       
   913     if (st==null || /amath|\\begin{a?math}/i.test(st) ||
       
   914       st.indexOf(AMdelimiter1+" ")!=-1 || st.slice(-1)==AMdelimiter1 ||
       
   915       st.indexOf(AMdelimiter1+"<")!=-1 || st.indexOf(AMdelimiter1+"\n")!=-1) {
       
   916       AMprocessNodeR(n,linebreaks);
       
   917     }
       
   918   }
       
   919   if (isIE) { //needed to match size and font of formula to surrounding text
       
   920     frag = document.getElementsByTagName('math');
       
   921     for (var i=0;i<frag.length;i++) frag[i].update()
       
   922   }
       
   923 }
       
   924 
       
   925 var AMbody;
       
   926 var AMnoMathML = false, AMtranslated = false;
       
   927 
       
   928 function translate(spanclassAM) {
       
   929   if (!AMtranslated) { // run this only once
       
   930     AMtranslated = true;
       
   931     AMbody = document.getElementsByTagName("body")[0];
       
   932     var processN = document.getElementById(AMdocumentId);
       
   933 //    var processN = getElementsByClass(AMbody,"div",AMdocumentClass);
       
   934     AMprocessNode((processN!=null?processN:AMbody), false, spanclassAM);
       
   935   }
       
   936 }
       
   937 
       
   938 AMinitSymbols();
       
   939 
       
   940 /*
       
   941 LaTeXMathML.js
       
   942 ==============
       
   943 
       
   944 Version 1.1, July 20, 2007 (c) modifications by Peter Jipsen
       
   945 
       
   946 (changes: renamed global variables from AM... to LM... so that
       
   947 LaTeXMathML and ASCIIMathML can be used simultaneously)
       
   948 
       
   949 Previous header notice:
       
   950 This file (Version 1.0), is due to Douglas Woodall, June 2006.
       
   951 It contains JavaScript functions to convert (most simple) LaTeX
       
   952 math notation to Presentation MathML.  It was obtained by
       
   953 downloading the file ASCIIMathML.js from
       
   954 	http://www1.chapman.edu/~jipsen/mathml/asciimathdownload/
       
   955 and modifying it so that it carries out ONLY those conversions
       
   956 that would be carried out in LaTeX.  A description of the original
       
   957 file, with examples, can be found at
       
   958 	www1.chapman.edu/~jipsen/mathml/asciimath.html
       
   959 	ASCIIMathML: Math on the web for everyone
       
   960 
       
   961 Here is the header notice from the original file:
       
   962 
       
   963 ASCIIMathML.js
       
   964 ==============
       
   965 This file contains JavaScript functions to convert ASCII math notation
       
   966 to Presentation MathML. The conversion is done while the (X)HTML page
       
   967 loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet
       
   968 Explorer 6+MathPlayer (http://www.dessci.com/en/products/mathplayer/).
       
   969 Just add the next line to your (X)HTML page with this file in the same folder:
       
   970 <script type="text/javascript" src="ASCIIMathML.js"></script>
       
   971 This is a convenient and inexpensive solution for authoring MathML.
       
   972 
       
   973 Version 1.4.7 Dec 15, 2005, (c) Peter Jipsen http://www.chapman.edu/~jipsen
       
   974 Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js
       
   975 For changes see http://www.chapman.edu/~jipsen/mathml/asciimathchanges.txt
       
   976 If you use it on a webpage, please send the URL to jipsen@chapman.edu
       
   977 
       
   978 This program is free software; you can redistribute it and/or modify
       
   979 it under the terms of the GNU Lesser General Public License as published by
       
   980 the Free Software Foundation; either version 2.1 of the License, or (at
       
   981 your option) any later version.
       
   982 
       
   983 This program is distributed in the hope that it will be useful,
       
   984 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
   985 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
       
   986 General Public License (at http://www.gnu.org/license/lgpl.html)
       
   987 for more details.
       
   988 
       
   989 LaTeXMathML.js (ctd)
       
   990 ==============
       
   991 
       
   992 Content between $...$ and $$...$$ is converted by this part of the file
       
   993 */
       
   994 
       
   995 var LMcheckForMathML = true;   // check if browser can display MathML
       
   996 var LMnotifyIfNoMathML = true; // display note if no MathML capability
       
   997 var LMalertIfNoMathML = false;  // show alert box if no MathML capability
       
   998 var LMmathcolor = "";	     // "" (to inherit) or change to another color
       
   999 var LMmathfontfamily = "serif"; // change to "" to inherit (works in IE)
       
  1000                                 // or another family (e.g. "arial")
       
  1001 var LMshowasciiformulaonhover = true; // helps students learn LaTeX
       
  1002 
       
  1003 // all further global variables start with "LM"
       
  1004 
       
  1005 function LMcreateElementXHTML(t) {
       
  1006   if (isIE) return document.createElement(t);
       
  1007   else return document.createElementNS("http://www.w3.org/1999/xhtml",t);
       
  1008 }
       
  1009 
       
  1010 function LMnoMathMLNote() {
       
  1011   var nd = LMcreateElementXHTML("h3");
       
  1012   nd.setAttribute("align","center")
       
  1013   nd.appendChild(LMcreateElementXHTML("p"));
       
  1014   nd.appendChild(document.createTextNode("To view the "));
       
  1015   var an = LMcreateElementXHTML("a");
       
  1016   an.appendChild(document.createTextNode("LaTeXMathML"));
       
  1017   an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");
       
  1018   nd.appendChild(an);
       
  1019   nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+")); 
       
  1020   an = LMcreateElementXHTML("a");
       
  1021   an.appendChild(document.createTextNode("MathPlayer"));
       
  1022   an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");
       
  1023   nd.appendChild(an);
       
  1024   nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));
       
  1025   nd.appendChild(LMcreateElementXHTML("p"));
       
  1026   return nd;
       
  1027 }
       
  1028 
       
  1029 function LMisMathMLavailable() {
       
  1030   if (navigator.appName.slice(0,8)=="Netscape")
       
  1031     if (navigator.appVersion.slice(0,1)>="5") return null;
       
  1032     else return LMnoMathMLNote();
       
  1033   else if (navigator.appName.slice(0,9)=="Microsoft")
       
  1034     try {
       
  1035         var ActiveX = new ActiveXObject("MathPlayer.Factory.1");
       
  1036         return null;
       
  1037     } catch (e) {
       
  1038         return LMnoMathMLNote();
       
  1039     }
       
  1040   else return LMnoMathMLNote();
       
  1041 }
       
  1042 
       
  1043 // character lists for Mozilla/Netscape fonts
       
  1044 var LMcal = [0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];
       
  1045 var LMfrk = [0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];
       
  1046 var LMbbb = [0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];
       
  1047 
       
  1048 //var CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4,
       
  1049 //    RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8, TEXT = 10, 
       
  1050 var BIG = 11, LONG = 12, STRETCHY = 13, MATRIX = 14; // token types
       
  1051 
       
  1052 var LMsqrt = {input:"\\sqrt",	tag:"msqrt", output:"sqrt",	ttype:UNARY},
       
  1053   LMroot = {input:"\\root",	tag:"mroot", output:"root",	ttype:BINARY},
       
  1054   LMfrac = {input:"\\frac",	tag:"mfrac", output:"/",	ttype:BINARY},
       
  1055   LMover = {input:"\\stackrel", tag:"mover", output:"stackrel", ttype:BINARY},
       
  1056   LMatop = {input:"\\atop",	tag:"mfrac", output:"",		ttype:INFIX},
       
  1057   LMchoose = {input:"\\choose", tag:"mfrac", output:"",		ttype:INFIX},
       
  1058   LMsub  = {input:"_",		tag:"msub",  output:"_",	ttype:INFIX},
       
  1059   LMsup  = {input:"^",		tag:"msup",  output:"^",	ttype:INFIX},
       
  1060   LMtext = {input:"\\mathrm",	tag:"mtext", output:"text",	ttype:TEXT},
       
  1061   LMmbox = {input:"\\mbox",	tag:"mtext", output:"mbox",	ttype:TEXT};
       
  1062 
       
  1063 // Commented out by DRW to prevent 1/2 turning into a 2-line fraction
       
  1064 // LMdiv   = {input:"/",	 tag:"mfrac", output:"/",    ttype:INFIX},
       
  1065 // Commented out by DRW so that " prints literally in equations
       
  1066 // LMquote = {input:"\"",	 tag:"mtext", output:"mbox", ttype:TEXT};
       
  1067 
       
  1068 var LMsymbols = [
       
  1069 //Greek letters
       
  1070 {input:"\\alpha",	tag:"mi", output:"\u03B1", ttype:CONST},
       
  1071 {input:"\\beta",	tag:"mi", output:"\u03B2", ttype:CONST},
       
  1072 {input:"\\gamma",	tag:"mi", output:"\u03B3", ttype:CONST},
       
  1073 {input:"\\delta",	tag:"mi", output:"\u03B4", ttype:CONST},
       
  1074 {input:"\\epsilon",	tag:"mi", output:"\u03B5", ttype:CONST},
       
  1075 {input:"\\varepsilon",  tag:"mi", output:"\u025B", ttype:CONST},
       
  1076 {input:"\\zeta",	tag:"mi", output:"\u03B6", ttype:CONST},
       
  1077 {input:"\\eta",		tag:"mi", output:"\u03B7", ttype:CONST},
       
  1078 {input:"\\theta",	tag:"mi", output:"\u03B8", ttype:CONST},
       
  1079 {input:"\\vartheta",	tag:"mi", output:"\u03D1", ttype:CONST},
       
  1080 {input:"\\iota",	tag:"mi", output:"\u03B9", ttype:CONST},
       
  1081 {input:"\\kappa",	tag:"mi", output:"\u03BA", ttype:CONST},
       
  1082 {input:"\\lambda",	tag:"mi", output:"\u03BB", ttype:CONST},
       
  1083 {input:"\\mu",		tag:"mi", output:"\u03BC", ttype:CONST},
       
  1084 {input:"\\nu",		tag:"mi", output:"\u03BD", ttype:CONST},
       
  1085 {input:"\\xi",		tag:"mi", output:"\u03BE", ttype:CONST},
       
  1086 {input:"\\pi",		tag:"mi", output:"\u03C0", ttype:CONST},
       
  1087 {input:"\\varpi",	tag:"mi", output:"\u03D6", ttype:CONST},
       
  1088 {input:"\\rho",		tag:"mi", output:"\u03C1", ttype:CONST},
       
  1089 {input:"\\varrho",	tag:"mi", output:"\u03F1", ttype:CONST},
       
  1090 {input:"\\varsigma",	tag:"mi", output:"\u03C2", ttype:CONST},
       
  1091 {input:"\\sigma",	tag:"mi", output:"\u03C3", ttype:CONST},
       
  1092 {input:"\\tau",		tag:"mi", output:"\u03C4", ttype:CONST},
       
  1093 {input:"\\upsilon",	tag:"mi", output:"\u03C5", ttype:CONST},
       
  1094 {input:"\\phi",		tag:"mi", output:"\u03C6", ttype:CONST},
       
  1095 {input:"\\varphi",	tag:"mi", output:"\u03D5", ttype:CONST},
       
  1096 {input:"\\chi",		tag:"mi", output:"\u03C7", ttype:CONST},
       
  1097 {input:"\\psi",		tag:"mi", output:"\u03C8", ttype:CONST},
       
  1098 {input:"\\omega",	tag:"mi", output:"\u03C9", ttype:CONST},
       
  1099 {input:"\\Gamma",	tag:"mo", output:"\u0393", ttype:CONST},
       
  1100 {input:"\\Delta",	tag:"mo", output:"\u0394", ttype:CONST},
       
  1101 {input:"\\Theta",	tag:"mo", output:"\u0398", ttype:CONST},
       
  1102 {input:"\\Lambda",	tag:"mo", output:"\u039B", ttype:CONST},
       
  1103 {input:"\\Xi",		tag:"mo", output:"\u039E", ttype:CONST},
       
  1104 {input:"\\Pi",		tag:"mo", output:"\u03A0", ttype:CONST},
       
  1105 {input:"\\Sigma",	tag:"mo", output:"\u03A3", ttype:CONST},
       
  1106 {input:"\\Upsilon",	tag:"mo", output:"\u03A5", ttype:CONST},
       
  1107 {input:"\\Phi",		tag:"mo", output:"\u03A6", ttype:CONST},
       
  1108 {input:"\\Psi",		tag:"mo", output:"\u03A8", ttype:CONST},
       
  1109 {input:"\\Omega",	tag:"mo", output:"\u03A9", ttype:CONST},
       
  1110 
       
  1111 //fractions
       
  1112 {input:"\\frac12",	tag:"mo", output:"\u00BD", ttype:CONST},
       
  1113 {input:"\\frac14",	tag:"mo", output:"\u00BC", ttype:CONST},
       
  1114 {input:"\\frac34",	tag:"mo", output:"\u00BE", ttype:CONST},
       
  1115 {input:"\\frac13",	tag:"mo", output:"\u2153", ttype:CONST},
       
  1116 {input:"\\frac23",	tag:"mo", output:"\u2154", ttype:CONST},
       
  1117 {input:"\\frac15",	tag:"mo", output:"\u2155", ttype:CONST},
       
  1118 {input:"\\frac25",	tag:"mo", output:"\u2156", ttype:CONST},
       
  1119 {input:"\\frac35",	tag:"mo", output:"\u2157", ttype:CONST},
       
  1120 {input:"\\frac45",	tag:"mo", output:"\u2158", ttype:CONST},
       
  1121 {input:"\\frac16",	tag:"mo", output:"\u2159", ttype:CONST},
       
  1122 {input:"\\frac56",	tag:"mo", output:"\u215A", ttype:CONST},
       
  1123 {input:"\\frac18",	tag:"mo", output:"\u215B", ttype:CONST},
       
  1124 {input:"\\frac38",	tag:"mo", output:"\u215C", ttype:CONST},
       
  1125 {input:"\\frac58",	tag:"mo", output:"\u215D", ttype:CONST},
       
  1126 {input:"\\frac78",	tag:"mo", output:"\u215E", ttype:CONST},
       
  1127 
       
  1128 //binary operation symbols
       
  1129 {input:"\\pm",		tag:"mo", output:"\u00B1", ttype:CONST},
       
  1130 {input:"\\mp",		tag:"mo", output:"\u2213", ttype:CONST},
       
  1131 {input:"\\triangleleft",tag:"mo", output:"\u22B2", ttype:CONST},
       
  1132 {input:"\\triangleright",tag:"mo",output:"\u22B3", ttype:CONST},
       
  1133 {input:"\\cdot",	tag:"mo", output:"\u22C5", ttype:CONST},
       
  1134 {input:"\\star",	tag:"mo", output:"\u22C6", ttype:CONST},
       
  1135 {input:"\\ast",		tag:"mo", output:"\u002A", ttype:CONST},
       
  1136 {input:"\\times",	tag:"mo", output:"\u00D7", ttype:CONST},
       
  1137 {input:"\\div",		tag:"mo", output:"\u00F7", ttype:CONST},
       
  1138 {input:"\\circ",	tag:"mo", output:"\u2218", ttype:CONST},
       
  1139 //{input:"\\bullet",	  tag:"mo", output:"\u2219", ttype:CONST},
       
  1140 {input:"\\bullet",	tag:"mo", output:"\u2022", ttype:CONST},
       
  1141 {input:"\\oplus",	tag:"mo", output:"\u2295", ttype:CONST},
       
  1142 {input:"\\ominus",	tag:"mo", output:"\u2296", ttype:CONST},
       
  1143 {input:"\\otimes",	tag:"mo", output:"\u2297", ttype:CONST},
       
  1144 {input:"\\bigcirc",	tag:"mo", output:"\u25CB", ttype:CONST},
       
  1145 {input:"\\oslash",	tag:"mo", output:"\u2298", ttype:CONST},
       
  1146 {input:"\\odot",	tag:"mo", output:"\u2299", ttype:CONST},
       
  1147 {input:"\\land",	tag:"mo", output:"\u2227", ttype:CONST},
       
  1148 {input:"\\wedge",	tag:"mo", output:"\u2227", ttype:CONST},
       
  1149 {input:"\\lor",		tag:"mo", output:"\u2228", ttype:CONST},
       
  1150 {input:"\\vee",		tag:"mo", output:"\u2228", ttype:CONST},
       
  1151 {input:"\\cap",		tag:"mo", output:"\u2229", ttype:CONST},
       
  1152 {input:"\\cup",		tag:"mo", output:"\u222A", ttype:CONST},
       
  1153 {input:"\\sqcap",	tag:"mo", output:"\u2293", ttype:CONST},
       
  1154 {input:"\\sqcup",	tag:"mo", output:"\u2294", ttype:CONST},
       
  1155 {input:"\\uplus",	tag:"mo", output:"\u228E", ttype:CONST},
       
  1156 {input:"\\amalg",	tag:"mo", output:"\u2210", ttype:CONST},
       
  1157 {input:"\\bigtriangleup",tag:"mo",output:"\u25B3", ttype:CONST},
       
  1158 {input:"\\bigtriangledown",tag:"mo",output:"\u25BD", ttype:CONST},
       
  1159 {input:"\\dag",		tag:"mo", output:"\u2020", ttype:CONST},
       
  1160 {input:"\\dagger",	tag:"mo", output:"\u2020", ttype:CONST},
       
  1161 {input:"\\ddag",	tag:"mo", output:"\u2021", ttype:CONST},
       
  1162 {input:"\\ddagger",	tag:"mo", output:"\u2021", ttype:CONST},
       
  1163 {input:"\\lhd",		tag:"mo", output:"\u22B2", ttype:CONST},
       
  1164 {input:"\\rhd",		tag:"mo", output:"\u22B3", ttype:CONST},
       
  1165 {input:"\\unlhd",	tag:"mo", output:"\u22B4", ttype:CONST},
       
  1166 {input:"\\unrhd",	tag:"mo", output:"\u22B5", ttype:CONST},
       
  1167 
       
  1168 
       
  1169 //BIG Operators
       
  1170 {input:"\\sum",		tag:"mo", output:"\u2211", ttype:UNDEROVER},
       
  1171 {input:"\\prod",	tag:"mo", output:"\u220F", ttype:UNDEROVER},
       
  1172 {input:"\\bigcap",	tag:"mo", output:"\u22C2", ttype:UNDEROVER},
       
  1173 {input:"\\bigcup",	tag:"mo", output:"\u22C3", ttype:UNDEROVER},
       
  1174 {input:"\\bigwedge",	tag:"mo", output:"\u22C0", ttype:UNDEROVER},
       
  1175 {input:"\\bigvee",	tag:"mo", output:"\u22C1", ttype:UNDEROVER},
       
  1176 {input:"\\bigsqcap",	tag:"mo", output:"\u2A05", ttype:UNDEROVER},
       
  1177 {input:"\\bigsqcup",	tag:"mo", output:"\u2A06", ttype:UNDEROVER},
       
  1178 {input:"\\coprod",	tag:"mo", output:"\u2210", ttype:UNDEROVER},
       
  1179 {input:"\\bigoplus",	tag:"mo", output:"\u2A01", ttype:UNDEROVER},
       
  1180 {input:"\\bigotimes",	tag:"mo", output:"\u2A02", ttype:UNDEROVER},
       
  1181 {input:"\\bigodot",	tag:"mo", output:"\u2A00", ttype:UNDEROVER},
       
  1182 {input:"\\biguplus",	tag:"mo", output:"\u2A04", ttype:UNDEROVER},
       
  1183 {input:"\\int",		tag:"mo", output:"\u222B", ttype:CONST},
       
  1184 {input:"\\oint",	tag:"mo", output:"\u222E", ttype:CONST},
       
  1185 
       
  1186 //binary relation symbols
       
  1187 {input:":=",		tag:"mo", output:":=",	   ttype:CONST},
       
  1188 {input:"\\lt",		tag:"mo", output:"<",	   ttype:CONST},
       
  1189 {input:"\\gt",		tag:"mo", output:">",	   ttype:CONST},
       
  1190 {input:"\\ne",		tag:"mo", output:"\u2260", ttype:CONST},
       
  1191 {input:"\\neq",		tag:"mo", output:"\u2260", ttype:CONST},
       
  1192 {input:"\\le",		tag:"mo", output:"\u2264", ttype:CONST},
       
  1193 {input:"\\leq",		tag:"mo", output:"\u2264", ttype:CONST},
       
  1194 {input:"\\leqslant",	tag:"mo", output:"\u2264", ttype:CONST},
       
  1195 {input:"\\ge",		tag:"mo", output:"\u2265", ttype:CONST},
       
  1196 {input:"\\geq",		tag:"mo", output:"\u2265", ttype:CONST},
       
  1197 {input:"\\geqslant",	tag:"mo", output:"\u2265", ttype:CONST},
       
  1198 {input:"\\equiv",	tag:"mo", output:"\u2261", ttype:CONST},
       
  1199 {input:"\\ll",		tag:"mo", output:"\u226A", ttype:CONST},
       
  1200 {input:"\\gg",		tag:"mo", output:"\u226B", ttype:CONST},
       
  1201 {input:"\\doteq",	tag:"mo", output:"\u2250", ttype:CONST},
       
  1202 {input:"\\prec",	tag:"mo", output:"\u227A", ttype:CONST},
       
  1203 {input:"\\succ",	tag:"mo", output:"\u227B", ttype:CONST},
       
  1204 {input:"\\preceq",	tag:"mo", output:"\u227C", ttype:CONST},
       
  1205 {input:"\\succeq",	tag:"mo", output:"\u227D", ttype:CONST},
       
  1206 {input:"\\subset",	tag:"mo", output:"\u2282", ttype:CONST},
       
  1207 {input:"\\supset",	tag:"mo", output:"\u2283", ttype:CONST},
       
  1208 {input:"\\subseteq",	tag:"mo", output:"\u2286", ttype:CONST},
       
  1209 {input:"\\supseteq",	tag:"mo", output:"\u2287", ttype:CONST},
       
  1210 {input:"\\sqsubset",	tag:"mo", output:"\u228F", ttype:CONST},
       
  1211 {input:"\\sqsupset",	tag:"mo", output:"\u2290", ttype:CONST},
       
  1212 {input:"\\sqsubseteq",  tag:"mo", output:"\u2291", ttype:CONST},
       
  1213 {input:"\\sqsupseteq",  tag:"mo", output:"\u2292", ttype:CONST},
       
  1214 {input:"\\sim",		tag:"mo", output:"\u223C", ttype:CONST},
       
  1215 {input:"\\simeq",	tag:"mo", output:"\u2243", ttype:CONST},
       
  1216 {input:"\\approx",	tag:"mo", output:"\u2248", ttype:CONST},
       
  1217 {input:"\\cong",	tag:"mo", output:"\u2245", ttype:CONST},
       
  1218 {input:"\\Join",	tag:"mo", output:"\u22C8", ttype:CONST},
       
  1219 {input:"\\bowtie",	tag:"mo", output:"\u22C8", ttype:CONST},
       
  1220 {input:"\\in",		tag:"mo", output:"\u2208", ttype:CONST},
       
  1221 {input:"\\ni",		tag:"mo", output:"\u220B", ttype:CONST},
       
  1222 {input:"\\owns",	tag:"mo", output:"\u220B", ttype:CONST},
       
  1223 {input:"\\propto",	tag:"mo", output:"\u221D", ttype:CONST},
       
  1224 {input:"\\vdash",	tag:"mo", output:"\u22A2", ttype:CONST},
       
  1225 {input:"\\dashv",	tag:"mo", output:"\u22A3", ttype:CONST},
       
  1226 {input:"\\models",	tag:"mo", output:"\u22A8", ttype:CONST},
       
  1227 {input:"\\perp",	tag:"mo", output:"\u22A5", ttype:CONST},
       
  1228 {input:"\\smile",	tag:"mo", output:"\u2323", ttype:CONST},
       
  1229 {input:"\\frown",	tag:"mo", output:"\u2322", ttype:CONST},
       
  1230 {input:"\\asymp",	tag:"mo", output:"\u224D", ttype:CONST},
       
  1231 {input:"\\notin",	tag:"mo", output:"\u2209", ttype:CONST},
       
  1232 
       
  1233 //matrices
       
  1234 {input:"\\begin{eqnarray}",	output:"X",	ttype:MATRIX, invisible:true},
       
  1235 {input:"\\begin{array}",	output:"X",	ttype:MATRIX, invisible:true},
       
  1236 {input:"\\\\",			output:"}&{",	ttype:DEFINITION},
       
  1237 {input:"\\end{eqnarray}",	output:"}}",	ttype:DEFINITION},
       
  1238 {input:"\\end{array}",		output:"}}",	ttype:DEFINITION},
       
  1239 
       
  1240 //grouping and literal brackets -- ieval is for IE
       
  1241 {input:"\\big",	   tag:"mo", output:"X", atval:"1.2", ieval:"2.2", ttype:BIG},
       
  1242 {input:"\\Big",	   tag:"mo", output:"X", atval:"1.6", ieval:"2.6", ttype:BIG},
       
  1243 {input:"\\bigg",   tag:"mo", output:"X", atval:"2.2", ieval:"3.2", ttype:BIG},
       
  1244 {input:"\\Bigg",   tag:"mo", output:"X", atval:"2.9", ieval:"3.9", ttype:BIG},
       
  1245 {input:"\\left",   tag:"mo", output:"X", ttype:LEFTBRACKET},
       
  1246 {input:"\\right",  tag:"mo", output:"X", ttype:RIGHTBRACKET},
       
  1247 {input:"{",	   output:"{", ttype:LEFTBRACKET,  invisible:true},
       
  1248 {input:"}",	   output:"}", ttype:RIGHTBRACKET, invisible:true},
       
  1249 
       
  1250 {input:"(",	   tag:"mo", output:"(",      atval:"1", ttype:STRETCHY},
       
  1251 {input:"[",	   tag:"mo", output:"[",      atval:"1", ttype:STRETCHY},
       
  1252 {input:"\\lbrack", tag:"mo", output:"[",      atval:"1", ttype:STRETCHY},
       
  1253 {input:"\\{",	   tag:"mo", output:"{",      atval:"1", ttype:STRETCHY},
       
  1254 {input:"\\lbrace", tag:"mo", output:"{",      atval:"1", ttype:STRETCHY},
       
  1255 {input:"\\langle", tag:"mo", output:"\u2329", atval:"1", ttype:STRETCHY},
       
  1256 {input:"\\lfloor", tag:"mo", output:"\u230A", atval:"1", ttype:STRETCHY},
       
  1257 {input:"\\lceil",  tag:"mo", output:"\u2308", atval:"1", ttype:STRETCHY},
       
  1258 
       
  1259 // rtag:"mi" causes space to be inserted before a following sin, cos, etc.
       
  1260 // (see function LMparseExpr() )
       
  1261 {input:")",	  tag:"mo",output:")",	    rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1262 {input:"]",	  tag:"mo",output:"]",	    rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1263 {input:"\\rbrack",tag:"mo",output:"]",	    rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1264 {input:"\\}",	  tag:"mo",output:"}",	    rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1265 {input:"\\rbrace",tag:"mo",output:"}",	    rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1266 {input:"\\rangle",tag:"mo",output:"\u232A", rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1267 {input:"\\rfloor",tag:"mo",output:"\u230B", rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1268 {input:"\\rceil", tag:"mo",output:"\u2309", rtag:"mi",atval:"1",ttype:STRETCHY},
       
  1269 
       
  1270 // "|", "\\|", "\\vert" and "\\Vert" modified later: lspace = rspace = 0em
       
  1271 {input:"|",		tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
       
  1272 {input:"\\|",		tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
       
  1273 {input:"\\vert",	tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
       
  1274 {input:"\\Vert",	tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
       
  1275 {input:"\\mid",		tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
       
  1276 {input:"\\parallel",	tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
       
  1277 {input:"/",		tag:"mo", output:"/",	atval:"1.01", ttype:STRETCHY},
       
  1278 {input:"\\backslash",	tag:"mo", output:"\u2216", atval:"1", ttype:STRETCHY},
       
  1279 {input:"\\setminus",	tag:"mo", output:"\\",	   ttype:CONST},
       
  1280 
       
  1281 //miscellaneous symbols
       
  1282 {input:"\\!",	  tag:"mspace", atname:"width", atval:"-0.167em", ttype:SPACE},
       
  1283 {input:"\\,",	  tag:"mspace", atname:"width", atval:"0.167em", ttype:SPACE},
       
  1284 {input:"\\>",	  tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE},
       
  1285 {input:"\\:",	  tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE},
       
  1286 {input:"\\;",	  tag:"mspace", atname:"width", atval:"0.278em", ttype:SPACE},
       
  1287 {input:"~",	  tag:"mspace", atname:"width", atval:"0.333em", ttype:SPACE},
       
  1288 {input:"\\quad",  tag:"mspace", atname:"width", atval:"1em", ttype:SPACE},
       
  1289 {input:"\\qquad", tag:"mspace", atname:"width", atval:"2em", ttype:SPACE},
       
  1290 //{input:"{}",		  tag:"mo", output:"\u200B", ttype:CONST}, // zero-width
       
  1291 {input:"\\prime",	tag:"mo", output:"\u2032", ttype:CONST},
       
  1292 {input:"'",		tag:"mo", output:"\u02B9", ttype:CONST},
       
  1293 {input:"''",		tag:"mo", output:"\u02BA", ttype:CONST},
       
  1294 {input:"'''",		tag:"mo", output:"\u2034", ttype:CONST},
       
  1295 {input:"''''",		tag:"mo", output:"\u2057", ttype:CONST},
       
  1296 {input:"\\ldots",	tag:"mo", output:"\u2026", ttype:CONST},
       
  1297 {input:"\\cdots",	tag:"mo", output:"\u22EF", ttype:CONST},
       
  1298 {input:"\\vdots",	tag:"mo", output:"\u22EE", ttype:CONST},
       
  1299 {input:"\\ddots",	tag:"mo", output:"\u22F1", ttype:CONST},
       
  1300 {input:"\\forall",	tag:"mo", output:"\u2200", ttype:CONST},
       
  1301 {input:"\\exists",	tag:"mo", output:"\u2203", ttype:CONST},
       
  1302 {input:"\\Re",		tag:"mo", output:"\u211C", ttype:CONST},
       
  1303 {input:"\\Im",		tag:"mo", output:"\u2111", ttype:CONST},
       
  1304 {input:"\\aleph",	tag:"mo", output:"\u2135", ttype:CONST},
       
  1305 {input:"\\hbar",	tag:"mo", output:"\u210F", ttype:CONST},
       
  1306 {input:"\\ell",		tag:"mo", output:"\u2113", ttype:CONST},
       
  1307 {input:"\\wp",		tag:"mo", output:"\u2118", ttype:CONST},
       
  1308 {input:"\\emptyset",	tag:"mo", output:"\u2205", ttype:CONST},
       
  1309 {input:"\\infty",	tag:"mo", output:"\u221E", ttype:CONST},
       
  1310 {input:"\\surd",	tag:"mo", output:"\\sqrt{}", ttype:DEFINITION},
       
  1311 {input:"\\partial",	tag:"mo", output:"\u2202", ttype:CONST},
       
  1312 {input:"\\nabla",	tag:"mo", output:"\u2207", ttype:CONST},
       
  1313 {input:"\\triangle",	tag:"mo", output:"\u25B3", ttype:CONST},
       
  1314 {input:"\\therefore",	tag:"mo", output:"\u2234", ttype:CONST},
       
  1315 {input:"\\angle",	tag:"mo", output:"\u2220", ttype:CONST},
       
  1316 //{input:"\\\\ ",	  tag:"mo", output:"\u00A0", ttype:CONST},
       
  1317 {input:"\\diamond",	tag:"mo", output:"\u22C4", ttype:CONST},
       
  1318 //{input:"\\Diamond",	  tag:"mo", output:"\u25CA", ttype:CONST},
       
  1319 {input:"\\Diamond",	tag:"mo", output:"\u25C7", ttype:CONST},
       
  1320 {input:"\\neg",		tag:"mo", output:"\u00AC", ttype:CONST},
       
  1321 {input:"\\lnot",	tag:"mo", output:"\u00AC", ttype:CONST},
       
  1322 {input:"\\bot",		tag:"mo", output:"\u22A5", ttype:CONST},
       
  1323 {input:"\\top",		tag:"mo", output:"\u22A4", ttype:CONST},
       
  1324 {input:"\\square",	tag:"mo", output:"\u25AB", ttype:CONST},
       
  1325 {input:"\\Box",		tag:"mo", output:"\u25A1", ttype:CONST},
       
  1326 {input:"\\wr",		tag:"mo", output:"\u2240", ttype:CONST},
       
  1327 
       
  1328 //standard functions
       
  1329 //Note UNDEROVER *must* have tag:"mo" to work properly
       
  1330 {input:"\\arccos", tag:"mi", output:"arccos", ttype:UNARY, func:true},
       
  1331 {input:"\\arcsin", tag:"mi", output:"arcsin", ttype:UNARY, func:true},
       
  1332 {input:"\\arctan", tag:"mi", output:"arctan", ttype:UNARY, func:true},
       
  1333 {input:"\\arg",	   tag:"mi", output:"arg",    ttype:UNARY, func:true},
       
  1334 {input:"\\cos",	   tag:"mi", output:"cos",    ttype:UNARY, func:true},
       
  1335 {input:"\\cosh",   tag:"mi", output:"cosh",   ttype:UNARY, func:true},
       
  1336 {input:"\\cot",	   tag:"mi", output:"cot",    ttype:UNARY, func:true},
       
  1337 {input:"\\coth",   tag:"mi", output:"coth",   ttype:UNARY, func:true},
       
  1338 {input:"\\csc",	   tag:"mi", output:"csc",    ttype:UNARY, func:true},
       
  1339 {input:"\\deg",	   tag:"mi", output:"deg",    ttype:UNARY, func:true},
       
  1340 {input:"\\det",	   tag:"mi", output:"det",    ttype:UNARY, func:true},
       
  1341 {input:"\\dim",	   tag:"mi", output:"dim",    ttype:UNARY, func:true}, //CONST?
       
  1342 {input:"\\exp",	   tag:"mi", output:"exp",    ttype:UNARY, func:true},
       
  1343 {input:"\\gcd",	   tag:"mi", output:"gcd",    ttype:UNARY, func:true}, //CONST?
       
  1344 {input:"\\hom",	   tag:"mi", output:"hom",    ttype:UNARY, func:true},
       
  1345 {input:"\\inf",	      tag:"mo", output:"inf",	 ttype:UNDEROVER},
       
  1346 {input:"\\ker",	   tag:"mi", output:"ker",    ttype:UNARY, func:true},
       
  1347 {input:"\\lg",	   tag:"mi", output:"lg",     ttype:UNARY, func:true},
       
  1348 {input:"\\lim",	      tag:"mo", output:"lim",	 ttype:UNDEROVER},
       
  1349 {input:"\\liminf",    tag:"mo", output:"liminf", ttype:UNDEROVER},
       
  1350 {input:"\\limsup",    tag:"mo", output:"limsup", ttype:UNDEROVER},
       
  1351 {input:"\\ln",	   tag:"mi", output:"ln",     ttype:UNARY, func:true},
       
  1352 {input:"\\log",	   tag:"mi", output:"log",    ttype:UNARY, func:true},
       
  1353 {input:"\\max",	      tag:"mo", output:"max",	 ttype:UNDEROVER},
       
  1354 {input:"\\min",	      tag:"mo", output:"min",	 ttype:UNDEROVER},
       
  1355 {input:"\\Pr",	   tag:"mi", output:"Pr",     ttype:UNARY, func:true},
       
  1356 {input:"\\sec",	   tag:"mi", output:"sec",    ttype:UNARY, func:true},
       
  1357 {input:"\\sin",	   tag:"mi", output:"sin",    ttype:UNARY, func:true},
       
  1358 {input:"\\sinh",   tag:"mi", output:"sinh",   ttype:UNARY, func:true},
       
  1359 {input:"\\sup",	      tag:"mo", output:"sup",	 ttype:UNDEROVER},
       
  1360 {input:"\\tan",	   tag:"mi", output:"tan",    ttype:UNARY, func:true},
       
  1361 {input:"\\tanh",   tag:"mi", output:"tanh",   ttype:UNARY, func:true},
       
  1362 
       
  1363 //arrows
       
  1364 {input:"\\gets",		tag:"mo", output:"\u2190", ttype:CONST},
       
  1365 {input:"\\leftarrow",		tag:"mo", output:"\u2190", ttype:CONST},
       
  1366 {input:"\\to",			tag:"mo", output:"\u2192", ttype:CONST},
       
  1367 {input:"\\rightarrow",		tag:"mo", output:"\u2192", ttype:CONST},
       
  1368 {input:"\\leftrightarrow",	tag:"mo", output:"\u2194", ttype:CONST},
       
  1369 {input:"\\uparrow",		tag:"mo", output:"\u2191", ttype:CONST},
       
  1370 {input:"\\downarrow",		tag:"mo", output:"\u2193", ttype:CONST},
       
  1371 {input:"\\updownarrow",		tag:"mo", output:"\u2195", ttype:CONST},
       
  1372 {input:"\\Leftarrow",		tag:"mo", output:"\u21D0", ttype:CONST},
       
  1373 {input:"\\Rightarrow",		tag:"mo", output:"\u21D2", ttype:CONST},
       
  1374 {input:"\\Leftrightarrow",	tag:"mo", output:"\u21D4", ttype:CONST},
       
  1375 {input:"\\iff", tag:"mo", output:"~\\Longleftrightarrow~", ttype:DEFINITION},
       
  1376 {input:"\\Uparrow",		tag:"mo", output:"\u21D1", ttype:CONST},
       
  1377 {input:"\\Downarrow",		tag:"mo", output:"\u21D3", ttype:CONST},
       
  1378 {input:"\\Updownarrow",		tag:"mo", output:"\u21D5", ttype:CONST},
       
  1379 {input:"\\mapsto",		tag:"mo", output:"\u21A6", ttype:CONST},
       
  1380 {input:"\\longleftarrow",	tag:"mo", output:"\u2190", ttype:LONG},
       
  1381 {input:"\\longrightarrow",	tag:"mo", output:"\u2192", ttype:LONG},
       
  1382 {input:"\\longleftrightarrow",	tag:"mo", output:"\u2194", ttype:LONG},
       
  1383 {input:"\\Longleftarrow",	tag:"mo", output:"\u21D0", ttype:LONG},
       
  1384 {input:"\\Longrightarrow",	tag:"mo", output:"\u21D2", ttype:LONG},
       
  1385 {input:"\\Longleftrightarrow",  tag:"mo", output:"\u21D4", ttype:LONG},
       
  1386 {input:"\\longmapsto",		tag:"mo", output:"\u21A6", ttype:CONST},
       
  1387 							// disaster if LONG
       
  1388 
       
  1389 //commands with argument
       
  1390 LMsqrt, LMroot, LMfrac, LMover, LMsub, LMsup, LMtext, LMmbox, LMatop, LMchoose,
       
  1391 //LMdiv, LMquote,
       
  1392 
       
  1393 //diacritical marks
       
  1394 {input:"\\acute",	tag:"mover",  output:"\u00B4", ttype:UNARY, acc:true},
       
  1395 //{input:"\\acute",	  tag:"mover",  output:"\u0317", ttype:UNARY, acc:true},
       
  1396 //{input:"\\acute",	  tag:"mover",  output:"\u0301", ttype:UNARY, acc:true},
       
  1397 //{input:"\\grave",	  tag:"mover",  output:"\u0300", ttype:UNARY, acc:true},
       
  1398 //{input:"\\grave",	  tag:"mover",  output:"\u0316", ttype:UNARY, acc:true},
       
  1399 {input:"\\grave",	tag:"mover",  output:"\u0060", ttype:UNARY, acc:true},
       
  1400 {input:"\\breve",	tag:"mover",  output:"\u02D8", ttype:UNARY, acc:true},
       
  1401 {input:"\\check",	tag:"mover",  output:"\u02C7", ttype:UNARY, acc:true},
       
  1402 {input:"\\dot",		tag:"mover",  output:".",      ttype:UNARY, acc:true},
       
  1403 {input:"\\ddot",	tag:"mover",  output:"..",     ttype:UNARY, acc:true},
       
  1404 //{input:"\\ddot",	  tag:"mover",  output:"\u00A8", ttype:UNARY, acc:true},
       
  1405 {input:"\\mathring",	tag:"mover",  output:"\u00B0", ttype:UNARY, acc:true},
       
  1406 {input:"\\vec",		tag:"mover",  output:"\u20D7", ttype:UNARY, acc:true},
       
  1407 {input:"\\overrightarrow",tag:"mover",output:"\u20D7", ttype:UNARY, acc:true},
       
  1408 {input:"\\overleftarrow",tag:"mover", output:"\u20D6", ttype:UNARY, acc:true},
       
  1409 {input:"\\hat",		tag:"mover",  output:"\u005E", ttype:UNARY, acc:true},
       
  1410 {input:"\\widehat",	tag:"mover",  output:"\u0302", ttype:UNARY, acc:true},
       
  1411 {input:"\\tilde",	tag:"mover",  output:"~",      ttype:UNARY, acc:true},
       
  1412 //{input:"\\tilde",	  tag:"mover",  output:"\u0303", ttype:UNARY, acc:true},
       
  1413 {input:"\\widetilde",	tag:"mover",  output:"\u02DC", ttype:UNARY, acc:true},
       
  1414 {input:"\\bar",		tag:"mover",  output:"\u203E", ttype:UNARY, acc:true},
       
  1415 {input:"\\overbrace",	tag:"mover",  output:"\u23B4", ttype:UNARY, acc:true},
       
  1416 {input:"\\overline",	tag:"mover",  output:"\u00AF", ttype:UNARY, acc:true},
       
  1417 {input:"\\underbrace",  tag:"munder", output:"\u23B5", ttype:UNARY, acc:true},
       
  1418 {input:"\\underline",	tag:"munder", output:"\u00AF", ttype:UNARY, acc:true},
       
  1419 //{input:"underline",	tag:"munder", output:"\u0332", ttype:UNARY, acc:true},
       
  1420 
       
  1421 //typestyles and fonts
       
  1422 {input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true", ttype:UNARY},
       
  1423 {input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false", ttype:UNARY},
       
  1424 {input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1", ttype:UNARY},
       
  1425 {input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2", ttype:UNARY},
       
  1426 {input:"\\textrm", tag:"mstyle", output:"\\mathrm", ttype: DEFINITION},
       
  1427 {input:"\\mathbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY},
       
  1428 {input:"\\textbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY},
       
  1429 {input:"\\mathit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY},
       
  1430 {input:"\\textit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY},
       
  1431 {input:"\\mathtt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY},
       
  1432 {input:"\\texttt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY},
       
  1433 {input:"\\mathsf", tag:"mstyle", atname:"mathvariant", atval:"sans-serif", ttype:UNARY},
       
  1434 {input:"\\mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", ttype:UNARY, codes:LMbbb},
       
  1435 {input:"\\mathcal",tag:"mstyle", atname:"mathvariant", atval:"script", ttype:UNARY, codes:LMcal},
       
  1436 {input:"\\mathfrak",tag:"mstyle",atname:"mathvariant", atval:"fraktur",ttype:UNARY, codes:LMfrk}
       
  1437 ];
       
  1438 
       
  1439 function compareNames(s1,s2) {
       
  1440   if (s1.input > s2.input) return 1
       
  1441   else return -1;
       
  1442 }
       
  1443 
       
  1444 var LMnames = []; //list of input symbols
       
  1445 
       
  1446 function LMinitSymbols() {
       
  1447   LMsymbols.sort(compareNames);
       
  1448   for (i=0; i<LMsymbols.length; i++) LMnames[i] = LMsymbols[i].input;
       
  1449 }
       
  1450 
       
  1451 var LMmathml = "http://www.w3.org/1998/Math/MathML";
       
  1452 
       
  1453 function LMcreateElementMathML(t) {
       
  1454   if (isIE) return document.createElement("m:"+t);
       
  1455   else return document.createElementNS(LMmathml,t);
       
  1456 }
       
  1457 
       
  1458 function LMcreateMmlNode(t,frag) {
       
  1459 //  var node = LMcreateElementMathML(name);
       
  1460   if (isIE) var node = document.createElement("m:"+t);
       
  1461   else var node = document.createElementNS(LMmathml,t);
       
  1462   node.appendChild(frag);
       
  1463   return node;
       
  1464 }
       
  1465 
       
  1466 function newcommand(oldstr,newstr) {
       
  1467   LMsymbols = LMsymbols.concat([{input:oldstr, tag:"mo", output:newstr,
       
  1468                                  ttype:DEFINITION}]);
       
  1469 }
       
  1470 
       
  1471 function LMremoveCharsAndBlanks(str,n) {
       
  1472 //remove n characters and any following blanks
       
  1473   var st;
       
  1474   st = str.slice(n);
       
  1475   for (var i=0; i<st.length && st.charCodeAt(i)<=32; i=i+1);
       
  1476   return st.slice(i);
       
  1477 }
       
  1478 
       
  1479 function LMposition(arr, str, n) {
       
  1480 // return position >=n where str appears or would be inserted
       
  1481 // assumes arr is sorted
       
  1482   if (n==0) {
       
  1483     var h,m;
       
  1484     n = -1;
       
  1485     h = arr.length;
       
  1486     while (n+1<h) {
       
  1487       m = (n+h) >> 1;
       
  1488       if (arr[m]<str) n = m; else h = m;
       
  1489     }
       
  1490     return h;
       
  1491   } else
       
  1492     for (var i=n; i<arr.length && arr[i]<str; i++);
       
  1493   return i; // i=arr.length || arr[i]>=str
       
  1494 }
       
  1495 
       
  1496 function LMgetSymbol(str) {
       
  1497 //return maximal initial substring of str that appears in names
       
  1498 //return null if there is none
       
  1499   var k = 0; //new pos
       
  1500   var j = 0; //old pos
       
  1501   var mk; //match pos
       
  1502   var st;
       
  1503   var tagst;
       
  1504   var match = "";
       
  1505   var more = true;
       
  1506   for (var i=1; i<=str.length && more; i++) {
       
  1507     st = str.slice(0,i); //initial substring of length i
       
  1508     j = k;
       
  1509     k = LMposition(LMnames, st, j);
       
  1510     if (k<LMnames.length && str.slice(0,LMnames[k].length)==LMnames[k]){
       
  1511       match = LMnames[k];
       
  1512       mk = k;
       
  1513       i = match.length;
       
  1514     }
       
  1515     more = k<LMnames.length && str.slice(0,LMnames[k].length)>=LMnames[k];
       
  1516   }
       
  1517   LMpreviousSymbol=LMcurrentSymbol;
       
  1518   if (match!=""){
       
  1519     LMcurrentSymbol=LMsymbols[mk].ttype;
       
  1520     return LMsymbols[mk];
       
  1521   }
       
  1522   LMcurrentSymbol=CONST;
       
  1523   k = 1;
       
  1524   st = str.slice(0,1); //take 1 character
       
  1525   if ("0"<=st && st<="9") tagst = "mn";
       
  1526   else tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi");
       
  1527 /*
       
  1528 // Commented out by DRW (not fully understood, but probably to do with
       
  1529 // use of "/" as an INFIX version of "\\frac", which we don't want):
       
  1530 //}
       
  1531 //if (st=="-" && LMpreviousSymbol==INFIX) {
       
  1532 //  LMcurrentSymbol = INFIX;  //trick "/" into recognizing "-" on second parse
       
  1533 //  return {input:st, tag:tagst, output:st, ttype:UNARY, func:true};
       
  1534 //}
       
  1535 */
       
  1536   return {input:st, tag:tagst, output:st, ttype:CONST};
       
  1537 }
       
  1538 
       
  1539 
       
  1540 /*Parsing ASCII math expressions with the following grammar
       
  1541 v ::= [A-Za-z] | greek letters | numbers | other constant symbols
       
  1542 u ::= sqrt | text | bb | other unary symbols for font commands
       
  1543 b ::= frac | root | stackrel	binary symbols
       
  1544 l ::= { | \left			left brackets
       
  1545 r ::= } | \right		right brackets
       
  1546 S ::= v | lEr | uS | bSS	Simple expression
       
  1547 I ::= S_S | S^S | S_S^S | S	Intermediate expression
       
  1548 E ::= IE | I/I			Expression
       
  1549 Each terminal symbol is translated into a corresponding mathml node.*/
       
  1550 
       
  1551 var LMpreviousSymbol,LMcurrentSymbol;
       
  1552 
       
  1553 function LMparseSexpr(str) { //parses str and returns [node,tailstr,(node)tag]
       
  1554   var symbol, node, result, result2, i, st,// rightvert = false,
       
  1555     newFrag = document.createDocumentFragment();
       
  1556   str = LMremoveCharsAndBlanks(str,0);
       
  1557   symbol = LMgetSymbol(str);             //either a token or a bracket or empty
       
  1558   if (symbol == null || symbol.ttype == RIGHTBRACKET)
       
  1559     return [null,str,null];
       
  1560   if (symbol.ttype == DEFINITION) {
       
  1561     str = symbol.output+LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1562     symbol = LMgetSymbol(str);
       
  1563     if (symbol == null || symbol.ttype == RIGHTBRACKET)
       
  1564       return [null,str,null];
       
  1565   }
       
  1566   str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1567   switch (symbol.ttype) {
       
  1568   case SPACE:
       
  1569     node = LMcreateElementMathML(symbol.tag);
       
  1570     node.setAttribute(symbol.atname,symbol.atval);
       
  1571     return [node,str,symbol.tag];
       
  1572   case UNDEROVER:
       
  1573     if (isIE) {
       
  1574       if (symbol.input.substr(0,4) == "\\big") {   // botch for missing symbols
       
  1575 	str = "\\"+symbol.input.substr(4)+str;	   // make \bigcup = \cup etc.
       
  1576 	symbol = LMgetSymbol(str);
       
  1577 	symbol.ttype = UNDEROVER;
       
  1578 	str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1579       }
       
  1580     }
       
  1581     return [LMcreateMmlNode(symbol.tag,
       
  1582 			document.createTextNode(symbol.output)),str,symbol.tag];
       
  1583   case CONST:
       
  1584     var output = symbol.output;
       
  1585     if (isIE) {
       
  1586       if (symbol.input == "'")
       
  1587 	output = "\u2032";
       
  1588       else if (symbol.input == "''")
       
  1589 	output = "\u2033";
       
  1590       else if (symbol.input == "'''")
       
  1591 	output = "\u2033\u2032";
       
  1592       else if (symbol.input == "''''")
       
  1593 	output = "\u2033\u2033";
       
  1594       else if (symbol.input == "\\square")
       
  1595 	output = "\u25A1";	// same as \Box
       
  1596       else if (symbol.input.substr(0,5) == "\\frac") {
       
  1597 						// botch for missing fractions
       
  1598 	var denom = symbol.input.substr(6,1);
       
  1599 	if (denom == "5" || denom == "6") {
       
  1600 	  str = symbol.input.replace(/\\frac/,"\\frac ")+str;
       
  1601 	  return [node,str,symbol.tag];
       
  1602 	}
       
  1603       }
       
  1604     }
       
  1605     node = LMcreateMmlNode(symbol.tag,document.createTextNode(output));
       
  1606     return [node,str,symbol.tag];
       
  1607   case LONG:  // added by DRW
       
  1608     node = LMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
       
  1609     node.setAttribute("minsize","1.5");
       
  1610     node.setAttribute("maxsize","1.5");
       
  1611     node = LMcreateMmlNode("mover",node);
       
  1612     node.appendChild(LMcreateElementMathML("mspace"));
       
  1613     return [node,str,symbol.tag];
       
  1614   case STRETCHY:  // added by DRW
       
  1615     if (isIE && symbol.input == "\\backslash")
       
  1616 	symbol.output = "\\";	// doesn't expand, but then nor does "\u2216"
       
  1617     node = LMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
       
  1618     if (symbol.input == "|" || symbol.input == "\\vert" ||
       
  1619 	symbol.input == "\\|" || symbol.input == "\\Vert") {
       
  1620 	  node.setAttribute("lspace","0em");
       
  1621 	  node.setAttribute("rspace","0em");
       
  1622     }
       
  1623     node.setAttribute("maxsize",symbol.atval);  // don't allow to stretch here
       
  1624     if (symbol.rtag != null)
       
  1625       return [node,str,symbol.rtag];
       
  1626     else
       
  1627       return [node,str,symbol.tag];
       
  1628   case BIG:  // added by DRW
       
  1629     var atval = symbol.atval;
       
  1630     if (isIE)
       
  1631       atval = symbol.ieval;
       
  1632     symbol = LMgetSymbol(str);
       
  1633     if (symbol == null)
       
  1634 	return [null,str,null];
       
  1635     str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1636     node = LMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
       
  1637     if (isIE) {		// to get brackets to expand
       
  1638       var space = LMcreateElementMathML("mspace");
       
  1639       space.setAttribute("height",atval+"ex");
       
  1640       node = LMcreateMmlNode("mrow",node);
       
  1641       node.appendChild(space);
       
  1642     } else {		// ignored in IE
       
  1643       node.setAttribute("minsize",atval);
       
  1644       node.setAttribute("maxsize",atval);
       
  1645     }
       
  1646     return [node,str,symbol.tag];
       
  1647   case LEFTBRACKET:   //read (expr+)
       
  1648     if (symbol.input == "\\left") { // left what?
       
  1649       symbol = LMgetSymbol(str);
       
  1650       if (symbol != null) {
       
  1651 	if (symbol.input == ".")
       
  1652 	  symbol.invisible = true;
       
  1653 	str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1654       }
       
  1655     }
       
  1656     result = LMparseExpr(str,true,false);
       
  1657     if (symbol==null ||
       
  1658 	(typeof symbol.invisible == "boolean" && symbol.invisible))
       
  1659       node = LMcreateMmlNode("mrow",result[0]);
       
  1660     else {
       
  1661       node = LMcreateMmlNode("mo",document.createTextNode(symbol.output));
       
  1662       node = LMcreateMmlNode("mrow",node);
       
  1663       node.appendChild(result[0]);
       
  1664     }
       
  1665     return [node,result[1],result[2]];
       
  1666   case MATRIX:	 //read (expr+)
       
  1667     if (symbol.input == "\\begin{array}") {
       
  1668       var mask = "";
       
  1669       symbol = LMgetSymbol(str);
       
  1670       str = LMremoveCharsAndBlanks(str,0);
       
  1671       if (symbol == null)
       
  1672 	mask = "l";
       
  1673       else {
       
  1674 	str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1675 	if (symbol.input != "{")
       
  1676 	  mask = "l";
       
  1677 	else do {
       
  1678 	  symbol = LMgetSymbol(str);
       
  1679 	  if (symbol != null) {
       
  1680 	    str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1681 	    if (symbol.input != "}")
       
  1682 	      mask = mask+symbol.input;
       
  1683 	  }
       
  1684 	} while (symbol != null && symbol.input != "" && symbol.input != "}");
       
  1685       }
       
  1686       result = LMparseExpr("{"+str,true,true);
       
  1687 //    if (result[0]==null) return [LMcreateMmlNode("mo",
       
  1688 //			   document.createTextNode(symbol.input)),str];
       
  1689       node = LMcreateMmlNode("mtable",result[0]);
       
  1690       mask = mask.replace(/l/g,"left ");
       
  1691       mask = mask.replace(/r/g,"right ");
       
  1692       mask = mask.replace(/c/g,"center ");
       
  1693       node.setAttribute("columnalign",mask);
       
  1694       node.setAttribute("displaystyle","false");
       
  1695       if (isIE)
       
  1696 	return [node,result[1],null];
       
  1697 // trying to get a *little* bit of space around the array
       
  1698 // (IE already includes it)
       
  1699       var lspace = LMcreateElementMathML("mspace");
       
  1700       lspace.setAttribute("width","0.167em");
       
  1701       var rspace = LMcreateElementMathML("mspace");
       
  1702       rspace.setAttribute("width","0.167em");
       
  1703       var node1 = LMcreateMmlNode("mrow",lspace);
       
  1704       node1.appendChild(node);
       
  1705       node1.appendChild(rspace);
       
  1706       return [node1,result[1],null];
       
  1707     } else {	// eqnarray
       
  1708       result = LMparseExpr("{"+str,true,true);
       
  1709       node = LMcreateMmlNode("mtable",result[0]);
       
  1710       if (isIE)
       
  1711 	node.setAttribute("columnspacing","0.25em"); // best in practice?
       
  1712       else
       
  1713 	node.setAttribute("columnspacing","0.167em"); // correct (but ignored?)
       
  1714       node.setAttribute("columnalign","right center left");
       
  1715       node.setAttribute("displaystyle","true");
       
  1716       node = LMcreateMmlNode("mrow",node);
       
  1717       return [node,result[1],null];
       
  1718     }
       
  1719   case TEXT:
       
  1720       if (str.charAt(0)=="{") i=str.indexOf("}");
       
  1721       else i = 0;
       
  1722       if (i==-1)
       
  1723 		 i = str.length;
       
  1724       st = str.slice(1,i);
       
  1725       if (st.charAt(0) == " ") {
       
  1726 	node = LMcreateElementMathML("mspace");
       
  1727 	node.setAttribute("width","0.33em");	// was 1ex
       
  1728 	newFrag.appendChild(node);
       
  1729       }
       
  1730       newFrag.appendChild(
       
  1731         LMcreateMmlNode(symbol.tag,document.createTextNode(st)));
       
  1732       if (st.charAt(st.length-1) == " ") {
       
  1733 	node = LMcreateElementMathML("mspace");
       
  1734 	node.setAttribute("width","0.33em");	// was 1ex
       
  1735 	newFrag.appendChild(node);
       
  1736       }
       
  1737       str = LMremoveCharsAndBlanks(str,i+1);
       
  1738       return [LMcreateMmlNode("mrow",newFrag),str,null];
       
  1739   case UNARY:
       
  1740       result = LMparseSexpr(str);
       
  1741       if (result[0]==null) return [LMcreateMmlNode(symbol.tag,
       
  1742                              document.createTextNode(symbol.output)),str];
       
  1743       if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
       
  1744 	st = str.charAt(0);
       
  1745 //	if (st=="^" || st=="_" || st=="/" || st=="|" || st==",") {
       
  1746 	if (st=="^" || st=="_" || st==",") {
       
  1747 	  return [LMcreateMmlNode(symbol.tag,
       
  1748 		    document.createTextNode(symbol.output)),str,symbol.tag];
       
  1749         } else {
       
  1750 	  node = LMcreateMmlNode("mrow",
       
  1751 	   LMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
       
  1752 	  if (isIE) {
       
  1753 	    var space = LMcreateElementMathML("mspace");
       
  1754 	    space.setAttribute("width","0.167em");
       
  1755 	    node.appendChild(space);
       
  1756 	  }
       
  1757 	  node.appendChild(result[0]);
       
  1758 	  return [node,result[1],symbol.tag];
       
  1759         }
       
  1760       }
       
  1761       if (symbol.input == "\\sqrt") {		// sqrt
       
  1762 	if (isIE) {	// set minsize, for \surd
       
  1763 	  var space = LMcreateElementMathML("mspace");
       
  1764 	  space.setAttribute("height","1.2ex");
       
  1765 	  space.setAttribute("width","0em");	// probably no effect
       
  1766 	  node = LMcreateMmlNode(symbol.tag,result[0])
       
  1767 //	  node.setAttribute("minsize","1");	// ignored
       
  1768 //	  node = LMcreateMmlNode("mrow",node);  // hopefully unnecessary
       
  1769 	  node.appendChild(space);
       
  1770 	  return [node,result[1],symbol.tag];
       
  1771 	} else
       
  1772 	  return [LMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];
       
  1773       } else if (typeof symbol.acc == "boolean" && symbol.acc) {   // accent
       
  1774         node = LMcreateMmlNode(symbol.tag,result[0]);
       
  1775 	var output = symbol.output;
       
  1776 	if (isIE) {
       
  1777 		if (symbol.input == "\\hat")
       
  1778 			output = "\u0302";
       
  1779 		else if (symbol.input == "\\widehat")
       
  1780 			output = "\u005E";
       
  1781 		else if (symbol.input == "\\bar")
       
  1782 			output = "\u00AF";
       
  1783 		else if (symbol.input == "\\grave")
       
  1784 			output = "\u0300";
       
  1785 		else if (symbol.input == "\\tilde")
       
  1786 			output = "\u0303";
       
  1787 	}
       
  1788 	var node1 = LMcreateMmlNode("mo",document.createTextNode(output));
       
  1789 	if (symbol.input == "\\vec" || symbol.input == "\\check")
       
  1790 						// don't allow to stretch
       
  1791 	    node1.setAttribute("maxsize","1.2");
       
  1792 		 // why doesn't "1" work?  \vec nearly disappears in firefox
       
  1793 	if (isIE && symbol.input == "\\bar")
       
  1794 	    node1.setAttribute("maxsize","0.5");
       
  1795 	if (symbol.input == "\\underbrace" || symbol.input == "\\underline")
       
  1796 	  node1.setAttribute("accentunder","true");
       
  1797 	else
       
  1798 	  node1.setAttribute("accent","true");
       
  1799 	node.appendChild(node1);
       
  1800 	if (symbol.input == "\\overbrace" || symbol.input == "\\underbrace")
       
  1801 	  node.ttype = UNDEROVER;
       
  1802 	return [node,result[1],symbol.tag];
       
  1803       } else {			      // font change or displaystyle command
       
  1804         if (!isIE && typeof symbol.codes != "undefined") {
       
  1805           for (i=0; i<result[0].childNodes.length; i++)
       
  1806             if (result[0].childNodes[i].nodeName=="mi" || result[0].nodeName=="mi") {
       
  1807               st = (result[0].nodeName=="mi"?result[0].firstChild.nodeValue:
       
  1808                               result[0].childNodes[i].firstChild.nodeValue);
       
  1809               var newst = [];
       
  1810               for (var j=0; j<st.length; j++)
       
  1811                 if (st.charCodeAt(j)>64 && st.charCodeAt(j)<91) newst = newst +
       
  1812                   String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);
       
  1813                 else newst = newst + st.charAt(j);
       
  1814               if (result[0].nodeName=="mi")
       
  1815                 result[0]=LMcreateElementMathML("mo").
       
  1816                           appendChild(document.createTextNode(newst));
       
  1817               else result[0].replaceChild(LMcreateElementMathML("mo").
       
  1818           appendChild(document.createTextNode(newst)),result[0].childNodes[i]);
       
  1819             }
       
  1820         }
       
  1821         node = LMcreateMmlNode(symbol.tag,result[0]);
       
  1822         node.setAttribute(symbol.atname,symbol.atval);
       
  1823 	if (symbol.input == "\\scriptstyle" ||
       
  1824 	    symbol.input == "\\scriptscriptstyle")
       
  1825 		node.setAttribute("displaystyle","false");
       
  1826 	return [node,result[1],symbol.tag];
       
  1827       }
       
  1828   case BINARY:
       
  1829     result = LMparseSexpr(str);
       
  1830     if (result[0]==null) return [LMcreateMmlNode("mo",
       
  1831 			   document.createTextNode(symbol.input)),str,null];
       
  1832     result2 = LMparseSexpr(result[1]);
       
  1833     if (result2[0]==null) return [LMcreateMmlNode("mo",
       
  1834 			   document.createTextNode(symbol.input)),str,null];
       
  1835     if (symbol.input=="\\root" || symbol.input=="\\stackrel")
       
  1836       newFrag.appendChild(result2[0]);
       
  1837     newFrag.appendChild(result[0]);
       
  1838     if (symbol.input=="\\frac") newFrag.appendChild(result2[0]);
       
  1839     return [LMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];
       
  1840   case INFIX:
       
  1841     str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1842     return [LMcreateMmlNode("mo",document.createTextNode(symbol.output)),
       
  1843 	str,symbol.tag];
       
  1844   default:
       
  1845     return [LMcreateMmlNode(symbol.tag,        //its a constant
       
  1846 	document.createTextNode(symbol.output)),str,symbol.tag];
       
  1847   }
       
  1848 }
       
  1849 
       
  1850 function LMparseIexpr(str) {
       
  1851   var symbol, sym1, sym2, node, result, tag, underover;
       
  1852   str = LMremoveCharsAndBlanks(str,0);
       
  1853   sym1 = LMgetSymbol(str);
       
  1854   result = LMparseSexpr(str);
       
  1855   node = result[0];
       
  1856   str = result[1];
       
  1857   tag = result[2];
       
  1858   symbol = LMgetSymbol(str);
       
  1859   if (symbol.ttype == INFIX) {
       
  1860     str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1861     result = LMparseSexpr(str);
       
  1862     if (result[0] == null) // show box in place of missing argument
       
  1863       result[0] = LMcreateMmlNode("mo",document.createTextNode("\u25A1"));
       
  1864     str = result[1];
       
  1865     tag = result[2];
       
  1866     if (symbol.input == "_" || symbol.input == "^") {
       
  1867       sym2 = LMgetSymbol(str);
       
  1868       tag = null;	// no space between x^2 and a following sin, cos, etc.
       
  1869 // This is for \underbrace and \overbrace
       
  1870       underover = ((sym1.ttype == UNDEROVER) || (node.ttype == UNDEROVER));
       
  1871 //    underover = (sym1.ttype == UNDEROVER);
       
  1872       if (symbol.input == "_" && sym2.input == "^") {
       
  1873         str = LMremoveCharsAndBlanks(str,sym2.input.length);
       
  1874         var res2 = LMparseSexpr(str);
       
  1875 	str = res2[1];
       
  1876 	tag = res2[2];  // leave space between x_1^2 and a following sin etc.
       
  1877         node = LMcreateMmlNode((underover?"munderover":"msubsup"),node);
       
  1878         node.appendChild(result[0]);
       
  1879         node.appendChild(res2[0]);
       
  1880       } else if (symbol.input == "_") {
       
  1881 	node = LMcreateMmlNode((underover?"munder":"msub"),node);
       
  1882         node.appendChild(result[0]);
       
  1883       } else {
       
  1884 	node = LMcreateMmlNode((underover?"mover":"msup"),node);
       
  1885         node.appendChild(result[0]);
       
  1886       }
       
  1887       node = LMcreateMmlNode("mrow",node); // so sum does not stretch
       
  1888     } else {
       
  1889       node = LMcreateMmlNode(symbol.tag,node);
       
  1890       if (symbol.input == "\\atop" || symbol.input == "\\choose")
       
  1891 	node.setAttribute("linethickness","0ex");
       
  1892       node.appendChild(result[0]);
       
  1893       if (symbol.input == "\\choose")
       
  1894 	node = LMcreateMmlNode("mfenced",node);
       
  1895     }
       
  1896   }
       
  1897   return [node,str,tag];
       
  1898 }
       
  1899 
       
  1900 function LMparseExpr(str,rightbracket,matrix) {
       
  1901   var symbol, node, result, i, tag,
       
  1902   newFrag = document.createDocumentFragment();
       
  1903   do {
       
  1904     str = LMremoveCharsAndBlanks(str,0);
       
  1905     result = LMparseIexpr(str);
       
  1906     node = result[0];
       
  1907     str = result[1];
       
  1908     tag = result[2];
       
  1909     symbol = LMgetSymbol(str);
       
  1910     if (node!=undefined) {
       
  1911       if ((tag == "mn" || tag == "mi") && symbol!=null &&
       
  1912 	typeof symbol.func == "boolean" && symbol.func) {
       
  1913 			// Add space before \sin in 2\sin x or x\sin x
       
  1914 	  var space = LMcreateElementMathML("mspace");
       
  1915 	  space.setAttribute("width","0.167em");
       
  1916 	  node = LMcreateMmlNode("mrow",node);
       
  1917 	  node.appendChild(space);
       
  1918       }
       
  1919       newFrag.appendChild(node);
       
  1920     }
       
  1921   } while ((symbol.ttype != RIGHTBRACKET)
       
  1922         && symbol!=null && symbol.output!="");
       
  1923   tag = null;
       
  1924   if (symbol.ttype == RIGHTBRACKET) {
       
  1925     if (symbol.input == "\\right") { // right what?
       
  1926       str = LMremoveCharsAndBlanks(str,symbol.input.length);
       
  1927       symbol = LMgetSymbol(str);
       
  1928       if (symbol != null && symbol.input == ".")
       
  1929 	symbol.invisible = true;
       
  1930       if (symbol != null)
       
  1931 	tag = symbol.rtag;
       
  1932     }
       
  1933     if (symbol!=null)
       
  1934       str = LMremoveCharsAndBlanks(str,symbol.input.length); // ready to return
       
  1935     var len = newFrag.childNodes.length;
       
  1936     if (matrix &&
       
  1937       len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 &&
       
  1938       newFrag.childNodes[len-2].nodeName == "mo" &&
       
  1939       newFrag.childNodes[len-2].firstChild.nodeValue == "&") { //matrix
       
  1940 	var pos = []; // positions of ampersands
       
  1941         var m = newFrag.childNodes.length;
       
  1942         for (i=0; matrix && i<m; i=i+2) {
       
  1943           pos[i] = [];
       
  1944           node = newFrag.childNodes[i];
       
  1945 	  for (var j=0; j<node.childNodes.length; j++)
       
  1946 	    if (node.childNodes[j].firstChild.nodeValue=="&")
       
  1947 	      pos[i][pos[i].length]=j;
       
  1948         }
       
  1949 	var row, frag, n, k, table = document.createDocumentFragment();
       
  1950 	for (i=0; i<m; i=i+2) {
       
  1951 	  row = document.createDocumentFragment();
       
  1952 	  frag = document.createDocumentFragment();
       
  1953 	  node = newFrag.firstChild; // <mrow> -&-&...&-&- </mrow>
       
  1954 	  n = node.childNodes.length;
       
  1955 	  k = 0;
       
  1956 	  for (j=0; j<n; j++) {
       
  1957 	    if (typeof pos[i][k] != "undefined" && j==pos[i][k]){
       
  1958 	      node.removeChild(node.firstChild); //remove &
       
  1959 	      row.appendChild(LMcreateMmlNode("mtd",frag));
       
  1960 	      k++;
       
  1961 	    } else frag.appendChild(node.firstChild);
       
  1962 	  }
       
  1963 	  row.appendChild(LMcreateMmlNode("mtd",frag));
       
  1964 	  if (newFrag.childNodes.length>2) {
       
  1965 	    newFrag.removeChild(newFrag.firstChild); //remove <mrow> </mrow>
       
  1966 	    newFrag.removeChild(newFrag.firstChild); //remove <mo>&</mo>
       
  1967 	  }
       
  1968 	  table.appendChild(LMcreateMmlNode("mtr",row));
       
  1969 	}
       
  1970 	return [table,str];
       
  1971     }
       
  1972     if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
       
  1973       node = LMcreateMmlNode("mo",document.createTextNode(symbol.output));
       
  1974       newFrag.appendChild(node);
       
  1975     }
       
  1976   }
       
  1977   return [newFrag,str,tag];
       
  1978 }
       
  1979 
       
  1980 function LMparseMath(str) {
       
  1981   var result, node = LMcreateElementMathML("mstyle");
       
  1982   if (LMmathcolor != "") node.setAttribute("mathcolor",LMmathcolor);
       
  1983   if (LMmathfontfamily != "") node.setAttribute("fontfamily",LMmathfontfamily);
       
  1984   node.appendChild(LMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);
       
  1985   node = LMcreateMmlNode("math",node);
       
  1986   if (LMshowasciiformulaonhover)                    //fixed by djhsu so newline
       
  1987     node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko
       
  1988   var fnode = LMcreateElementXHTML("span");
       
  1989   fnode.style.fontSize = mathfontsize;
       
  1990   if (LMmathfontfamily != "") fnode.style.fontFamily = LMmathfontfamily;
       
  1991   fnode.appendChild(node);
       
  1992   return fnode;
       
  1993 }
       
  1994 
       
  1995 function LMstrarr2docFrag(arr, linebreaks) {
       
  1996   var newFrag=document.createDocumentFragment();
       
  1997   var expr = false;
       
  1998   for (var i=0; i<arr.length; i++) {
       
  1999     if (expr) newFrag.appendChild(LMparseMath(arr[i]));
       
  2000     else {
       
  2001       var arri = (linebreaks ? arr[i].split("\n\n") : [arr[i]]);
       
  2002       newFrag.appendChild(LMcreateElementXHTML("span").
       
  2003       appendChild(document.createTextNode(arri[0])));
       
  2004       for (var j=1; j<arri.length; j++) {
       
  2005         newFrag.appendChild(LMcreateElementXHTML("p"));
       
  2006         newFrag.appendChild(LMcreateElementXHTML("span").
       
  2007         appendChild(document.createTextNode(arri[j])));
       
  2008       }
       
  2009     }
       
  2010     expr = !expr;
       
  2011   }
       
  2012   return newFrag;
       
  2013 }
       
  2014 
       
  2015 function LMprocessNodeR(n, linebreaks) {
       
  2016   var mtch, str, arr, frg, i;
       
  2017   if (n.childNodes.length == 0) {
       
  2018    if ((n.nodeType!=8 || linebreaks) &&
       
  2019     n.parentNode.nodeName!="form" && n.parentNode.nodeName!="FORM" &&
       
  2020     n.parentNode.nodeName!="textarea" && n.parentNode.nodeName!="TEXTAREA" &&
       
  2021     n.parentNode.nodeName!="pre" && n.parentNode.nodeName!="PRE") {
       
  2022     str = n.nodeValue;
       
  2023     if (!(str == null)) {
       
  2024       str = str.replace(/\r\n\r\n/g,"\n\n");
       
  2025       str = str.replace(/\x20+/g," ");
       
  2026       str = str.replace(/\s*\r\n/g," ");
       
  2027 // DELIMITERS:
       
  2028       mtch = (str.indexOf("\$")==-1 ? false : true);
       
  2029       str = str.replace(/([^\\])\$/g,"$1 \$");
       
  2030       str = str.replace(/^\$/," \$");	// in case \$ at start of string
       
  2031       arr = str.split(" \$");
       
  2032       for (i=0; i<arr.length; i++)
       
  2033 	arr[i]=arr[i].replace(/\\\$/g,"\$");
       
  2034       if (arr.length>1 || mtch) {
       
  2035         if (LMcheckForMathML) {
       
  2036           LMcheckForMathML = false;
       
  2037           var nd = LMisMathMLavailable();
       
  2038           LMnoMathML = nd != null;
       
  2039           if (LMnoMathML && LMnotifyIfNoMathML)
       
  2040             if (LMalertIfNoMathML)
       
  2041               alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\n\
       
  2042                 or Firefox/Mozilla/Netscape");
       
  2043             else LMbody.insertBefore(nd,LMbody.childNodes[0]);
       
  2044         }
       
  2045         if (!LMnoMathML) {
       
  2046           frg = LMstrarr2docFrag(arr,n.nodeType==8);
       
  2047           var len = frg.childNodes.length;
       
  2048           n.parentNode.replaceChild(frg,n);
       
  2049           return len-1;
       
  2050         } else return 0;
       
  2051       }
       
  2052     }
       
  2053    } else return 0;
       
  2054   } else if (n.nodeName!="math") {
       
  2055     for (i=0; i<n.childNodes.length; i++)
       
  2056       i += LMprocessNodeR(n.childNodes[i], linebreaks);
       
  2057   }
       
  2058   return 0;
       
  2059 }
       
  2060 
       
  2061 var tcnt = 0, dcnt = 0; //theorem and definition counters
       
  2062 
       
  2063 function simpleLaTeXformatting(st) {
       
  2064   st = st.replace(/\$\$(.*?)\$\$/g,"<p align=\"center\">$\\displaystyle{$1}$</p>");
       
  2065   st = st.replace(/\\begin{(theorem|lemma|proposition|corollary)}((.|\n)*?)\\end{\1}/g,function(r,s,t){tcnt++; return "<b>"+s.charAt(0).toUpperCase()+s.slice(1)+" "+tcnt+".</b> <i>"+t.replace(/^\s*<\/?\w+\/?>|\s*<\/?\w+\/?>$/g,"")+"</i>"});
       
  2066   st = st.replace(/\\begin{(definition|example|remark|problem|exercise|conjecture|solution)}((.|\n)*?)\\end{\1}/g,function(r,s,t){dcnt++; return "<b>"+s.charAt(0).toUpperCase()+s.slice(1)+" "+dcnt+".</b> "+t.replace(/^\s*<\/?\w+\/?>|\s*<\/?\w+\/?>$/g,"")});
       
  2067   st = st.replace(/\\begin{proof}((.|\n)*?)\\end{proof}/g,function(s,t){return "<i>Proof:</i> "+t.replace(/^\s*<\/?\w+\/?>|\s*<\/?\w+\/?>$/g,"")+" &#x25A1;"});
       
  2068   st = st.replace(/\\emph{(.*?)}/g,"<em>$1</em>");
       
  2069   st = st.replace(/\\textbf{(.*?)}/g,"<b>$1</b>");
       
  2070   st = st.replace(/\\cite{(.*?)}/g,"[$1]");
       
  2071   st = st.replace(/\\chapter{(.*?)}/g,"<h2>$1</h2>");
       
  2072   st = st.replace(/\\section{(.*?)}(\s*<\/?(br|p)\s?\/?>)?/g,"<h3>$1</h3>");
       
  2073   st = st.replace(/\\subsection{(.*?)}/g,"<h4>$1</h4>");
       
  2074   st = st.replace(/\\begin{itemize}(\s*<\/?(br|p)\s?\/?>)?/g,"<ul>");
       
  2075   st = st.replace(/\\item\s((.|\n)*?)(?=(\\item|\\end))/g,"<li>$1</li>");
       
  2076   st = st.replace(/\\end{itemize}(\s*<\/?(br|p)\s?\/?>)?/g,"</ul>");
       
  2077   st = st.replace(/\\begin{enumerate}(\s*<\/?(br|p)\s?\/?>)?/g,"<ol>");
       
  2078   st = st.replace(/\\end{enumerate}(\s*<\/?(br|p)\s?\/?>)?/g,"</ol>");
       
  2079   st = st.replace(/\\item\[(.*?)]{(.*?)}/g,"<dt>$1</dt><dd>$2</dd>");
       
  2080   st = st.replace(/\\begin{description}/g,"<dl>");
       
  2081   st = st.replace(/\\end{description}/g,"</dl>");
       
  2082   st = st.replace(/\\newline\b/g,"<br/>");
       
  2083   st = st.replace(/\\newpage\b/g,"<br style=\"page-break-after:always;\">");
       
  2084   st = st.replace(/\\par\b/g,"<p>&nbsp;</p>");
       
  2085   st = st.replace(/\\bigskip/g,"<p style=\"margin-bottom:0.5in\">&nbsp;</p>");
       
  2086   st = st.replace(/\\medskip/g,"<p style=\"margin-bottom:0.3in\">&nbsp;</p>");
       
  2087   st = st.replace(/\\smallskip/g,"<p style=\"margin-bottom:0.15in\">&nbsp;</p>");
       
  2088   st = st.replace(/\\begin{center}(.*?)\\end{center}/g,"<p align=\"center\">$1</p>");
       
  2089   st = st.replace(/<embed\s+class\s?=\s?"ASCIIsvg"/g,"<embed class=\"ASCIIsvg\" src=\""+dsvglocation+"d.svg\" wmode=\"transparent\"");
       
  2090   st = st.replace(/(?:\\begin{a?graph}|agraph|\(:graph\s)((.|\n)*?)(?:\\end{a?graph}|enda?graph|:\))/g,function(s,t){return "<div><embed class=\"ASCIIsvg\" src=\""+dsvglocation+"d.svg\" wmode=\"transparent\" script=\'"+t.replace(/<\/?(br|p|pre)\s?\/?>/gi,"\n")+"\'/></div>"});
       
  2091 //  st = st.replace(/\(:graph((.|\n)*?):\)/g,function(s,t){return "<div><embed class=\"ASCIIsvg\" src=\""+dsvglocation+"d.svg\" wmode=\"transparent\" script=\'"+t.replace(/<\/?(br|p|pre)\s?\/?>/gi,"\n")+"\'/></div>"});
       
  2092   st = st.replace(/insertASCIIMathCalculator/g,"<div class=\"ASCIIMathCalculator\"></div>");
       
  2093   return st
       
  2094 }
       
  2095 
       
  2096 function LMprocessNode(n, linebreaks, spanclassLM) {
       
  2097   var frag,st;
       
  2098   if (spanclassLM!=null) {
       
  2099     frag = document.getElementsByTagName("span")
       
  2100     for (var i=0;i<frag.length;i++)
       
  2101       if (frag[i].className == "LM")
       
  2102         LMprocessNodeR(frag[i],linebreaks);
       
  2103   } else {
       
  2104     try {
       
  2105       st = n.innerHTML;
       
  2106     } catch(err) {}
       
  2107     var am = /amath|agraph/i.test(st);
       
  2108     if ((st==null || st.indexOf("\$ ")!=-1 || st.indexOf("\$<")!=-1 || 
       
  2109          st.indexOf("\\begin")!=-1 || am || st.slice(-1)=="$" ||
       
  2110          st.indexOf("\$\n")!=-1)&& !/edit-content|HTMLArea|wikiedit/.test(st)){
       
  2111       if (!avoidinnerHTML && translateLaTeXformatting) 
       
  2112         st = simpleLaTeXformatting(st);
       
  2113       if (st!=null && am && !avoidinnerHTML) {
       
  2114 //alert(st)
       
  2115         st = st.replace(/<sup>(.*?)<\/sup>(\s|(\S))/gi,"^{$1} $3");
       
  2116 //        st = st.replace(/<\/?font.*?>/gi,""); // do this only in amath...end
       
  2117         st = st.replace(/(Proof:)/g,"<i>$1</i>");
       
  2118         st = st.replace(/QED/g,"&#x25A1;");
       
  2119         st = st.replace(/(\\?end{?a?math}?)/ig,"<span></span>$1");
       
  2120         st = st.replace(/(\bamath|\\begin{a?math})/ig,"<span></span>$1");
       
  2121         st = st.replace(/([>\n])(Theorem|Lemma|Proposition|Corollary|Definition|Example|Remark|Problem|Exercise|Conjecture|Solution)(:|\W\W?(\w|\.)*?\W?:)/g,"$1<b>$2$3</b>");
       
  2122       }
       
  2123       st = st.replace(/%7E/g,"~");
       
  2124       if (!avoidinnerHTML) n.innerHTML = st;
       
  2125       LMprocessNodeR(n,linebreaks);
       
  2126     }
       
  2127   }
       
  2128   if (isIE) { //needed to match size and font of formula to surrounding text
       
  2129     frag = document.getElementsByTagName('math');
       
  2130     for (var i=0;i<frag.length;i++) frag[i].update()
       
  2131   }
       
  2132 }
       
  2133 
       
  2134 var LMbody;
       
  2135 var LMnoMathML = false, LMtranslated = false;
       
  2136 
       
  2137 function LMtranslate(spanclassLM) {
       
  2138   if (!LMtranslated) { // run this only once
       
  2139     LMtranslated = true;
       
  2140     LMinitSymbols();
       
  2141     LMbody = document.getElementsByTagName("body")[0];
       
  2142     var processN = document.getElementById(AMdocumentId);
       
  2143 //alert(processN)
       
  2144     LMprocessNode((processN!=null?processN:LMbody), false, spanclassLM);
       
  2145   }
       
  2146 }
       
  2147 
       
  2148 if (isIE) { // avoid adding MathPlayer info explicitly to each webpage
       
  2149   document.write("<object id=\"mathplayer\"\
       
  2150   classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");
       
  2151   document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");
       
  2152 }
       
  2153 
       
  2154 /* ASCIIsvg.js
       
  2155 ==============
       
  2156 JavaScript routines to dynamically generate Scalable Vector Graphics
       
  2157 using a mathematical xy-coordinate system (y increases upwards) and
       
  2158 very intuitive JavaScript commands (no programming experience required).
       
  2159 ASCIIsvg.js is good for learning math and illustrating online math texts.
       
  2160 Works with Internet Explorer+Adobe SVGviewer and SVG enabled Mozilla/Firefox.
       
  2161 
       
  2162 Ver 1.2.9 July 31, 2007 (c) Peter Jipsen http://www.chapman.edu/~jipsen
       
  2163 Latest version at http://math.chapman.edu/~jipsen/math/pub/ASCIIsvg.js
       
  2164 If you use it on a webpage, please send the URL to jipsen@chapman.edu
       
  2165 
       
  2166 This program is free software; you can redistribute it and/or modify
       
  2167 it under the terms of the GNU Lesser General Public License as published by
       
  2168 the Free Software Foundation; either version 2.1 of the License, or (at
       
  2169 your option) any later version.
       
  2170 
       
  2171 This program is distributed in the hope that it will be useful, 
       
  2172 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
  2173 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
       
  2174 General Public License (at http://www.gnu.org/license/lgpl.html) 
       
  2175 for more details.*/
       
  2176 
       
  2177 // you can change these
       
  2178 var checkIfSVGavailable = true;
       
  2179 var notifyIfNoSVG = true;
       
  2180 var alertIfNoSVG = false;
       
  2181 
       
  2182 // global defaults used if not specified by graph (you can change these)
       
  2183 var defaultwidth = 300; defaultheight = 200;   // in pixels
       
  2184 var defaultxmin = -5.5; defaultxmax = 5.5;     // in usercoords
       
  2185 var defaultborder = 0; border = defaultborder; // in pixel
       
  2186 var defaultstrokewidth = "1"; // default line width in pixel
       
  2187 var defaultstroke = "blue";   // default line color
       
  2188 var defaultstrokeopacity = 1; // transparent = 0, solid =1
       
  2189 var defaultstrokedasharray = null; // "10,10" gives 10px long dashes
       
  2190 var defaultfill = "none";        // default fill color
       
  2191 var defaultfillopacity = 1;      // transparent = 0, solid =1
       
  2192 var defaultfontstyle = "normal"; // default text shape normal|italic|inherit
       
  2193 var defaultfontfamily = "times"; // default font times|ariel|helvetica|...
       
  2194 var defaultfontsize = "16";      // default size (scaled automatically)
       
  2195 var defaultfontweight = "normal";// normal|bold|bolder|lighter|100|...|900
       
  2196 var defaultfontstroke = "none";  // default font outline color
       
  2197 var defaultfontfill = "none";    // default font color
       
  2198 var defaultmarker = "none";      // "dot" | "arrow" | "+" | "-" | "|"
       
  2199 var defaultendpoints = "";       // "c-d" where c is <|o|* and d is >|o|*
       
  2200 
       
  2201 // global values used for all pictures (you can change these)
       
  2202 var showcoordinates = true;
       
  2203 var markerstrokewidth = "1";
       
  2204 var markerstroke = "black";
       
  2205 var markerfill = "yellow";
       
  2206 var markersize = 4;
       
  2207 var arrowfill = stroke;
       
  2208 var dotradius = 4;
       
  2209 var ticklength = 4;
       
  2210 var axesstroke = "black";
       
  2211 var gridstroke = "grey";
       
  2212 var backgroundstyle = "fill-opacity:0; fill:white";
       
  2213 var singlelettersitalic = true;
       
  2214 
       
  2215 // internal variables (probably no need to change these)
       
  2216 var picturepos = null; // position of picture relative to top of HTML page
       
  2217 var xunitlength;       // in pixels, used to convert to user coordinates
       
  2218 var yunitlength;       // in pixels
       
  2219 var origin = [0,0];    // in pixels (default is bottom left corner)
       
  2220 var above = "above";   // shorthands (to avoid typing quotes)
       
  2221 var below = "below";
       
  2222 var left = "left";
       
  2223 var right = "right";
       
  2224 var aboveleft = "aboveleft";
       
  2225 var aboveright = "aboveright";
       
  2226 var belowleft = "belowleft";
       
  2227 var belowright = "belowright";
       
  2228 var xmin, xmax, ymin, ymax, xscl, yscl, 
       
  2229     xgrid, ygrid, xtick, ytick, initialized;
       
  2230 var strokewidth, strokedasharray, stroke, fill, strokeopacity, fillopacity;
       
  2231 var fontstyle, fontfamily, fontsize, fontweight, fontstroke, fontfill;
       
  2232 var marker, endpoints, dynamic = {};
       
  2233 var picture, svgpicture, doc, width, height, a, b, c, d, i, n, p, t, x, y;
       
  2234 var isIE = document.createElementNS==null;
       
  2235 
       
  2236 var cpi = "\u03C0", ctheta = "\u03B8";      // character for pi, theta
       
  2237 var log = function(x) { return ln(x)/ln(10) };
       
  2238 var pi = Math.PI, e = Math.E, ln = Math.log, sqrt = Math.sqrt;
       
  2239 var floor = Math.floor, ceil = Math.ceil, abs = Math.abs;
       
  2240 var sin = Math.sin, cos = Math.cos, tan = Math.tan;
       
  2241 var arcsin = Math.asin, arccos = Math.acos, arctan = Math.atan;
       
  2242 var sec = function(x) { return 1/Math.cos(x) };
       
  2243 var csc = function(x) { return 1/Math.sin(x) };
       
  2244 var cot = function(x) { return 1/Math.tan(x) };
       
  2245 var arcsec = function(x) { return arccos(1/x) };
       
  2246 var arccsc = function(x) { return arcsin(1/x) };
       
  2247 var arccot = function(x) { return arctan(1/x) };
       
  2248 var sinh = function(x) { return (Math.exp(x)-Math.exp(-x))/2 };
       
  2249 var cosh = function(x) { return (Math.exp(x)+Math.exp(-x))/2 };
       
  2250 var tanh = 
       
  2251   function(x) { return (Math.exp(x)-Math.exp(-x))/(Math.exp(x)+Math.exp(-x)) };
       
  2252 var sech = function(x) { return 1/cosh(x) };
       
  2253 var csch = function(x) { return 1/sinh(x) };
       
  2254 var coth = function(x) { return 1/tanh(x) };
       
  2255 var arcsinh = function(x) { return ln(x+Math.sqrt(x*x+1)) };
       
  2256 var arccosh = function(x) { return ln(x+Math.sqrt(x*x-1)) };
       
  2257 var arctanh = function(x) { return ln((1+x)/(1-x))/2 };
       
  2258 var sech = function(x) { return 1/cosh(x) };
       
  2259 var csch = function(x) { return 1/sinh(x) };
       
  2260 var coth = function(x) { return 1/tanh(x) };
       
  2261 var arcsech = function(x) { return arccosh(1/x) };
       
  2262 var arccsch = function(x) { return arcsinh(1/x) };
       
  2263 var arccoth = function(x) { return arctanh(1/x) };
       
  2264 var sign = function(x) { return (x==0?0:(x<0?-1:1)) };
       
  2265 
       
  2266 function factorial(x,n) { // Factorial function
       
  2267   if (n==null) n=1;
       
  2268   if (Math.abs(x-Math.round(x*1000000)/1000000)<1e-15)
       
  2269     x = Math.round(x*1000000)/1000000;
       
  2270   if (x-Math.floor(x)!=0) return NaN;
       
  2271   for (var i=x-n; i>0; i-=n) x*=i;
       
  2272   return (x<0?NaN:(x==0?1:x));
       
  2273 }
       
  2274 
       
  2275 function C(x,k) {  // Binomial coefficient function
       
  2276   var res=1;
       
  2277   for (var i=0; i<k; i++) res*=(x-i)/(k-i);
       
  2278   return res;
       
  2279 }
       
  2280 
       
  2281 function chop(x,n) { // Truncate decimal number to n places after decimal point
       
  2282   if (n==null) n=0;
       
  2283   return Math.floor(x*Math.pow(10,n))/Math.pow(10,n);
       
  2284 }
       
  2285 
       
  2286 function ran(a,b,n) { // Generate random number in [a,b] with n digits after .
       
  2287   if (n==null) n=0;
       
  2288   return chop((b+Math.pow(10,-n)-a)*Math.random()+a,n);
       
  2289 }
       
  2290 
       
  2291 function myCreateElementXHTML(t) {
       
  2292   if (isIE) return document.createElement(t);
       
  2293   else return document.createElementNS("http://www.w3.org/1999/xhtml",t);
       
  2294 }
       
  2295 
       
  2296 function myCreateElementSVG(t) {
       
  2297   if (isIE) return doc.createElement(t);
       
  2298   else return doc.createElementNS("http://www.w3.org/2000/svg",t);
       
  2299 }
       
  2300 
       
  2301 function getElementsByClass(container, tagName, clsName){
       
  2302   var list = new Array(0);
       
  2303   var collection = container.getElementsByTagName(tagName);
       
  2304   for(var i = 0; i < collection.length; i++)
       
  2305     if(collection[i].className.slice(0,clsName.length)==clsName)
       
  2306       list[list.length] = collection[i];
       
  2307   return list;
       
  2308 }
       
  2309 
       
  2310 function findPos(obj) { // top-left corner of obj on HTML page in pixel
       
  2311   var curleft = curtop = 0;
       
  2312   if (obj.offsetParent) {
       
  2313     curleft = obj.offsetLeft
       
  2314     curtop = obj.offsetTop
       
  2315     while (obj = obj.offsetParent) {
       
  2316       curleft += obj.offsetLeft
       
  2317       curtop += obj.offsetTop
       
  2318     }
       
  2319   }
       
  2320   return [curleft,curtop];
       
  2321 }
       
  2322 
       
  2323 function isSVGavailable() {
       
  2324   var nd = myCreateElementXHTML("center");
       
  2325   nd.appendChild(document.createTextNode("To view the "));
       
  2326   var an = myCreateElementXHTML("a");
       
  2327   an.appendChild(document.createTextNode("ASCIIsvg"));
       
  2328   an.setAttribute("href","http://www.chapman.edu/~jipsen/asciisvg.html");
       
  2329   nd.appendChild(an);
       
  2330   nd.appendChild(document.createTextNode(" images use Internet Explorer 6+"));
       
  2331   an = myCreateElementXHTML("a");
       
  2332   an.appendChild(document.createTextNode("Adobe SVGviewer 3.02"));
       
  2333   an.setAttribute("href","http://www.adobe.com/svg");
       
  2334   nd.appendChild(an);
       
  2335   nd.appendChild(document.createTextNode(" or "));
       
  2336   an = myCreateElementXHTML("a");
       
  2337   an.appendChild(document.createTextNode("SVG enabled Mozilla/Firefox"));
       
  2338   an.setAttribute("href",
       
  2339     "http://www.chapman.edu/~jipsen/svg/svgenabledmozillafirefox.html");
       
  2340   nd.appendChild(an);
       
  2341   if (navigator.appName.slice(0,8)=="Netscape") 
       
  2342     if (window['SVGElement']) return null;
       
  2343     else return nd;
       
  2344   else if (navigator.appName.slice(0,9)=="Microsoft")
       
  2345     try {
       
  2346       var oSVG=eval("new ActiveXObject('Adobe.SVGCtl.3');");
       
  2347         return null;
       
  2348     } catch (e) {
       
  2349         return nd;
       
  2350     }
       
  2351   else return nd;
       
  2352 }
       
  2353 
       
  2354 function setText(st,id) { // add text to an existing node with given id
       
  2355   var node = document.getElementById(id);
       
  2356   if (node!=null)
       
  2357     if (node.childNodes.length!=0) node.childNodes[0].nodeValue = st;
       
  2358     else node.appendChild(document.createTextNode(st));
       
  2359 }
       
  2360 
       
  2361 function getX(evt) { // return mouse x-coord in user coordinate system
       
  2362   var svgroot = evt.target.parentNode;
       
  2363   return (evt.clientX+(isIE?0:window.pageXOffset)-svgroot.getAttribute("left")-svgroot.getAttribute("ox"))/(svgroot.getAttribute("xunitlength")-0);
       
  2364 }
       
  2365 
       
  2366 function getY(evt) { // return mouse y-coord in user coordinate system
       
  2367   var svgroot = evt.target.parentNode;
       
  2368   return (svgroot.getAttribute("height")-svgroot.getAttribute("oy")-(evt.clientY+(isIE?0:window.pageYOffset)-svgroot.getAttribute("top")))/(svgroot.getAttribute("yunitlength")-0);
       
  2369 }
       
  2370 
       
  2371 function translateandeval(src) { //modify user input to JavaScript syntax
       
  2372   var errstr;
       
  2373   // replace plot(f(x),...) with plot("f(x)",...)  
       
  2374   src = src.replace(/plot\(\x20*([^\"f\[][^\n\r;]+?)\,/g,"plot\(\"$1\",");
       
  2375   src = src.replace(/plot\(\x20*([^\"f\[][^\n\r;]+)\)/g,"plot(\"$1\")");
       
  2376 
       
  2377   // replace (expr,expr) by [expr,expr] where expr has no (,) in it
       
  2378   src = src.replace(/([=(,]\x20*)\(([-a-z0-9./+*]+?),([-a-z0-9./+*]+?)\)/g,"$1[$2,$3]");
       
  2379 
       
  2380   // insert * between digit and letter e.g. 2x --> 2*x
       
  2381   src = src.replace(/([0-9])([a-zA-Z])/g,"$1*$2");
       
  2382   src = src.replace(/\)([\(0-9a-zA-Z])/g,"\)*$1");
       
  2383 
       
  2384   try {
       
  2385     with (Math) eval(src);          // here the svgpicture object is created
       
  2386   } catch(err) {
       
  2387     if (err!="wait") {
       
  2388       if (typeof err=="object") 
       
  2389         errstr = err.name+" "+err.message+" "+err.number+" "+err.description;
       
  2390       else errstr = err;
       
  2391       alert(errstr+"\n"+src)
       
  2392     }
       
  2393   }
       
  2394 }
       
  2395 
       
  2396 function drawPictures() { // main routine; called after webpage has loaded
       
  2397   var src, id, dsvg, nd, node, ht, index, cols, arr, i, node2;
       
  2398   var pictures = document.getElementsByTagName("textarea");
       
  2399   for (index = 0; index<pictures.length; index++)
       
  2400     if (pictures[index].className=="ASCIIsvg"){
       
  2401       pictures[index].style.display="none";  // hide the textarea
       
  2402     }
       
  2403   var ASbody = document.getElementsByTagName("body")[0];
       
  2404   pictures = getElementsByClass(ASbody,"embed","ASCIIsvg");
       
  2405   var len = pictures.length;
       
  2406   if (checkIfSVGavailable) {
       
  2407     nd = isSVGavailable();
       
  2408     if (nd != null && notifyIfNoSVG && len>0)
       
  2409       if (alertIfNoSVG)
       
  2410         alert("To view the SVG pictures in Internet Explorer\n\
       
  2411 download the free Adobe SVGviewer from www.adobe.com/svg or\n\
       
  2412 use Firefox 2.0 or later");
       
  2413       else {
       
  2414         ASbody.insertBefore(nd,ASbody.childNodes[0]);
       
  2415       }
       
  2416   }
       
  2417  if (nd == null) {
       
  2418   for (index = 0; index < len; index++) {
       
  2419    width = null; height = null; 
       
  2420    xmin = null; xmax = null; ymin = null; ymax = null;
       
  2421    xscl = null; xgrid = null; yscl = null; ygrid = null;
       
  2422    initialized = false;
       
  2423    picture = pictures[index];  // current picture object
       
  2424    src = picture.getAttribute("script"); // get the ASCIIsvg code
       
  2425    if (src==null) src = "";
       
  2426    // insert "axes()" if not present  ******** experimental
       
  2427    if (!/axes\b|initPicture/.test(src)) {
       
  2428      var i = 0
       
  2429      while (/((yscl|ymax|ymin|xscl|xmax|xmin|\bwidth|\bheight)\s*=\s*-?\d*(\d\.|\.\d|\d)\d*\s*;?)/.test(src.slice(i))) i++;
       
  2430      src = (i==0?"axes(); "+src: src.slice(0,i)+src.slice(i).replace(/((scl|max|min|idth|eight)\s*=\s*-?\d*(\d\.|\.\d|\d)\d*\s*;?)/,"$1\naxes();"));
       
  2431    }
       
  2432    ht = picture.getAttribute("height");
       
  2433    if (isIE) {
       
  2434      picture.setAttribute("wmode","transparent");
       
  2435 //alert("*"+picture.getAttribute("src")+dsvglocation);
       
  2436 //adding d.svg dynamically greates problems in IE...
       
  2437      if (picture.getAttribute("src")=="") picture.setAttribute("src",dsvglocation+"d.svg");
       
  2438    }
       
  2439    if (document.getElementById("picture"+(index+1)+"mml")==null) {
       
  2440      picture.parentNode.style.position = "relative";
       
  2441      node = myCreateElementXHTML("div");
       
  2442      node.style.position = "absolute";
       
  2443      node.style.top = "0px";
       
  2444      node.style.left = "0px";
       
  2445      node.setAttribute("id","picture"+(index+1)+"mml");
       
  2446      picture.parentNode.insertBefore(node,picture.nextSibling);
       
  2447    }
       
  2448    if (ht==null) ht ="";
       
  2449 //   if (ht!="") defaultborder = 25;
       
  2450    if (ht=="" || src=="") 
       
  2451     if (document.getElementById("picture"+(index+1)+"input")==null) {
       
  2452       node = myCreateElementXHTML("textarea");
       
  2453       arr = src.split("\n");
       
  2454       cols = 0;
       
  2455       for (i=0;i<arr.length;i++) cols = Math.max(cols,arr[i].length);
       
  2456       node.setAttribute("rows",Math.min(10,arr.length)+1);
       
  2457       node.setAttribute("cols",Math.max(Math.min(60,cols),20)+5);
       
  2458 //      node.setAttribute("style","display:block");
       
  2459       if (isIE) src = src.replace(/([^\r])\n/g,"$1\r");
       
  2460       node.appendChild(document.createTextNode(src));
       
  2461       if (src.indexOf("showcode()")==-1) node.style.display = "none";
       
  2462       node.setAttribute("id","picture"+(index+1)+"input");
       
  2463       picture.parentNode.insertBefore(node,picture.nextSibling);
       
  2464       picture.parentNode.insertBefore(myCreateElementXHTML("br"),node);
       
  2465       node2 = myCreateElementXHTML("button");
       
  2466       node2.setAttribute("id","picture"+(index+1)+"button");
       
  2467       if (isIE) node2.onclick = function() {updatePicture(this)};
       
  2468       else node2.setAttribute("onclick","updatePicture(this)");
       
  2469       node2.appendChild(document.createTextNode("Update"));
       
  2470       if (src.indexOf("showcode()")==-1) node2.style.display = "none";
       
  2471       picture.parentNode.insertBefore(node2,node);
       
  2472       picture.parentNode.insertBefore(myCreateElementXHTML("br"),node);
       
  2473     } else src = document.getElementById("picture"+(index+1)+"input").value;
       
  2474     id = picture.getAttribute("id");
       
  2475     dsvg = picture.getAttribute("src");
       
  2476     if (id == null || id == "") {
       
  2477       id = "picture"+(index+1);
       
  2478       picture.setAttribute("id",id);
       
  2479     }
       
  2480     translateandeval(src)
       
  2481   }
       
  2482  }
       
  2483 }
       
  2484 
       
  2485 function setdefaults() { //called before each graph is evaluated
       
  2486   strokewidth = defaultstrokewidth;
       
  2487   stroke = defaultstroke;
       
  2488   strokeopacity = defaultstrokeopacity;
       
  2489   strokedasharray = defaultstrokedasharray;
       
  2490   fill = defaultfill;
       
  2491   fillopacity = defaultfillopacity;
       
  2492   fontstyle = defaultfontstyle;
       
  2493   fontfamily = defaultfontfamily;
       
  2494   fontsize = defaultfontsize;
       
  2495   fontweight = defaultfontweight;
       
  2496   fontstroke = defaultfontstroke;
       
  2497   fontfill = defaultfontfill;
       
  2498   marker = defaultmarker;
       
  2499   endpoints = defaultendpoints;
       
  2500 }
       
  2501 
       
  2502 function switchTo(id) { // used by dynamic code to select appropriate graph
       
  2503   picture = document.getElementById(id);
       
  2504   width = picture.getAttribute("width")-0;
       
  2505   height = picture.getAttribute("height")-0;
       
  2506   setdefaults();
       
  2507   if ((picture.nodeName == "EMBED" || picture.nodeName == "embed") && isIE) {
       
  2508     svgpicture = picture.getSVGDocument().getElementById("root");
       
  2509     doc = picture.getSVGDocument();
       
  2510   } else {
       
  2511     svgpicture = picture;
       
  2512     doc = document;
       
  2513   }
       
  2514   xunitlength = svgpicture.getAttribute("xunitlength")-0;
       
  2515   yunitlength = svgpicture.getAttribute("yunitlength")-0;
       
  2516   xmin = svgpicture.getAttribute("xmin")-0;
       
  2517   xmax = svgpicture.getAttribute("xmax")-0;
       
  2518   ymin = svgpicture.getAttribute("ymin")-0;
       
  2519   ymax = svgpicture.getAttribute("ymax")-0;
       
  2520   origin = [svgpicture.getAttribute("ox")-0,svgpicture.getAttribute("oy")-0];
       
  2521 }
       
  2522 
       
  2523 function updatePicture(obj) {
       
  2524   var node, src, id;
       
  2525   if (typeof obj=="object") id = obj.id.slice(0,-6);
       
  2526   else id = (typeof obj=="string"?obj:"picture"+(obj+1));
       
  2527   src = document.getElementById(id+"input").value;
       
  2528   xmin = null; xmax = null; ymin = null; ymax = null;
       
  2529   xscl = null; xgrid = null; yscl = null; ygrid = null;
       
  2530   initialized = false;
       
  2531   picture = document.getElementById(id);
       
  2532 //  switchTo(id);
       
  2533   translateandeval(src)
       
  2534 }
       
  2535 
       
  2536 function changepicturesize(evt,factor) {
       
  2537   var obj = evt.target;
       
  2538   var name = obj.parentNode.getAttribute("name");
       
  2539   var pic = document.getElementById(name);
       
  2540   var src = document.getElementById(name+"input").value;
       
  2541   src = src.replace(/width\s*=\s*\d+/,"width="+(factor*(pic.getAttribute("width")-0)));
       
  2542   src = src.replace(/height\s*=\s*\d+/,"height="+(factor*(pic.getAttribute("height")-0)));
       
  2543   document.getElementById(name+"input").value = src;
       
  2544 //alert(getKey(evt.keycode))
       
  2545   updatePicture(name);
       
  2546 }
       
  2547 
       
  2548 var sinceFirstClick = 0; // ondblclick simulation from 
       
  2549 var dblClkTimer;         // http://www.enja.org/david/?cat=13 Thanks!
       
  2550 function timer() {
       
  2551   if(sinceFirstClick<60) {
       
  2552     sinceFirstClick++;
       
  2553     setTimeout("timer()",10);
       
  2554   } else {
       
  2555     clearTimeout(dblClkTimer);
       
  2556     dblClkTimer = "";
       
  2557   }
       
  2558 }
       
  2559 function mClick(evt) {
       
  2560   if(sinceFirstClick!=0) {
       
  2561     if(sinceFirstClick <= 40) {
       
  2562       if (evt.shiftKey) changepicturesize(evt,2);
       
  2563       else if (evt.altKey) changepicturesize(evt,.5);
       
  2564       else showHideCode(evt);             // do this on dblclick
       
  2565       clearTimeout(dblClkTimer);
       
  2566       dblClkTimer = "";
       
  2567     } else {
       
  2568       clearTimeout(dblClkTimer);
       
  2569       sinceFirstClick = 0;
       
  2570       dblClkTimer = setTimeout("timer()",10);
       
  2571     }	      
       
  2572   } else {
       
  2573     sinceFirstClick = 0;
       
  2574     dblClkTimer = setTimeout("timer()",10);
       
  2575   }
       
  2576 }
       
  2577 
       
  2578 function showHideCode(evt) { // called by onclick event
       
  2579 //  if (evt.getDetail()==2) {//getDetail unfortunately not in Firefox
       
  2580   var obj=evt.target;
       
  2581   var name = obj.parentNode.getAttribute("name");
       
  2582   var node = document.getElementById(name+"input");
       
  2583   node.style.display = (node.style.display == "none"?"":"none");
       
  2584   var node = document.getElementById(name+"button");
       
  2585   node.style.display = (node.style.display == "none"?"":"none");
       
  2586 //  }
       
  2587 }
       
  2588 
       
  2589 function showcode() {} // do nothing
       
  2590 
       
  2591 function setBorder(x) { border = x } //deprecate
       
  2592 
       
  2593 function initPicture(x_min,x_max,y_min,y_max) { // set up the graph
       
  2594 // usually called by axes() or noaxes(), but can be used directly
       
  2595  if (!initialized) {
       
  2596   setdefaults();
       
  2597   initialized = true;
       
  2598   if (x_min!=null) xmin = x_min;
       
  2599   if (x_max!=null) xmax = x_max;
       
  2600   if (y_min!=null) ymin = y_min;
       
  2601   if (y_max!=null) ymax = y_max;
       
  2602   if (xmin==null) xmin = defaultxmin;
       
  2603   if (xmax==null) xmax = defaultxmax;
       
  2604  if (typeof xmin != "number" || typeof xmax != "number" || xmin >= xmax) 
       
  2605    alert("Picture requires at least two numbers: xmin < xmax");
       
  2606  else if (y_max != null && (typeof y_min != "number" || 
       
  2607           typeof y_max != "number" || y_min >= y_max))
       
  2608    alert("initPicture(xmin,xmax,ymin,ymax) requires numbers ymin < ymax");
       
  2609  else {
       
  2610   if (width==null) {
       
  2611     width = picture.getAttribute("width");
       
  2612     if (width==null || width=="") width=defaultwidth;
       
  2613   }
       
  2614   picture.setAttribute("width",width);
       
  2615   if (height==null) { 
       
  2616     height = picture.getAttribute("height");
       
  2617     if (height==null || height=="") height=defaultheight;
       
  2618   }
       
  2619   picture.setAttribute("height",height);
       
  2620   xunitlength = (width-2*border)/(xmax-xmin);
       
  2621   yunitlength = xunitlength;
       
  2622 //alert(xmin+" "+xmax+" "+ymin+" "+ymax)
       
  2623   if (ymin==null) {
       
  2624     origin = [-xmin*xunitlength+border,height/2];
       
  2625     ymin = -(height-2*border)/(2*yunitlength);
       
  2626     ymax = -ymin;
       
  2627   } else {
       
  2628     if (ymax!=null) yunitlength = (height-2*border)/(ymax-ymin);
       
  2629     else ymax = (height-2*border)/yunitlength + ymin;
       
  2630     origin = [-xmin*xunitlength+border,-ymin*yunitlength+border];
       
  2631   }
       
  2632   if (isIE) {
       
  2633     if (picture.FULLSCREEN==undefined) {
       
  2634       setTimeout('drawPictures()',50);
       
  2635       throw "wait";
       
  2636     }
       
  2637     svgpicture = picture.getSVGDocument().getElementById("root");
       
  2638     if (svgpicture==null) {
       
  2639       setTimeout('drawPictures()',50);
       
  2640       throw "wait";
       
  2641     }
       
  2642     svgpicture = picture.getSVGDocument().getElementById("root");
       
  2643     while (svgpicture.childNodes.length>0) 
       
  2644       svgpicture.removeChild(svgpicture.lastChild); 
       
  2645     svgpicture.setAttribute("width",width);
       
  2646     svgpicture.setAttribute("height",height);
       
  2647     svgpicture.setAttribute("name",picture.getAttribute("id"));
       
  2648     doc = picture.getSVGDocument();
       
  2649     var nd = document.getElementById(picture.getAttribute("id")+"mml");
       
  2650     if (nd!=null) // clear out MathML layer
       
  2651       while (nd.childNodes.length>0) nd.removeChild(nd.lastChild); 
       
  2652   } else {
       
  2653     var qnode = document.createElementNS("http://www.w3.org/2000/svg","svg");
       
  2654     qnode.setAttribute("id",picture.getAttribute("id"));
       
  2655     qnode.setAttribute("name",picture.getAttribute("id"));
       
  2656     qnode.setAttribute("style","display:inline");
       
  2657     qnode.setAttribute("width",picture.getAttribute("width"));
       
  2658     qnode.setAttribute("height",picture.getAttribute("height"));
       
  2659     picturepos = findPos(picture);
       
  2660     qnode.setAttribute("left",picturepos[0]);
       
  2661     qnode.setAttribute("top",picturepos[1]);
       
  2662 //      qnode.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");
       
  2663     if (picture.parentNode!=null) {
       
  2664       picture.parentNode.replaceChild(qnode,picture);
       
  2665     } else {
       
  2666       svgpicture.parentNode.replaceChild(qnode,svgpicture);
       
  2667     }
       
  2668     svgpicture = qnode;
       
  2669     doc = document;
       
  2670   }
       
  2671   svgpicture.setAttribute("xunitlength",xunitlength);
       
  2672   svgpicture.setAttribute("yunitlength",yunitlength);
       
  2673   svgpicture.setAttribute("xmin",xmin);
       
  2674   svgpicture.setAttribute("xmax",xmax);
       
  2675   svgpicture.setAttribute("ymin",ymin);
       
  2676   svgpicture.setAttribute("ymax",ymax);
       
  2677   svgpicture.setAttribute("ox",origin[0]);
       
  2678   svgpicture.setAttribute("oy",origin[1]);
       
  2679   var node = myCreateElementSVG("rect");
       
  2680   node.setAttribute("x","0");
       
  2681   node.setAttribute("y","0");
       
  2682   node.setAttribute("width",width);
       
  2683   node.setAttribute("height",height);
       
  2684   node.setAttribute("style",backgroundstyle);
       
  2685   svgpicture.appendChild(node);
       
  2686   svgpicture.setAttribute("onmousemove","displayCoord(evt)");
       
  2687   svgpicture.setAttribute("onmouseout","removeCoord(evt)");
       
  2688   svgpicture.setAttribute("onclick","mClick(evt)");
       
  2689   node = myCreateElementSVG("text");
       
  2690   node.appendChild(doc.createTextNode(" "));
       
  2691   svgpicture.appendChild(node);
       
  2692   border = defaultborder;
       
  2693  }
       
  2694  }
       
  2695 }
       
  2696 
       
  2697 //////////////////////////user graphics commands start/////////////////////////
       
  2698 
       
  2699 function line(p,q,id,endpts) { // segment connecting points p,q (coordinates in units)
       
  2700   var node;
       
  2701   if (id!=null) node = doc.getElementById(id);
       
  2702   if (node==null) {
       
  2703     node = myCreateElementSVG("path");
       
  2704     node.setAttribute("id", id);
       
  2705     svgpicture.appendChild(node);
       
  2706   }
       
  2707   node.setAttribute("d","M"+(p[0]*xunitlength+origin[0])+","+
       
  2708     (height-p[1]*yunitlength-origin[1])+" "+
       
  2709     (q[0]*xunitlength+origin[0])+","+(height-q[1]*yunitlength-origin[1]));
       
  2710   node.setAttribute("stroke-width", strokewidth);
       
  2711   if (strokedasharray!=null) 
       
  2712     node.setAttribute("stroke-dasharray", strokedasharray);
       
  2713   node.setAttribute("stroke", stroke);
       
  2714   node.setAttribute("fill", fill);
       
  2715   node.setAttribute("stroke-opacity", strokeopacity);
       
  2716   node.setAttribute("fill-opacity", fillopacity);
       
  2717   if (marker=="dot" || marker=="arrowdot") {
       
  2718     ASdot(p,markersize,markerstroke,markerfill);
       
  2719     if (marker=="arrowdot") arrowhead(p,q);
       
  2720     ASdot(q,markersize,markerstroke,markerfill);
       
  2721   } else if (marker=="arrow") arrowhead(p,q);
       
  2722   if (endpts==null && endpoints!="") endpts = endpoints;
       
  2723   if (endpts!=null) {
       
  2724     if (endpts.indexOf("<-") != -1) arrowhead(q,p);
       
  2725     if (endpts.indexOf("o-") != -1) dot(p, "open");
       
  2726     if (endpts.indexOf("*-") != -1) dot(p, "closed");
       
  2727     if (endpts.indexOf("->") != -1) arrowhead(p,q);
       
  2728     if (endpts.indexOf("-o") != -1) dot(q, "open");
       
  2729     if (endpts.indexOf("-*") != -1) dot(q, "closed");
       
  2730   }
       
  2731 }
       
  2732 
       
  2733 function path(plist,id,c,endpts) {
       
  2734   if (c==null) c="";
       
  2735   var node, st, i;
       
  2736   if (id!=null) node = doc.getElementById(id);
       
  2737   if (node==null) {
       
  2738     node = myCreateElementSVG("path");
       
  2739     node.setAttribute("id", id);
       
  2740     svgpicture.appendChild(node);
       
  2741   }
       
  2742   if (typeof plist == "string") st = plist;
       
  2743   else {
       
  2744     st = "M";
       
  2745     st += (plist[0][0]*xunitlength+origin[0])+","+
       
  2746           (height-plist[0][1]*yunitlength-origin[1])+" "+c;
       
  2747     for (i=1; i<plist.length; i++)
       
  2748       st += (plist[i][0]*xunitlength+origin[0])+","+
       
  2749             (height-plist[i][1]*yunitlength-origin[1])+" ";
       
  2750   }
       
  2751   node.setAttribute("d", st);
       
  2752   node.setAttribute("stroke-width", strokewidth);
       
  2753   if (strokedasharray!=null) 
       
  2754     node.setAttribute("stroke-dasharray", strokedasharray);
       
  2755   node.setAttribute("stroke", stroke);
       
  2756   node.setAttribute("fill", fill);
       
  2757   node.setAttribute("stroke-opacity", strokeopacity);
       
  2758   node.setAttribute("fill-opacity", fillopacity);
       
  2759   if (marker=="dot" || marker=="arrowdot")
       
  2760     for (i=0; i<plist.length; i++)
       
  2761       if (c!="C" && c!="T" || i!=1 && i!=2)
       
  2762         ASdot(plist[i],markersize,markerstroke,markerfill);
       
  2763   if (endpts==null && endpoints!="") endpts = endpoints;
       
  2764   if (endpts!=null) {
       
  2765     if (endpts.indexOf("<-") != -1) arrowhead(plist[1],plist[0]);
       
  2766     if (endpts.indexOf("o-") != -1) dot(plist[0], "open");
       
  2767     if (endpts.indexOf("*-") != -1) dot(plist[0], "closed");
       
  2768     if (endpts.indexOf("->") != -1) arrowhead(plist[plist.length-2],plist[plist.length-1]);
       
  2769     if (endpts.indexOf("-o") != -1) dot(plist[plist.length-1], "open");
       
  2770     if (endpts.indexOf("-*") != -1) dot(plist[plist.length-1], "closed");
       
  2771   }
       
  2772 }
       
  2773 
       
  2774 function curve(plist,id,endpts) {
       
  2775   path(plist,id,"T",endpts);
       
  2776 }
       
  2777 
       
  2778 function vector(p,q,id) {
       
  2779   line(p,q,id,"","->");
       
  2780 }
       
  2781 
       
  2782 function circle(center,radius,id) { // coordinates in units
       
  2783   var node;
       
  2784   if (id!=null) node = doc.getElementById(id);
       
  2785   if (node==null) {
       
  2786     node = myCreateElementSVG("circle");
       
  2787     node.setAttribute("id", id);
       
  2788     svgpicture.appendChild(node);
       
  2789   }
       
  2790   node.setAttribute("cx",center[0]*xunitlength+origin[0]);
       
  2791   node.setAttribute("cy",height-center[1]*yunitlength-origin[1]);
       
  2792   node.setAttribute("r",radius*xunitlength);
       
  2793   node.setAttribute("stroke-width", strokewidth);
       
  2794   node.setAttribute("stroke", stroke);
       
  2795   node.setAttribute("fill", fill);
       
  2796   node.setAttribute("stroke-opacity", strokeopacity);
       
  2797   node.setAttribute("fill-opacity", fillopacity);
       
  2798 }
       
  2799 
       
  2800 function loop(p,d,id) { 
       
  2801 // d is a direction vector e.g. [1,0] means loop starts in that direction
       
  2802   if (d==null) d=[1,0];
       
  2803   path([p,[p[0]+d[0],p[1]+d[1]],[p[0]-d[1],p[1]+d[0]],p],id,"C");
       
  2804   if (marker=="arrow" || marker=="arrowdot") 
       
  2805     arrowhead([p[0]+Math.cos(1.4)*d[0]-Math.sin(1.4)*d[1],
       
  2806                p[1]+Math.sin(1.4)*d[0]+Math.cos(1.4)*d[1]],p);
       
  2807 }
       
  2808 
       
  2809 function arc(start,end,radius,id) { // coordinates in units
       
  2810   var node, v;
       
  2811 //alert([fill, stroke, origin, xunitlength, yunitlength, height])
       
  2812   if (id!=null) node = doc.getElementById(id);
       
  2813   if (radius==null) {
       
  2814     v=[end[0]-start[0],end[1]-start[1]];
       
  2815     radius = Math.sqrt(v[0]*v[0]+v[1]*v[1]);
       
  2816   }
       
  2817   if (node==null) {
       
  2818     node = myCreateElementSVG("path");
       
  2819     node.setAttribute("id", id);
       
  2820     svgpicture.appendChild(node);
       
  2821   }
       
  2822   node.setAttribute("d","M"+(start[0]*xunitlength+origin[0])+","+
       
  2823     (height-start[1]*yunitlength-origin[1])+" A"+radius*xunitlength+","+
       
  2824      radius*yunitlength+" 0 0,0 "+(end[0]*xunitlength+origin[0])+","+
       
  2825     (height-end[1]*yunitlength-origin[1]));
       
  2826   node.setAttribute("stroke-width", strokewidth);
       
  2827   node.setAttribute("stroke", stroke);
       
  2828   node.setAttribute("fill", fill);
       
  2829   node.setAttribute("stroke-opacity", strokeopacity);
       
  2830   node.setAttribute("fill-opacity", fillopacity);
       
  2831   if (marker=="arrow" || marker=="arrowdot") {
       
  2832     u = [(end[1]-start[1])/4,(start[0]-end[0])/4];
       
  2833     v = [(end[0]-start[0])/2,(end[1]-start[1])/2];
       
  2834 //alert([u,v])
       
  2835     v = [start[0]+v[0]+u[0],start[1]+v[1]+u[1]];
       
  2836   } else v=[start[0],start[1]];
       
  2837   if (marker=="dot" || marker=="arrowdot") {
       
  2838     ASdot(start,markersize,markerstroke,markerfill);
       
  2839     if (marker=="arrowdot") arrowhead(v,end);
       
  2840     ASdot(end,markersize,markerstroke,markerfill);
       
  2841   } else if (marker=="arrow") arrowhead(v,end);
       
  2842 }
       
  2843 
       
  2844 function sector(center,start,end,id) { // center,start,end should be isoceles
       
  2845   var rx = start[0]-center[0], ry = start[1]-center[1];
       
  2846   arc(start,end,Math.sqrt(rx*rx+ry*ry),id+"arc");
       
  2847   path([end,center,start],id+"path");
       
  2848 }
       
  2849 
       
  2850 function ellipse(center,rx,ry,id) { // coordinates in units
       
  2851   var node;
       
  2852   if (id!=null) node = doc.getElementById(id);
       
  2853   if (node==null) {
       
  2854     node = myCreateElementSVG("ellipse");
       
  2855     node.setAttribute("id", id);
       
  2856     svgpicture.appendChild(node);
       
  2857   }
       
  2858   node.setAttribute("cx",center[0]*xunitlength+origin[0]);
       
  2859   node.setAttribute("cy",height-center[1]*yunitlength-origin[1]);
       
  2860   node.setAttribute("rx",rx*xunitlength);
       
  2861   node.setAttribute("ry",ry*yunitlength);
       
  2862   node.setAttribute("stroke-width", strokewidth);
       
  2863   node.setAttribute("stroke", stroke);
       
  2864   node.setAttribute("fill", fill);
       
  2865   node.setAttribute("stroke-opacity", strokeopacity);
       
  2866   node.setAttribute("fill-opacity", fillopacity);
       
  2867 }
       
  2868 
       
  2869 function triangle(p,q,r,id) {
       
  2870   path([p,q,r,p],id)
       
  2871 }
       
  2872 
       
  2873 function rect(p,q,id,rx,ry) { // opposite corners in units, rounded by radii
       
  2874   var node;
       
  2875   if (id!=null) node = doc.getElementById(id);
       
  2876   if (node==null) {
       
  2877     node = myCreateElementSVG("rect");
       
  2878     node.setAttribute("id", id);
       
  2879     svgpicture.appendChild(node);
       
  2880   }
       
  2881   node.setAttribute("x",p[0]*xunitlength+origin[0]);
       
  2882   node.setAttribute("y",height-q[1]*yunitlength-origin[1]);
       
  2883   node.setAttribute("width",(q[0]-p[0])*xunitlength);
       
  2884   node.setAttribute("height",(q[1]-p[1])*yunitlength);
       
  2885   if (rx!=null) node.setAttribute("rx",rx*xunitlength);
       
  2886   if (ry!=null) node.setAttribute("ry",ry*yunitlength);
       
  2887   node.setAttribute("stroke-width", strokewidth);
       
  2888   node.setAttribute("stroke", stroke);
       
  2889   node.setAttribute("fill", fill);
       
  2890   node.setAttribute("stroke-opacity", strokeopacity);
       
  2891   node.setAttribute("fill-opacity", fillopacity);
       
  2892 }
       
  2893 
       
  2894 function text(p,st,pos,id,fontsty) {
       
  2895   var dnode, node, dx = 0, dy = fontsize/3;
       
  2896   if (/(`|\$)/.test(st)) {  // layer for ASCIIMathML and LaTeXMathML
       
  2897     dnode = document.getElementById(svgpicture.getAttribute("name")+"mml");
       
  2898     if (dnode!=null) {
       
  2899       if (id!=null) node = document.getElementById(id);
       
  2900       if (node==null) {
       
  2901 //alert(dnode.childNodes.length)
       
  2902         node = myCreateElementXHTML("div");
       
  2903         node.setAttribute("id", id);
       
  2904         node.style.position = "absolute";
       
  2905         dnode.appendChild(node);
       
  2906       }
       
  2907       while (node.childNodes.length>0) node.removeChild(node.lastChild); 
       
  2908       node.appendChild(document.createTextNode(st));
       
  2909 //      node.lastChild.nodeValue = st;
       
  2910       node.style.left = ""+(p[0]*xunitlength+origin[0])+"px";
       
  2911       node.style.top = ""+(height-p[1]*yunitlength-origin[1])+"px";
       
  2912       if (/`/.test(st)) AMprocessNode(node); else LMprocessNode(node);
       
  2913       dx = -node.offsetWidth/2;
       
  2914       dy = -node.offsetHeight/2;
       
  2915       if (pos!=null) {
       
  2916         if (/above/.test(pos)) dy = -node.offsetHeight;
       
  2917         if (/below/.test(pos)) dy = 0;
       
  2918         if (/right/.test(pos)) dx = 0;
       
  2919         if ( /left/.test(pos)) dx = -node.offsetWidth;
       
  2920       }
       
  2921       node.style.left = ""+(p[0]*xunitlength+origin[0]+dx)+"px";
       
  2922       node.style.top = ""+(height-p[1]*yunitlength-origin[1]+dy)+"px";
       
  2923     }
       
  2924     return p;
       
  2925   }
       
  2926   var textanchor = "middle";  // regular text goes into SVG
       
  2927   if (pos!=null) {
       
  2928     if (/above/.test(pos)) dy = -fontsize/2;
       
  2929     if (/below/.test(pos)) dy = fontsize-0;
       
  2930     if (/right/.test(pos)) {textanchor = "start"; dx = fontsize/4;}
       
  2931     if ( /left/.test(pos)) {textanchor = "end";  dx = -fontsize/4;}
       
  2932   }
       
  2933   if (id!=null) node = doc.getElementById(id);
       
  2934   if (node==null) {
       
  2935     node = myCreateElementSVG("text");
       
  2936     node.setAttribute("id", id);
       
  2937     svgpicture.appendChild(node);
       
  2938     node.appendChild(doc.createTextNode(st));
       
  2939   }
       
  2940   while (node.childNodes.length>1) node.removeChild(node.lastChild); 
       
  2941 //  node.appendChild(document.createTextNode("\xA0"+st+"\xA0"));
       
  2942 //alert("here");
       
  2943   node.lastChild.nodeValue = "\xA0"+st+"\xA0";
       
  2944   node.setAttribute("x",p[0]*xunitlength+origin[0]+dx);
       
  2945   node.setAttribute("y",height-p[1]*yunitlength-origin[1]+dy);
       
  2946   node.setAttribute("font-style",(fontsty!=null?fontsty:
       
  2947     (st.search(/^[a-zA-Z]$/)!=-1?"italic":fontstyle)));
       
  2948   node.setAttribute("font-family",fontfamily);
       
  2949   node.setAttribute("font-size",fontsize);
       
  2950   node.setAttribute("font-weight",fontweight);
       
  2951   node.setAttribute("text-anchor",textanchor);
       
  2952   if (fontstroke!="none") node.setAttribute("stroke",fontstroke);
       
  2953   if (fontfill!="none") node.setAttribute("fill",fontfill);
       
  2954   return p;
       
  2955 }
       
  2956 
       
  2957 function mtext(p,st,pos,fontsty) { // method for updating text on an svg
       
  2958 // "this" is the text object or the svgpicture object
       
  2959   var textanchor = "middle";
       
  2960   var dx = 0; var dy = fontsize/3;
       
  2961   if (pos!=null) {
       
  2962     if (pos.slice(0,5)=="above") dy = -fontsize/2;
       
  2963     if (pos.slice(0,5)=="below") dy = fontsize-0;
       
  2964     if (pos.slice(0,5)=="right" || pos.slice(5,10)=="right") {
       
  2965       textanchor = "start";
       
  2966       dx = fontsize/2;
       
  2967     }
       
  2968     if (pos.slice(0,4)=="left" || pos.slice(5,9)=="left") {
       
  2969       textanchor = "end";
       
  2970       dx = -fontsize/2;
       
  2971     }
       
  2972   }
       
  2973   var node = this;
       
  2974   if (this.nodeName=="svg") {
       
  2975     node = myCreateElementSVG("text");
       
  2976     this.appendChild(node);
       
  2977     node.appendChild(doc.createTextNode(st));
       
  2978   }
       
  2979   node.lastChild.nodeValue = st;
       
  2980   node.setAttribute("x",p[0]+dx);
       
  2981   node.setAttribute("y",p[1]+dy);
       
  2982   node.setAttribute("font-style",(fontsty!=null?fontsty:fontstyle));
       
  2983   node.setAttribute("font-family",fontfamily);
       
  2984   node.setAttribute("font-size",fontsize);
       
  2985   node.setAttribute("font-weight",fontweight);
       
  2986   node.setAttribute("text-anchor",textanchor);
       
  2987   if (fontstroke!="none") node.setAttribute("stroke",fontstroke);
       
  2988   if (fontfill!="none") node.setAttribute("fill",fontfill);
       
  2989 }
       
  2990 
       
  2991 function image(imgurl,p,w,h,id) { // not working yet
       
  2992   var node;
       
  2993   if (id!=null) node = doc.getElementById(id);
       
  2994   if (node==null) {
       
  2995     node = myCreateElementSVG("image");
       
  2996     node.setAttribute("id", id);
       
  2997     svgpicture.appendChild(node);
       
  2998   }
       
  2999   node.setAttribute("x",p[0]*xunitlength+origin[0]);
       
  3000   node.setAttribute("y",height-p[1]*yunitlength-origin[1]);
       
  3001   node.setAttribute("width",w);
       
  3002   node.setAttribute("height",h);
       
  3003   node.setAttribute("xlink:href", imgurl);
       
  3004 }
       
  3005 
       
  3006 function ASdot(center,radius,s,f) { // coordinates in units, radius in pixel
       
  3007   if (s==null) s = stroke; if (f==null) f = fill;
       
  3008   var node = myCreateElementSVG("circle");
       
  3009   node.setAttribute("cx",center[0]*xunitlength+origin[0]);
       
  3010   node.setAttribute("cy",height-center[1]*yunitlength-origin[1]);
       
  3011   node.setAttribute("r",radius);
       
  3012   node.setAttribute("stroke-width", strokewidth);
       
  3013   node.setAttribute("stroke", s);
       
  3014   node.setAttribute("fill", f);
       
  3015   svgpicture.appendChild(node);
       
  3016 }
       
  3017 
       
  3018 function dot(center, typ, label, pos, id) {
       
  3019   var node;
       
  3020   var cx = center[0]*xunitlength+origin[0];
       
  3021   var cy = height-center[1]*yunitlength-origin[1];
       
  3022   if (id!=null) node = doc.getElementById(id);
       
  3023   if (typ=="+" || typ=="-" || typ=="|") {
       
  3024     if (node==null) {
       
  3025       node = myCreateElementSVG("path");
       
  3026       node.setAttribute("id", id);
       
  3027       svgpicture.appendChild(node);
       
  3028     }
       
  3029     if (typ=="+") {
       
  3030       node.setAttribute("d",
       
  3031         " M "+(cx-ticklength)+" "+cy+" L "+(cx+ticklength)+" "+cy+
       
  3032         " M "+cx+" "+(cy-ticklength)+" L "+cx+" "+(cy+ticklength));
       
  3033       node.setAttribute("stroke-width", .5);
       
  3034       node.setAttribute("stroke", axesstroke);
       
  3035     } else {
       
  3036       if (typ=="-") node.setAttribute("d",
       
  3037         " M "+(cx-ticklength)+" "+cy+" L "+(cx+ticklength)+" "+cy);
       
  3038       else node.setAttribute("d",
       
  3039         " M "+cx+" "+(cy-ticklength)+" L "+cx+" "+(cy+ticklength));
       
  3040       node.setAttribute("stroke-width", strokewidth);
       
  3041       node.setAttribute("stroke", stroke);
       
  3042     }
       
  3043   } else {
       
  3044     if (node==null) {
       
  3045       node = myCreateElementSVG("circle");
       
  3046       node.setAttribute("id", id);
       
  3047       svgpicture.appendChild(node);
       
  3048     }
       
  3049     node.setAttribute("cx",cx);
       
  3050     node.setAttribute("cy",cy);
       
  3051     node.setAttribute("r",dotradius);
       
  3052     node.setAttribute("stroke-width", strokewidth);
       
  3053     node.setAttribute("stroke", stroke);
       
  3054     node.setAttribute("fill", (typ=="open"?"white":
       
  3055                               (typ=="closed"?stroke:markerfill)));
       
  3056   }
       
  3057   if (label!=null) 
       
  3058     text(center,label,(pos==null?"below":pos),(id==null?id:id+"label"))
       
  3059 }
       
  3060 
       
  3061 point = dot; //alternative name
       
  3062 
       
  3063 function arrowhead(p,q) { // draw arrowhead at q (in units) add size param
       
  3064   var up;
       
  3065   var v = [p[0]*xunitlength+origin[0],height-p[1]*yunitlength-origin[1]];
       
  3066   var w = [q[0]*xunitlength+origin[0],height-q[1]*yunitlength-origin[1]];
       
  3067   var u = [w[0]-v[0],w[1]-v[1]];
       
  3068   var d = Math.sqrt(u[0]*u[0]+u[1]*u[1]);
       
  3069   if (d > 0.00000001) {
       
  3070     u = [u[0]/d, u[1]/d];
       
  3071     up = [-u[1],u[0]];
       
  3072     var node = myCreateElementSVG("path");
       
  3073     node.setAttribute("d","M "+(w[0]-15*u[0]-4*up[0])+" "+
       
  3074       (w[1]-15*u[1]-4*up[1])+" L "+(w[0]-3*u[0])+" "+(w[1]-3*u[1])+" L "+
       
  3075       (w[0]-15*u[0]+4*up[0])+" "+(w[1]-15*u[1]+4*up[1])+" z");
       
  3076     node.setAttribute("stroke-width", markerstrokewidth);
       
  3077     node.setAttribute("stroke", stroke); /*was markerstroke*/
       
  3078     node.setAttribute("fill", stroke); /*was arrowfill*/
       
  3079     node.setAttribute("stroke-opacity", strokeopacity);
       
  3080     node.setAttribute("fill-opacity", fillopacity);
       
  3081     svgpicture.appendChild(node);    
       
  3082   }
       
  3083 }
       
  3084 
       
  3085 function chopZ(st) {
       
  3086   var k = st.indexOf(".");
       
  3087   if (k==-1) return st;
       
  3088   for (var i=st.length-1; i>k && st.charAt(i)=="0"; i--);
       
  3089   if (i==k) i--;
       
  3090   return st.slice(0,i+1);
       
  3091 }
       
  3092 
       
  3093 function grid(dx,dy) { // for backward compatibility
       
  3094   axes(dx,dy,null,dx,dy)
       
  3095 }
       
  3096 
       
  3097 function noaxes() {
       
  3098   if (!initialized) initPicture();
       
  3099 }
       
  3100 
       
  3101 function axes(dx,dy,labels,gdx,gdy) {
       
  3102 //xscl=x is equivalent to xtick=x; xgrid=x; labels=true;
       
  3103   var x, y, ldx, ldy, lx, ly, lxp, lyp, pnode, st;
       
  3104   if (!initialized) initPicture();
       
  3105   if (typeof dx=="string") { labels = dx; dx = null; }
       
  3106   if (typeof dy=="string") { gdx = dy; dy = null; }
       
  3107   if (xscl!=null) {dx = xscl; gdx = xscl; labels = dx}
       
  3108   if (yscl!=null) {dy = yscl; gdy = yscl}
       
  3109   if (xtick!=null) {dx = xtick}
       
  3110   if (ytick!=null) {dy = ytick}
       
  3111   dx = (dx==null?xunitlength:dx*xunitlength);
       
  3112   dy = (dy==null?dx:dy*yunitlength);
       
  3113   fontsize = Math.min(dx/2,dy/2,16); //alert(fontsize)
       
  3114   ticklength = fontsize/4;
       
  3115   if (xgrid!=null) gdx = xgrid;
       
  3116   if (ygrid!=null) gdy = ygrid;
       
  3117   if (gdx!=null) {
       
  3118     gdx = (typeof gdx=="string"?dx:gdx*xunitlength);
       
  3119     gdy = (gdy==null?dy:gdy*yunitlength);
       
  3120     pnode = myCreateElementSVG("path");
       
  3121     st="";
       
  3122     for (x = origin[0]; x<width; x = x+gdx)
       
  3123       st += " M"+x+",0"+" "+x+","+height;
       
  3124     for (x = origin[0]-gdx; x>0; x = x-gdx)
       
  3125       st += " M"+x+",0"+" "+x+","+height;
       
  3126     for (y = height-origin[1]; y<height; y = y+gdy)
       
  3127       st += " M0,"+y+" "+width+","+y;
       
  3128     for (y = height-origin[1]-gdy; y>0; y = y-gdy)
       
  3129       st += " M0,"+y+" "+width+","+y;
       
  3130     pnode.setAttribute("d",st);
       
  3131     pnode.setAttribute("stroke-width", .5);
       
  3132     pnode.setAttribute("stroke", gridstroke);
       
  3133     pnode.setAttribute("fill", fill);
       
  3134     svgpicture.appendChild(pnode);
       
  3135   }
       
  3136   pnode = myCreateElementSVG("path");
       
  3137   st="M0,"+(height-origin[1])+" "+width+","+
       
  3138     (height-origin[1])+" M"+origin[0]+",0 "+origin[0]+","+height;
       
  3139   for (x = origin[0]+dx; x<width; x = x+dx)
       
  3140     st += " M"+x+","+(height-origin[1]+ticklength)+" "+x+","+
       
  3141            (height-origin[1]-ticklength);
       
  3142   for (x = origin[0]-dx; x>0; x = x-dx)
       
  3143     st += " M"+x+","+(height-origin[1]+ticklength)+" "+x+","+
       
  3144            (height-origin[1]-ticklength);
       
  3145   for (y = height-origin[1]+dy; y<height; y = y+dy)
       
  3146     st += " M"+(origin[0]+ticklength)+","+y+" "+(origin[0]-ticklength)+","+y;
       
  3147   for (y = height-origin[1]-dy; y>0; y = y-dy)
       
  3148     st += " M"+(origin[0]+ticklength)+","+y+" "+(origin[0]-ticklength)+","+y;
       
  3149   if (labels!=null) with (Math) {
       
  3150     ldx = dx/xunitlength;
       
  3151     ldy = dy/yunitlength;
       
  3152     lx = (xmin>0 || xmax<0?xmin:0);
       
  3153     ly = (ymin>0 || ymax<0?ymin:0);
       
  3154     lxp = (ly==0?"below":"above");
       
  3155     lyp = (lx==0?"left":"right");
       
  3156     var ddx = floor(1.1-log(ldx)/log(10))+1;
       
  3157     var ddy = floor(1.1-log(ldy)/log(10))+1;
       
  3158     for (x = ldx; x<=xmax; x = x+ldx)
       
  3159       text([x,ly],chopZ(x.toFixed(ddx)),lxp);
       
  3160     for (x = -ldx; xmin<=x; x = x-ldx)
       
  3161       text([x,ly],chopZ(x.toFixed(ddx)),lxp);
       
  3162     for (y = ldy; y<=ymax; y = y+ldy)
       
  3163       text([lx,y],chopZ(y.toFixed(ddy)),lyp);
       
  3164     for (y = -ldy; ymin<=y; y = y-ldy)
       
  3165       text([lx,y],chopZ(y.toFixed(ddy)),lyp);
       
  3166   }
       
  3167   fontsize = defaultfontsize;
       
  3168   pnode.setAttribute("d",st);
       
  3169   pnode.setAttribute("stroke-width", .5);
       
  3170   pnode.setAttribute("stroke", axesstroke);
       
  3171   pnode.setAttribute("fill", fill);
       
  3172   pnode.setAttribute("stroke-opacity", strokeopacity);
       
  3173   pnode.setAttribute("fill-opacity", fillopacity);
       
  3174   svgpicture.appendChild(pnode);
       
  3175 }
       
  3176 
       
  3177 function mathjs(st) {
       
  3178   //translate a math formula to js function notation
       
  3179   // a^b --> pow(a,b)
       
  3180   // na --> n*a
       
  3181   // (...)d --> (...)*d
       
  3182   // n! --> factorial(n)
       
  3183   // sin^-1 --> arcsin etc.
       
  3184   //while ^ in string, find term on left and right
       
  3185   //slice and concat new formula string
       
  3186   st = st.replace(/\s/g,"");
       
  3187   if (st.indexOf("^-1")!=-1) {
       
  3188     st = st.replace(/sin\^-1/g,"arcsin");
       
  3189     st = st.replace(/cos\^-1/g,"arccos");
       
  3190     st = st.replace(/tan\^-1/g,"arctan");
       
  3191     st = st.replace(/sec\^-1/g,"arcsec");
       
  3192     st = st.replace(/csc\^-1/g,"arccsc");
       
  3193     st = st.replace(/cot\^-1/g,"arccot");
       
  3194     st = st.replace(/sinh\^-1/g,"arcsinh");
       
  3195     st = st.replace(/cosh\^-1/g,"arccosh");
       
  3196     st = st.replace(/tanh\^-1/g,"arctanh");
       
  3197     st = st.replace(/sech\^-1/g,"arcsech");
       
  3198     st = st.replace(/csch\^-1/g,"arccsch");
       
  3199     st = st.replace(/coth\^-1/g,"arccoth");
       
  3200   }
       
  3201   st = st.replace(/^e$/g,"(Math.E)");
       
  3202   st = st.replace(/^e([^a-zA-Z])/g,"(Math.E)$1");
       
  3203   st = st.replace(/([^a-zA-Z])e/g,"$1(Math.E)");
       
  3204 //  st = st.replace(/([^a-zA-Z])e([^a-zA-Z])/g,"$1(Math.E)$2");
       
  3205   st = st.replace(/([0-9])([\(a-zA-Z])/g,"$1*$2");
       
  3206   st = st.replace(/\)([\(0-9a-zA-Z])/g,"\)*$1");
       
  3207   var i,j,k, ch, nested;
       
  3208   while ((i=st.indexOf("^"))!=-1) {
       
  3209     //find left argument
       
  3210     if (i==0) return "Error: missing argument";
       
  3211     j = i-1;
       
  3212     ch = st.charAt(j);
       
  3213     if (ch>="0" && ch<="9") {// look for (decimal) number
       
  3214       j--;
       
  3215       while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
       
  3216       if (ch==".") {
       
  3217         j--;
       
  3218         while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
       
  3219       }
       
  3220     } else if (ch==")") {// look for matching opening bracket and function name
       
  3221       nested = 1;
       
  3222       j--;
       
  3223       while (j>=0 && nested>0) {
       
  3224         ch = st.charAt(j);
       
  3225         if (ch=="(") nested--;
       
  3226         else if (ch==")") nested++;
       
  3227         j--;
       
  3228       }
       
  3229       while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
       
  3230         j--;
       
  3231     } else if (ch>="a" && ch<="z" || ch>="A" && ch<="Z") {// look for variable
       
  3232       j--;
       
  3233       while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
       
  3234         j--;
       
  3235     } else { 
       
  3236       return "Error: incorrect syntax in "+st+" at position "+j;
       
  3237     }
       
  3238     //find right argument
       
  3239     if (i==st.length-1) return "Error: missing argument";
       
  3240     k = i+1;
       
  3241     ch = st.charAt(k);
       
  3242     if (ch>="0" && ch<="9" || ch=="-") {// look for signed (decimal) number
       
  3243       k++;
       
  3244       while (k<st.length && (ch=st.charAt(k))>="0" && ch<="9") k++;
       
  3245       if (ch==".") {
       
  3246         k++;
       
  3247         while (k<st.length && (ch=st.charAt(k))>="0" && ch<="9") k++;
       
  3248       }
       
  3249     } else if (ch=="(") {// look for matching closing bracket and function name
       
  3250       nested = 1;
       
  3251       k++;
       
  3252       while (k<st.length && nested>0) {
       
  3253         ch = st.charAt(k);
       
  3254         if (ch=="(") nested++;
       
  3255         else if (ch==")") nested--;
       
  3256         k++;
       
  3257       }
       
  3258     } else if (ch>="a" && ch<="z" || ch>="A" && ch<="Z") {// look for variable
       
  3259       k++;
       
  3260       while (k<st.length && (ch=st.charAt(k))>="a" && ch<="z" ||
       
  3261                ch>="A" && ch<="Z") k++;
       
  3262     } else { 
       
  3263       return "Error: incorrect syntax in "+st+" at position "+k;
       
  3264     }
       
  3265     st = st.slice(0,j+1)+"Math.pow("+st.slice(j+1,i)+","+st.slice(i+1,k)+")"+
       
  3266            st.slice(k);
       
  3267   }
       
  3268   while ((i=st.indexOf("!"))!=-1) {
       
  3269     //find left argument
       
  3270     if (i==0) return "Error: missing argument";
       
  3271     j = i-1;
       
  3272     ch = st.charAt(j);
       
  3273     if (ch>="0" && ch<="9") {// look for (decimal) number
       
  3274       j--;
       
  3275       while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
       
  3276       if (ch==".") {
       
  3277         j--;
       
  3278         while (j>=0 && (ch=st.charAt(j))>="0" && ch<="9") j--;
       
  3279       }
       
  3280     } else if (ch==")") {// look for matching opening bracket and function name
       
  3281       nested = 1;
       
  3282       j--;
       
  3283       while (j>=0 && nested>0) {
       
  3284         ch = st.charAt(j);
       
  3285         if (ch=="(") nested--;
       
  3286         else if (ch==")") nested++;
       
  3287         j--;
       
  3288       }
       
  3289       while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
       
  3290         j--;
       
  3291     } else if (ch>="a" && ch<="z" || ch>="A" && ch<="Z") {// look for variable
       
  3292       j--;
       
  3293       while (j>=0 && (ch=st.charAt(j))>="a" && ch<="z" || ch>="A" && ch<="Z")
       
  3294         j--;
       
  3295     } else { 
       
  3296       return "Error: incorrect syntax in "+st+" at position "+j;
       
  3297     }
       
  3298     st = st.slice(0,j+1)+"factorial("+st.slice(j+1,i)+")"+st.slice(i+1);
       
  3299   }
       
  3300   return st;
       
  3301 }
       
  3302 
       
  3303 function plot(fun,x_min,x_max,points,id,endpts) {
       
  3304   var pth = [];
       
  3305   var f = function(x) { return x }, g = fun;
       
  3306   var name = null;
       
  3307   if (typeof fun=="string") 
       
  3308     eval("g = function(x){ with(Math) return "+mathjs(fun)+" }");
       
  3309   else if (typeof fun=="object") {
       
  3310     eval("f = function(t){ with(Math) return "+mathjs(fun[0])+" }");
       
  3311     eval("g = function(t){ with(Math) return "+mathjs(fun[1])+" }");
       
  3312   }
       
  3313   if (typeof x_min=="string") { name = x_min; x_min = xmin }
       
  3314   else name = id;
       
  3315   var min = (x_min==null?xmin:x_min);
       
  3316   var max = (x_max==null?xmax:x_max);
       
  3317   var inc = max-min-0.000001*(max-min);
       
  3318   inc = (points==null?inc/200:inc/points);
       
  3319   var gt;
       
  3320 //alert(typeof g(min))
       
  3321   for (var t = min; t <= max; t += inc) {
       
  3322     gt = g(t);
       
  3323     if (!(isNaN(gt)||Math.abs(gt)=="Infinity")) pth[pth.length] = [f(t), gt];
       
  3324   }
       
  3325   path(pth,name,null,endpts);
       
  3326   return p;
       
  3327 }
       
  3328 
       
  3329 // make polar plot
       
  3330 
       
  3331 // make Riemann sums
       
  3332 
       
  3333 function slopefield(fun,dx,dy) {
       
  3334   var g = fun;
       
  3335   if (typeof fun=="string") 
       
  3336     eval("g = function(x,y){ with(Math) return "+mathjs(fun)+" }");
       
  3337   var gxy,x,y,u,v,dz;
       
  3338   if (dx==null) dx=1;
       
  3339   if (dy==null) dy=1;
       
  3340   dz = Math.sqrt(dx*dx+dy*dy)/6;
       
  3341   var x_min = Math.ceil(xmin/dx);
       
  3342   var y_min = Math.ceil(ymin/dy);
       
  3343   for (x = x_min; x <= xmax; x += dx)
       
  3344     for (y = y_min; y <= ymax; y += dy) {
       
  3345       gxy = g(x,y);
       
  3346       if (!isNaN(gxy)) {
       
  3347         if (Math.abs(gxy)=="Infinity") {u = 0; v = dz;}
       
  3348         else {u = dz/Math.sqrt(1+gxy*gxy); v = gxy*u;}
       
  3349         line([x-u,y-v],[x+u,y+v]);
       
  3350       }
       
  3351     }
       
  3352 }
       
  3353 
       
  3354 ///////////////////////user graphics commands end here/////////////////////////
       
  3355 
       
  3356 function show_props(obj) {
       
  3357   var result = "";
       
  3358   for (var i=0; i< obj.childNodes.length; i++)
       
  3359     result += obj.childNodes.item(i) + "\n";
       
  3360   return result;
       
  3361 }
       
  3362 
       
  3363 function displayCoord(evt) {
       
  3364   if (showcoordinates) {
       
  3365 //alert(show_props(evt.target.parentNode))
       
  3366     var svgroot = evt.target.parentNode;
       
  3367     var nl = svgroot.childNodes;
       
  3368     for (var i=0; i<nl.length && nl.item(i).nodeName!="text"; i++);
       
  3369     var cnode = nl.item(i);
       
  3370     cnode.mtext = mtext;
       
  3371     cnode.mtext([svgroot.getAttribute("width")-0,svgroot.getAttribute("height")-0],"("+getX(evt).toFixed(2)+", "+getY(evt).toFixed(2)+")", "aboveleft", "");
       
  3372   }
       
  3373 }
       
  3374 
       
  3375 function removeCoord(evt) {
       
  3376     var svgroot = evt.target.parentNode;
       
  3377     var nl = svgroot.childNodes;
       
  3378     for (var i=0; i<nl.length && nl.item(i).nodeName!="text"; i++);
       
  3379     var cnode = nl.item(i);
       
  3380     cnode.mtext = mtext;
       
  3381     cnode.mtext([svgroot.getAttribute("width")-0,svgroot.getAttribute("height")-0],"", "aboveleft", "");
       
  3382 }
       
  3383 
       
  3384 function initASCIIMathCalculators(li) {
       
  3385   var i;
       
  3386   for (i=0; i<li.length; i++) {
       
  3387     li[i].innerHTML = calcstr;
       
  3388     AMprocessNode(li[i]);
       
  3389   }
       
  3390   li = document.getElementsByTagName("textarea");
       
  3391   var st;
       
  3392   for (i=0; i<li.length; i++) {
       
  3393     st = li[i].getAttribute("onkeyup");
       
  3394     if (st!=null) eval(String(st).replace(/function anonymous\(\)/,""));
       
  3395   }
       
  3396 }
       
  3397 
       
  3398 function calculate(inputId,outputId) {
       
  3399   var str = document.getElementById(inputId).value;
       
  3400   var err = "";
       
  3401   var ind = str.lastIndexOf("\n");
       
  3402   if (ind==str.length-1) str = str.slice(0,ind);
       
  3403   str = str.slice(str.lastIndexOf("\n")+1);
       
  3404   try {
       
  3405     var res = eval(mathjs(str));
       
  3406   } catch(e) {
       
  3407     err = "syntax incomplete";
       
  3408   }
       
  3409   if (!isNaN(res) && res!="Infinity") 
       
  3410     str = "`"+str+" =` "+(Math.abs(res-Math.round(res*1000000)/1000000)<1e-15?Math.round(res*1000000)/1000000:res)+err; 
       
  3411   else if (str!="") str = "`"+str+"` = undefined"; //debug:+mathjs(str);
       
  3412   var outnode = document.getElementById(outputId);
       
  3413   var n = outnode.childNodes.length;
       
  3414   for (var i=0; i<n; i++)
       
  3415     outnode.removeChild(outnode.firstChild);
       
  3416   outnode.appendChild(document.createTextNode(str));
       
  3417   AMprocessNode(outnode);
       
  3418 }
       
  3419 
       
  3420 function append(st){
       
  3421   document.getElementById('in').value+=st;
       
  3422   calculate('in','out');
       
  3423   document.getElementById('in').scrollTop = 1000;
       
  3424   document.getElementById('in').focus();
       
  3425 }
       
  3426 
       
  3427 function clearTextArea(){
       
  3428   document.getElementById('in').value="";
       
  3429   calculate('in','out');
       
  3430   document.getElementById('in').focus();
       
  3431 }
       
  3432 
       
  3433 var calcstr = "<table align=\"center\">\n<tr><th>\nASCIIMath Scientific Calculator\n</th></tr>\n<tr><td>\nClick in the box to use your keyboard or use the buttons\n</td></tr>\n<tr><td>\n<textarea id=\"in\" rows=\"3\" cols=\"40\" onkeyup=\"calculate('in','out')\"></textarea></td></tr>\n<tr><td height=\"50\">Result: &nbsp; &nbsp; <span id=\"out\"></span></td></tr>\n</table>\n<table align=\"center\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody align=\"center\">\n<tr>\n<td colspan=\"4\">\n<button onclick=\"append('sin^-1(')\"><font size=2>`sin^-1`</font></button><button onclick=\"append('cos^-1(')\"><font size=2>`cos^-1`</font></button><button onclick=\"append('tan^-1(')\"><font size=2>`tan^-1`</font></button></td>\n<td><button onclick=\"clearTextArea()\">&nbsp;`C`&nbsp;</button></td>\n\n</tr>\n<tr>\n<td><button onclick=\"append('pi')\">&nbsp;`pi` &nbsp;</button></td>\n<td><button onclick=\"append('sin(')\">&nbsp;`sin`</button></td>\n<td><button onclick=\"append('cos(')\">&nbsp;`cos`</button></td>\n<td><button onclick=\"append('tan(')\">&nbsp;`tan`</button></td>\n<td><button onclick=\"append('^')\">`x^y`</button></td>\n</tr>\n<tr>\n<td><button onclick=\"append('!')\">&nbsp; `!` &nbsp;</button></td>\n\n<td><button onclick=\"append('(')\"><font size=2>&nbsp;&nbsp;`(`&nbsp;&nbsp;</font></button></td>\n<td><button onclick=\"append(')')\"><font size=2>&nbsp;&nbsp;`)`&nbsp;&nbsp;</font></button></td>\n<td><button onclick=\"append('sqrt(')\"><font size=2>`sqrt({::}^\ )`</font></button></td>\n<td><button onclick=\"append('/')\">&nbsp;`-:\ `</button></td>\n</tr>\n<tr>\n<td><button onclick=\"append('log(')\">`log`</button></td>\n<td><button onclick=\"append('7')\">&nbsp; `7` &nbsp;</button></td>\n<td><button onclick=\"append('8')\">&nbsp; `8` &nbsp;</button></td>\n\n<td><button onclick=\"append('9')\">&nbsp; `9` &nbsp;</button></td>\n<td><button onclick=\"append('*')\">&nbsp;`times`&nbsp;</button></td>\n</tr>\n<tr>\n<td><button onclick=\"append('ln(')\">&nbsp;`ln`&nbsp;</button></td>\n<td><button onclick=\"append('4')\">&nbsp; `4` &nbsp;</button></td>\n<td><button onclick=\"append('5')\">&nbsp; `5` &nbsp;</button></td>\n<td><button onclick=\"append('6')\">&nbsp; `6` &nbsp;</button></td>\n\n<td><button onclick=\"append('-')\">&nbsp;`-{::}`&nbsp;</button></td>\n</tr>\n<tr>\n<td><button onclick=\"append('e')\">&nbsp; `e` &nbsp;</button></td>\n<td><button onclick=\"append('1')\">&nbsp;&nbsp;`1` &nbsp;</button></td>\n<td><button onclick=\"append('2')\">&nbsp; `2` &nbsp;</button></td>\n<td><button onclick=\"append('3')\">&nbsp; `3` &nbsp;</button></td>\n<td><button onclick=\"append('+')\">&nbsp;`+{::}`&nbsp;</button></td>\n\n</tr>\n<tr>\n<td> <!--button onclick=\"append('pi')\">&nbsp;`pi` &nbsp;</button--></td>\n<td><button onclick=\"append('0')\">&nbsp; `0` &nbsp;</button></td>\n<td><button onclick=\"append('.')\">&nbsp; `.` &nbsp;</button></td>\n<td><button onclick=\"append('\\n')\">&nbsp;`\"ent\"`</button></td>\n</tr>\n</tbody>\n</table>";
       
  3434 
       
  3435 // GO1.1 Generic onload by Brothercake
       
  3436 // http://www.brothercake.com/
       
  3437 //onload function (replaces the onload="translate()" in the <body> tag)
       
  3438 function generic()
       
  3439 {
       
  3440   if (translateOnLoad) {
       
  3441     var nd = document.getElementById("processasciimathinmoodle");
       
  3442     if (nd!=null) dsvglocation = nd.className;
       
  3443     if (nd!=null || !checkforprocessasciimathinmoodle) {
       
  3444       if (translateLaTeX) LMtranslate();
       
  3445       if (translateASCIIMath) translate();
       
  3446       if (translateASCIIsvg) drawPictures();
       
  3447     }
       
  3448     var li = getElementsByClass(document,"div","ASCIIMathCalculator");
       
  3449     if (li.length>0) initASCIIMathCalculators(li);
       
  3450   }
       
  3451 };
       
  3452 //setup onload function
       
  3453 if(typeof window.addEventListener != 'undefined')
       
  3454 {
       
  3455   //.. gecko, safari, konqueror and standard
       
  3456   window.addEventListener('load', generic, false);
       
  3457 }
       
  3458 else if(typeof document.addEventListener != 'undefined')
       
  3459 {
       
  3460   //.. opera 7
       
  3461   document.addEventListener('load', generic, false);
       
  3462 }
       
  3463 else if(typeof window.attachEvent != 'undefined')
       
  3464 {
       
  3465   //.. win/ie
       
  3466   window.attachEvent('onload', generic);
       
  3467 }
       
  3468 //** remove this condition to degrade older browsers
       
  3469 else
       
  3470 {
       
  3471   //.. mac/ie5 and anything else that gets this far
       
  3472   //if there's an existing onload function
       
  3473   if(typeof window.onload == 'function')
       
  3474   {
       
  3475     //store it
       
  3476     var existing = onload;
       
  3477     //add new onload handler
       
  3478     window.onload = function()
       
  3479     {
       
  3480       //call existing onload function
       
  3481       existing();
       
  3482       //call generic onload function
       
  3483       generic();
       
  3484     };
       
  3485   }
       
  3486   else
       
  3487   {
       
  3488     //setup onload function
       
  3489     window.onload = generic;
       
  3490   }
       
  3491 }
       
  3492