PageSourceSearch

https://olivermath.github.io/LaTeXMathML.js

js olivermath.github.io collected 2026-10-03 09:42:41 UTC 54,437 bytes, 1,225 lines download raw bytes

1/*
2LaTeXMathML.js
3==============
4
5This file, in this form, is due to Douglas Woodall, June 2006.
6It contains JavaScript functions to convert (most simple) LaTeX
7math notation to Presentation MathML.  It was obtained by
8downloading the file ASCIIMathML.js from
9	http://www1.chapman.edu/~jipsen/mathml/asciimathdownload/
10and modifying it so that it carries out ONLY those conversions
11that would be carried out in LaTeX.  A description of the original
12file, with examples, can be found at
13	www1.chapman.edu/~jipsen/mathml/asciimath.html
14	ASCIIMathML: Math on the web for everyone
15
16Here is the header notice from the original file:
17
18ASCIIMathML.js
19==============
20This file contains JavaScript functions to convert ASCII math notation
21to Presentation MathML. The conversion is done while the (X)HTML page
22loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet
23Explorer 6+MathPlayer (http://www.dessci.com/en/products/mathplayer/).
24Just add the next line to your (X)HTML page with this file in the same folder:
25<script type="text/javascript" src="ASCIIMathML.js"></script>
26This is a convenient and inexpensive solution for authoring MathML.
27
28Version 1.4.7 Dec 15, 2005, (c) Peter Jipsen http://www.chapman.edu/~jipsen
29Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js
30For changes see http://www.chapman.edu/~jipsen/mathml/asciimathchanges.txt
31If you use it on a webpage, please send the URL to [email protected]
32
33This program is free software; you can redistribute it and/or modify
34it under the terms of the GNU General Public License as published by
35the Free Software Foundation; either version 2 of the License, or (at
36your option) any later version.
37
38This program is distributed in the hope that it will be useful,
39but WITHOUT ANY WARRANTY; without even the implied warranty of
40MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41General Public License (at http://www.gnu.org/copyleft/gpl.html)
42for more details.
43
44LaTeXMathML.js (ctd)
45==============
46
47The instructions for use are the same as for the original
48ASCIIMathML.js, except that of course the line you add to your
49file should be
50<script type="text/javascript" src="LaTeXMathML.js"></script>
51Or use absolute path names if the file is not in the same folder
52as your (X)HTML page.
53*/
54
55var checkForMathML = true;   // check if browser can display MathML
56var notifyIfNoMathML = true; // display note if no MathML capability
57var alertIfNoMathML = false;  // show alert box if no MathML capability
58// was "red":
59var mathcolor = "";	     // change it to "" (to inherit) or any other color
60// was "serif":
61var mathfontfamily = "";      // change to "" to inherit (works in IE)
62                              // or another family (e.g. "arial")
63var showasciiformulaonhover = true; // helps students learn ASCIIMath
64/*
65// Commented out by DRW -- not now used -- see DELIMITERS (twice) near the end
66var displaystyle = false;     // puts limits above and below large operators
67var decimalsign = ".";        // change to "," if you like, beware of `(1,2)`!
68var AMdelimiter1 = "`", AMescape1 = "\\\\`"; // can use other characters
69var AMdelimiter2 = "$", AMescape2 = "\\\\\\$", AMdelimiter2regexp = "\\$";
70var doubleblankmathdelimiter = false; // if true,  x+1  is equal to `x+1`
71                                      // for IE this works only in <!--   -->
72//var separatetokens;// has been removed (email me if this is a problem)
73*/
74var isIE = document.createElementNS==null;
75
76if (document.getElementById==null)
77  alert("This webpage requires a recent browser such as\
78\nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
79
80// all further global variables start with "AM"
81
82function AMcreateElementXHTML(t) {
83  if (isIE) return document.createElement(t);
84  else return document.createElementNS("http://www.w3.org/1999/xhtml",t);
85}
86
87function AMnoMathMLNote() {
88  var nd = AMcreateElementXHTML("h3");
89  nd.setAttribute("align","center")
90  nd.appendChild(AMcreateElementXHTML("p"));
91  nd.appendChild(document.createTextNode("To view the "));
92  var an = AMcreateElementXHTML("a");
93  an.appendChild(document.createTextNode("LaTeXMathML"));
94  an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");
95  nd.appendChild(an);
96  nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+")); 
97  an = AMcreateElementXHTML("a");
98  an.appendChild(document.createTextNode("MathPlayer"));
99  an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");
100  nd.appendChild(an);
101  nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));
102  nd.appendChild(AMcreateElementXHTML("p"));
103  return nd;
104}
105
106function AMisMathMLavailable() {
107  if (navigator.appName.slice(0,8)=="Netscape")
108    if (navigator.appVersion.slice(0,1)>="5") return null;
109    else return AMnoMathMLNote();
110  else if (navigator.appName.slice(0,9)=="Microsoft")
111    try {
112        var ActiveX = new ActiveXObject("MathPlayer.Factory.1");
113        return null;
114    } catch (e) {
115        return AMnoMathMLNote();
116    }
117  else return AMnoMathMLNote();
118}
119
120// character lists for Mozilla/Netscape fonts
121var 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];
122var 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];
123var 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];
124
125var CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4,
126    RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8,
127    TEXT = 9, BIG = 10, LONG = 11, STRETCHY = 12, MATRIX = 13; // token types
128
129var AMsqrt = {input:"\\sqrt",	tag:"msqrt", output:"sqrt",	ttype:UNARY},
130  AMroot = {input:"\\root",	tag:"mroot", output:"root",	ttype:BINARY},
131  AMfrac = {input:"\\frac",	tag:"mfrac", output:"/",	ttype:BINARY},
132  AMover = {input:"\\stackrel", tag:"mover", output:"stackrel", ttype:BINARY},
133  AMatop = {input:"\\atop",	tag:"mfrac", output:"",		ttype:INFIX},
134  AMchoose = {input:"\\choose", tag:"mfrac", output:"",		ttype:INFIX},
135  AMsub  = {input:"_",		tag:"msub",  output:"_",	ttype:INFIX},
136  AMsup  = {input:"^",		tag:"msup",  output:"^",	ttype:INFIX},
137  AMtext = {input:"\\mathrm",	tag:"mtext", output:"text",	ttype:TEXT},
138  AMmbox = {input:"\\mbox",	tag:"mtext", output:"mbox",	ttype:TEXT};
139
140// Commented out by DRW to prevent 1/2 turning into a 2-line fraction
141// AMdiv   = {input:"/",	 tag:"mfrac", output:"/",    ttype:INFIX},
142// Commented out by DRW so that " prints literally in equations
143// AMquote = {input:"\"",	 tag:"mtext", output:"mbox", ttype:TEXT};
144
145var AMsymbols = [
146//Greek letters
147{input:"\\alpha",	tag:"mi", output:"\u03B1", ttype:CONST},
148{input:"\\beta",	tag:"mi", output:"\u03B2", ttype:CONST},
149{input:"\\gamma",	tag:"mi", output:"\u03B3", ttype:CONST},
150{input:"\\delta",	tag:"mi", output:"\u03B4", ttype:CONST},
151{input:"\\epsilon",	tag:"mi", output:"\u03B5", ttype:CONST},
152{input:"\\varepsilon",  tag:"mi", output:"\u025B", ttype:CONST},
153{input:"\\zeta",	tag:"mi", output:"\u03B6", ttype:CONST},
154{input:"\\eta",		tag:"mi", output:"\u03B7", ttype:CONST},
155{input:"\\theta",	tag:"mi", output:"\u03B8", ttype:CONST},
156{input:"\\vartheta",	tag:"mi", output:"\u03D1", ttype:CONST},
157{input:"\\iota",	tag:"mi", output:"\u03B9", ttype:CONST},
158{input:"\\kappa",	tag:"mi", output:"\u03BA", ttype:CONST},
159{input:"\\lambda",	tag:"mi", output:"\u03BB", ttype:CONST},
160{input:"\\mu",		tag:"mi", output:"\u03BC", ttype:CONST},
161{input:"\\nu",		tag:"mi", output:"\u03BD", ttype:CONST},
162{input:"\\xi",		tag:"mi", output:"\u03BE", ttype:CONST},
163{input:"\\pi",		tag:"mi", output:"\u03C0", ttype:CONST},
164{input:"\\varpi",	tag:"mi", output:"\u03D6", ttype:CONST},
165{input:"\\rho",		tag:"mi", output:"\u03C1", ttype:CONST},
166{input:"\\varrho",	tag:"mi", output:"\u03F1", ttype:CONST},
167{input:"\\varsigma",	tag:"mi", output:"\u03C2", ttype:CONST},
168{input:"\\sigma",	tag:"mi", output:"\u03C3", ttype:CONST},
169{input:"\\tau",		tag:"mi", output:"\u03C4", ttype:CONST},
170{input:"\\upsilon",	tag:"mi", output:"\u03C5", ttype:CONST},
171{input:"\\phi",		tag:"mi", output:"\u03C6", ttype:CONST},
172{input:"\\varphi",	tag:"mi", output:"\u03D5", ttype:CONST},
173{input:"\\chi",		tag:"mi", output:"\u03C7", ttype:CONST},
174{input:"\\psi",		tag:"mi", output:"\u03C8", ttype:CONST},
175{input:"\\omega",	tag:"mi", output:"\u03C9", ttype:CONST},
176{input:"\\Gamma",	tag:"mo", output:"\u0393", ttype:CONST},
177{input:"\\Delta",	tag:"mo", output:"\u0394", ttype:CONST},
178{input:"\\Theta",	tag:"mo", output:"\u0398", ttype:CONST},
179{input:"\\Lambda",	tag:"mo", output:"\u039B", ttype:CONST},
180{input:"\\Xi",		tag:"mo", output:"\u039E", ttype:CONST},
181{input:"\\Pi",		tag:"mo", output:"\u03A0", ttype:CONST},
182{input:"\\Sigma",	tag:"mo", output:"\u03A3", ttype:CONST},
183{input:"\\Upsilon",	tag:"mo", output:"\u03A5", ttype:CONST},
184{input:"\\Phi",		tag:"mo", output:"\u03A6", ttype:CONST},
185{input:"\\Psi",		tag:"mo", output:"\u03A8", ttype:CONST},
186{input:"\\Omega",	tag:"mo", output:"\u03A9", ttype:CONST},
187
188//fractions
189{input:"\\frac12",	tag:"mo", output:"\u00BD", ttype:CONST},
190{input:"\\frac14",	tag:"mo", output:"\u00BC", ttype:CONST},
191{input:"\\frac34",	tag:"mo", output:"\u00BE", ttype:CONST},
192{input:"\\frac13",	tag:"mo", output:"\u2153", ttype:CONST},
193{input:"\\frac23",	tag:"mo", output:"\u2154", ttype:CONST},
194{input:"\\frac15",	tag:"mo", output:"\u2155", ttype:CONST},
195{input:"\\frac25",	tag:"mo", output:"\u2156", ttype:CONST},
196{input:"\\frac35",	tag:"mo", output:"\u2157", ttype:CONST},
197{input:"\\frac45",	tag:"mo", output:"\u2158", ttype:CONST},
198{input:"\\frac16",	tag:"mo", output:"\u2159", ttype:CONST},
199{input:"\\frac56",	tag:"mo", output:"\u215A", ttype:CONST},
200{input:"\\frac18",	tag:"mo", output:"\u215B", ttype:CONST},
201{input:"\\frac38",	tag:"mo", output:"\u215C", ttype:CONST},
202{input:"\\frac58",	tag:"mo", output:"\u215D", ttype:CONST},
203{input:"\\frac78",	tag:"mo", output:"\u215E", ttype:CONST},
204
205//binary operation symbols
206{input:"\\pm",		tag:"mo", output:"\u00B1", ttype:CONST},
207{input:"\\mp",		tag:"mo", output:"\u2213", ttype:CONST},
208{input:"\\triangleleft",tag:"mo", output:"\u22B2", ttype:CONST},
209{input:"\\triangleright",tag:"mo",output:"\u22B3", ttype:CONST},
210{input:"\\cdot",	tag:"mo", output:"\u22C5", ttype:CONST},
211{input:"\\star",	tag:"mo", output:"\u22C6", ttype:CONST},
212{input:"\\ast",		tag:"mo", output:"\u002A", ttype:CONST},
213{input:"\\times",	tag:"mo", output:"\u00D7", ttype:CONST},
214{input:"\\div",		tag:"mo", output:"\u00F7", ttype:CONST},
215{input:"\\circ",	tag:"mo", output:"\u2218", ttype:CONST},
216//{input:"\\bullet",	  tag:"mo", output:"\u2219", ttype:CONST},
217{input:"\\bullet",	tag:"mo", output:"\u2022", ttype:CONST},
218{input:"\\oplus",	tag:"mo", output:"\u2295", ttype:CONST},
219{input:"\\ominus",	tag:"mo", output:"\u2296", ttype:CONST},
220{input:"\\otimes",	tag:"mo", output:"\u2297", ttype:CONST},
221{input:"\\bigcirc",	tag:"mo", output:"\u25CB", ttype:CONST},
222{input:"\\oslash",	tag:"mo", output:"\u2298", ttype:CONST},
223{input:"\\odot",	tag:"mo", output:"\u2299", ttype:CONST},
224{input:"\\land",	tag:"mo", output:"\u2227", ttype:CONST},
225{input:"\\wedge",	tag:"mo", output:"\u2227", ttype:CONST},
226{input:"\\lor",		tag:"mo", output:"\u2228", ttype:CONST},
227{input:"\\vee",		tag:"mo", output:"\u2228", ttype:CONST},
228{input:"\\cap",		tag:"mo", output:"\u2229", ttype:CONST},
229{input:"\\cup",		tag:"mo", output:"\u222A", ttype:CONST},
230{input:"\\sqcap",	tag:"mo", output:"\u2293", ttype:CONST},
231{input:"\\sqcup",	tag:"mo", output:"\u2294", ttype:CONST},
232{input:"\\uplus",	tag:"mo", output:"\u228E", ttype:CONST},
233{input:"\\amalg",	tag:"mo", output:"\u2210", ttype:CONST},
234{input:"\\bigtriangleup",tag:"mo",output:"\u25B3", ttype:CONST},
235{input:"\\bigtriangledown",tag:"mo",output:"\u25BD", ttype:CONST},
236{input:"\\dag",		tag:"mo", output:"\u2020", ttype:CONST},
237{input:"\\dagger",	tag:"mo", output:"\u2020", ttype:CONST},
238{input:"\\ddag",	tag:"mo", output:"\u2021", ttype:CONST},
239{input:"\\ddagger",	tag:"mo", output:"\u2021", ttype:CONST},
240{input:"\\lhd",		tag:"mo", output:"\u22B2", ttype:CONST},
241{input:"\\rhd",		tag:"mo", output:"\u22B3", ttype:CONST},
242{input:"\\unlhd",	tag:"mo", output:"\u22B4", ttype:CONST},
243{input:"\\unrhd",	tag:"mo", output:"\u22B5", ttype:CONST},
244
245
246//BIG Operators
247{input:"\\sum",		tag:"mo", output:"\u2211", ttype:UNDEROVER},
248{input:"\\prod",	tag:"mo", output:"\u220F", ttype:UNDEROVER},
249{input:"\\bigcap",	tag:"mo", output:"\u22C2", ttype:UNDEROVER},
250{input:"\\bigcup",	tag:"mo", output:"\u22C3", ttype:UNDEROVER},
251{input:"\\bigwedge",	tag:"mo", output:"\u22C0", ttype:UNDEROVER},
252{input:"\\bigvee",	tag:"mo", output:"\u22C1", ttype:UNDEROVER},
253{input:"\\bigsqcap",	tag:"mo", output:"\u2A05", ttype:UNDEROVER},
254{input:"\\bigsqcup",	tag:"mo", output:"\u2A06", ttype:UNDEROVER},
255{input:"\\coprod",	tag:"mo", output:"\u2210", ttype:UNDEROVER},
256{input:"\\bigoplus",	tag:"mo", output:"\u2A01", ttype:UNDEROVER},
257{input:"\\bigotimes",	tag:"mo", output:"\u2A02", ttype:UNDEROVER},
258{input:"\\bigodot",	tag:"mo", output:"\u2A00", ttype:UNDEROVER},
259{input:"\\biguplus",	tag:"mo", output:"\u2A04", ttype:UNDEROVER},
260{input:"\\int",		tag:"mo", output:"\u222B", ttype:CONST},
261{input:"\\oint",	tag:"mo", output:"\u222E", ttype:CONST},
262
263//binary relation symbols
264{input:":=",		tag:"mo", output:":=",	   ttype:CONST},
265{input:"\\lt",		tag:"mo", output:"<",	   ttype:CONST},
266{input:"\\gt",		tag:"mo", output:">",	   ttype:CONST},
267{input:"\\ne",		tag:"mo", output:"\u2260", ttype:CONST},
268{input:"\\neq",		tag:"mo", output:"\u2260", ttype:CONST},
269{input:"\\le",		tag:"mo", output:"\u2264", ttype:CONST},
270{input:"\\leq",		tag:"mo", output:"\u2264", ttype:CONST},
271{input:"\\leqslant",	tag:"mo", output:"\u2264", ttype:CONST},
272{input:"\\ge",		tag:"mo", output:"\u2265", ttype:CONST},
273{input:"\\geq",		tag:"mo", output:"\u2265", ttype:CONST},
274{input:"\\geqslant",	tag:"mo", output:"\u2265", ttype:CONST},
275{input:"\\equiv",	tag:"mo", output:"\u2261", ttype:CONST},
276{input:"\\ll",		tag:"mo", output:"\u226A", ttype:CONST},
277{input:"\\gg",		tag:"mo", output:"\u226B", ttype:CONST},
278{input:"\\doteq",	tag:"mo", output:"\u2250", ttype:CONST},
279{input:"\\prec",	tag:"mo", output:"\u227A", ttype:CONST},
280{input:"\\succ",	tag:"mo", output:"\u227B", ttype:CONST},
281{input:"\\preceq",	tag:"mo", output:"\u227C", ttype:CONST},
282{input:"\\succeq",	tag:"mo", output:"\u227D", ttype:CONST},
283{input:"\\subset",	tag:"mo", output:"\u2282", ttype:CONST},
284{input:"\\supset",	tag:"mo", output:"\u2283", ttype:CONST},
285{input:"\\subseteq",	tag:"mo", output:"\u2286", ttype:CONST},
286{input:"\\supseteq",	tag:"mo", output:"\u2287", ttype:CONST},
287{input:"\\sqsubset",	tag:"mo", output:"\u228F", ttype:CONST},
288{input:"\\sqsupset",	tag:"mo", output:"\u2290", ttype:CONST},
289{input:"\\sqsubseteq",  tag:"mo", output:"\u2291", ttype:CONST},
290{input:"\\sqsupseteq",  tag:"mo", output:"\u2292", ttype:CONST},
291{input:"\\sim",		tag:"mo", output:"\u223C", ttype:CONST},
292{input:"\\simeq",	tag:"mo", output:"\u2243", ttype:CONST},
293{input:"\\approx",	tag:"mo", output:"\u2248", ttype:CONST},
294{input:"\\cong",	tag:"mo", output:"\u2245", ttype:CONST},
295{input:"\\Join",	tag:"mo", output:"\u22C8", ttype:CONST},
296{input:"\\bowtie",	tag:"mo", output:"\u22C8", ttype:CONST},
297{input:"\\in",		tag:"mo", output:"\u2208", ttype:CONST},
298{input:"\\ni",		tag:"mo", output:"\u220B", ttype:CONST},
299{input:"\\owns",	tag:"mo", output:"\u220B", ttype:CONST},
300{input:"\\propto",	tag:"mo", output:"\u221D", ttype:CONST},
301{input:"\\vdash",	tag:"mo", output:"\u22A2", ttype:CONST},
302{input:"\\dashv",	tag:"mo", output:"\u22A3", ttype:CONST},
303{input:"\\models",	tag:"mo", output:"\u22A8", ttype:CONST},
304{input:"\\perp",	tag:"mo", output:"\u22A5", ttype:CONST},
305{input:"\\smile",	tag:"mo", output:"\u2323", ttype:CONST},
306{input:"\\frown",	tag:"mo", output:"\u2322", ttype:CONST},
307{input:"\\asymp",	tag:"mo", output:"\u224D", ttype:CONST},
308{input:"\\notin",	tag:"mo", output:"\u2209", ttype:CONST},
309
310//matrices
311{input:"\\begin{eqnarray}",	output:"X",	ttype:MATRIX, invisible:true},
312{input:"\\begin{array}",	output:"X",	ttype:MATRIX, invisible:true},
313{input:"\\\\",			output:"}&{",	ttype:DEFINITION},
314{input:"\\end{eqnarray}",	output:"}}",	ttype:DEFINITION},
315{input:"\\end{array}",		output:"}}",	ttype:DEFINITION},
316
317//grouping and literal brackets -- ieval is for IE
318{input:"\\big",	   tag:"mo", output:"X", atval:"1.2", ieval:"2.2", ttype:BIG},
319{input:"\\Big",	   tag:"mo", output:"X", atval:"1.6", ieval:"2.6", ttype:BIG},
320{input:"\\bigg",   tag:"mo", output:"X", atval:"2.2", ieval:"3.2", ttype:BIG},
321{input:"\\Bigg",   tag:"mo", output:"X", atval:"2.9", ieval:"3.9", ttype:BIG},
322{input:"\\left",   tag:"mo", output:"X", ttype:LEFTBRACKET},
323{input:"\\right",  tag:"mo", output:"X", ttype:RIGHTBRACKET},
324{input:"{",	   output:"{", ttype:LEFTBRACKET,  invisible:true},
325{input:"}",	   output:"}", ttype:RIGHTBRACKET, invisible:true},
326
327{input:"(",	   tag:"mo", output:"(",      atval:"1", ttype:STRETCHY},
328{input:"[",	   tag:"mo", output:"[",      atval:"1", ttype:STRETCHY},
329{input:"\\lbrack", tag:"mo", output:"[",      atval:"1", ttype:STRETCHY},
330{input:"\\{",	   tag:"mo", output:"{",      atval:"1", ttype:STRETCHY},
331{input:"\\lbrace", tag:"mo", output:"{",      atval:"1", ttype:STRETCHY},
332{input:"\\langle", tag:"mo", output:"\u2329", atval:"1", ttype:STRETCHY},
333{input:"\\lfloor", tag:"mo", output:"\u230A", atval:"1", ttype:STRETCHY},
334{input:"\\lceil",  tag:"mo", output:"\u2308", atval:"1", ttype:STRETCHY},
335
336// rtag:"mi" causes space to be inserted before a following sin, cos, etc.
337// (see function AMparseExpr() )
338{input:")",	  tag:"mo",output:")",	    rtag:"mi",atval:"1",ttype:STRETCHY},
339{input:"]",	  tag:"mo",output:"]",	    rtag:"mi",atval:"1",ttype:STRETCHY},
340{input:"\\rbrack",tag:"mo",output:"]",	    rtag:"mi",atval:"1",ttype:STRETCHY},
341{input:"\\}",	  tag:"mo",output:"}",	    rtag:"mi",atval:"1",ttype:STRETCHY},
342{input:"\\rbrace",tag:"mo",output:"}",	    rtag:"mi",atval:"1",ttype:STRETCHY},
343{input:"\\rangle",tag:"mo",output:"\u232A", rtag:"mi",atval:"1",ttype:STRETCHY},
344{input:"\\rfloor",tag:"mo",output:"\u230B", rtag:"mi",atval:"1",ttype:STRETCHY},
345{input:"\\rceil", tag:"mo",output:"\u2309", rtag:"mi",atval:"1",ttype:STRETCHY},
346
347// "|", "\\|", "\\vert" and "\\Vert" modified later: lspace = rspace = 0em
348{input:"|",		tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
349{input:"\\|",		tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
350{input:"\\vert",	tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
351{input:"\\Vert",	tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
352{input:"\\mid",		tag:"mo", output:"\u2223", atval:"1", ttype:STRETCHY},
353{input:"\\parallel",	tag:"mo", output:"\u2225", atval:"1", ttype:STRETCHY},
354{input:"/",		tag:"mo", output:"/",	atval:"1.01", ttype:STRETCHY},
355{input:"\\backslash",	tag:"mo", output:"\u2216", atval:"1", ttype:STRETCHY},
356{input:"\\setminus",	tag:"mo", output:"\\",	   ttype:CONST},
357
358//miscellaneous symbols
359{input:"\\!",	  tag:"mspace", atname:"width", atval:"-0.167em", ttype:SPACE},
360{input:"\\,",	  tag:"mspace", atname:"width", atval:"0.167em", ttype:SPACE},
361{input:"\\>",	  tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE},
362{input:"\\:",	  tag:"mspace", atname:"width", atval:"0.222em", ttype:SPACE},
363{input:"\\;",	  tag:"mspace", atname:"width", atval:"0.278em", ttype:SPACE},
364{input:"~",	  tag:"mspace", atname:"width", atval:"0.333em", ttype:SPACE},
365{input:"\\quad",  tag:"mspace", atname:"width", atval:"1em", ttype:SPACE},
366{input:"\\qquad", tag:"mspace", atname:"width", atval:"2em", ttype:SPACE},
367//{input:"{}",		  tag:"mo", output:"\u200B", ttype:CONST}, // zero-width
368{input:"\\prime",	tag:"mo", output:"\u2032", ttype:CONST},
369{input:"'",		tag:"mo", output:"\u02B9", ttype:CONST},
370{input:"''",		tag:"mo", output:"\u02BA", ttype:CONST},
371{input:"'''",		tag:"mo", output:"\u2034", ttype:CONST},
372{input:"''''",		tag:"mo", output:"\u2057", ttype:CONST},
373{input:"\\ldots",	tag:"mo", output:"\u2026", ttype:CONST},
374{input:"\\cdots",	tag:"mo", output:"\u22EF", ttype:CONST},
375{input:"\\vdots",	tag:"mo", output:"\u22EE", ttype:CONST},
376{input:"\\ddots",	tag:"mo", output:"\u22F1", ttype:CONST},
377{input:"\\forall",	tag:"mo", output:"\u2200", ttype:CONST},
378{input:"\\exists",	tag:"mo", output:"\u2203", ttype:CONST},
379{input:"\\Re",		tag:"mo", output:"\u211C", ttype:CONST},
380{input:"\\Im",		tag:"mo", output:"\u2111", ttype:CONST},
381{input:"\\aleph",	tag:"mo", output:"\u2135", ttype:CONST},
382{input:"\\hbar",	tag:"mo", output:"\u210F", ttype:CONST},
383{input:"\\ell",		tag:"mo", output:"\u2113", ttype:CONST},
384{input:"\\wp",		tag:"mo", output:"\u2118", ttype:CONST},
385{input:"\\emptyset",	tag:"mo", output:"\u2205", ttype:CONST},
386{input:"\\infty",	tag:"mo", output:"\u221E", ttype:CONST},
387{input:"\\surd",	tag:"mo", output:"\\sqrt{}", ttype:DEFINITION},
388{input:"\\partial",	tag:"mo", output:"\u2202", ttype:CONST},
389{input:"\\nabla",	tag:"mo", output:"\u2207", ttype:CONST},
390{input:"\\triangle",	tag:"mo", output:"\u25B3", ttype:CONST},
391{input:"\\therefore",	tag:"mo", output:"\u2234", ttype:CONST},
392{input:"\\angle",	tag:"mo", output:"\u2220", ttype:CONST},
393//{input:"\\\\ ",	  tag:"mo", output:"\u00A0", ttype:CONST},
394{input:"\\diamond",	tag:"mo", output:"\u22C4", ttype:CONST},
395//{input:"\\Diamond",	  tag:"mo", output:"\u25CA", ttype:CONST},
396{input:"\\Diamond",	tag:"mo", output:"\u25C7", ttype:CONST},
397{input:"\\neg",		tag:"mo", output:"\u00AC", ttype:CONST},
398{input:"\\lnot",	tag:"mo", output:"\u00AC", ttype:CONST},
399{input:"\\bot",		tag:"mo", output:"\u22A5", ttype:CONST},
400{input:"\\top",		tag:"mo", output:"\u22A4", ttype:CONST},
401{input:"\\square",	tag:"mo", output:"\u25AB", ttype:CONST},
402{input:"\\Box",		tag:"mo", output:"\u25A1", ttype:CONST},
403{input:"\\wr",		tag:"mo", output:"\u2240", ttype:CONST},
404
405//standard functions
406//Note UNDEROVER *must* have tag:"mo" to work properly
407{input:"\\arccos", tag:"mi", output:"arccos", ttype:UNARY, func:true},
408{input:"\\arcsin", tag:"mi", output:"arcsin", ttype:UNARY, func:true},
409{input:"\\arctan", tag:"mi", output:"arctan", ttype:UNARY, func:true},
410{input:"\\arg",	   tag:"mi", output:"arg",    ttype:UNARY, func:true},
411{input:"\\cos",	   tag:"mi", output:"cos",    ttype:UNARY, func:true},
412{input:"\\cosh",   tag:"mi", output:"cosh",   ttype:UNARY, func:true},
413{input:"\\cot",	   tag:"mi", output:"cot",    ttype:UNARY, func:true},
414{input:"\\coth",   tag:"mi", output:"coth",   ttype:UNARY, func:true},
415{input:"\\csc",	   tag:"mi", output:"csc",    ttype:UNARY, func:true},
416{input:"\\deg",	   tag:"mi", output:"deg",    ttype:UNARY, func:true},
417{input:"\\det",	   tag:"mi", output:"det",    ttype:UNARY, func:true},
418{input:"\\dim",	   tag:"mi", output:"dim",    ttype:UNARY, func:true}, //CONST?
419{input:"\\exp",	   tag:"mi", output:"exp",    ttype:UNARY, func:true},
420{input:"\\gcd",	   tag:"mi", output:"gcd",    ttype:UNARY, func:true}, //CONST?
421{input:"\\hom",	   tag:"mi", output:"hom",    ttype:UNARY, func:true},
422{input:"\\inf",	      tag:"mo", output:"inf",	 ttype:UNDEROVER},
423{input:"\\ker",	   tag:"mi", output:"ker",    ttype:UNARY, func:true},
424{input:"\\lg",	   tag:"mi", output:"lg",     ttype:UNARY, func:true},
425{input:"\\lim",	      tag:"mo", output:"lim",	 ttype:UNDEROVER},
426{input:"\\liminf",    tag:"mo", output:"liminf", ttype:UNDEROVER},
427{input:"\\limsup",    tag:"mo", output:"limsup", ttype:UNDEROVER},
428{input:"\\ln",	   tag:"mi", output:"ln",     ttype:UNARY, func:true},
429{input:"\\log",	   tag:"mi", output:"log",    ttype:UNARY, func:true},
430{input:"\\max",	      tag:"mo", output:"max",	 ttype:UNDEROVER},
431{input:"\\min",	      tag:"mo", output:"min",	 ttype:UNDEROVER},
432{input:"\\Pr",	   tag:"mi", output:"Pr",     ttype:UNARY, func:true},
433{input:"\\sec",	   tag:"mi", output:"sec",    ttype:UNARY, func:true},
434{input:"\\sin",	   tag:"mi", output:"sin",    ttype:UNARY, func:true},
435{input:"\\sinh",   tag:"mi", output:"sinh",   ttype:UNARY, func:true},
436{input:"\\sup",	      tag:"mo", output:"sup",	 ttype:UNDEROVER},
437{input:"\\tan",	   tag:"mi", output:"tan",    ttype:UNARY, func:true},
438{input:"\\tanh",   tag:"mi", output:"tanh",   ttype:UNARY, func:true},
439
440//arrows
441{input:"\\gets",		tag:"mo", output:"\u2190", ttype:CONST},
442{input:"\\leftarrow",		tag:"mo", output:"\u2190", ttype:CONST},
443{input:"\\to",			tag:"mo", output:"\u2192", ttype:CONST},
444{input:"\\rightarrow",		tag:"mo", output:"\u2192", ttype:CONST},
445{input:"\\leftrightarrow",	tag:"mo", output:"\u2194", ttype:CONST},
446{input:"\\uparrow",		tag:"mo", output:"\u2191", ttype:CONST},
447{input:"\\downarrow",		tag:"mo", output:"\u2193", ttype:CONST},
448{input:"\\updownarrow",		tag:"mo", output:"\u2195", ttype:CONST},
449{input:"\\Leftarrow",		tag:"mo", output:"\u21D0", ttype:CONST},
450{input:"\\Rightarrow",		tag:"mo", output:"\u21D2", ttype:CONST},
451{input:"\\Leftrightarrow",	tag:"mo", output:"\u21D4", ttype:CONST},
452{input:"\\iff", tag:"mo", output:"~\\Longleftrightarrow~", ttype:DEFINITION},
453{input:"\\Uparrow",		tag:"mo", output:"\u21D1", ttype:CONST},
454{input:"\\Downarrow",		tag:"mo", output:"\u21D3", ttype:CONST},
455{input:"\\Updownarrow",		tag:"mo", output:"\u21D5", ttype:CONST},
456{input:"\\mapsto",		tag:"mo", output:"\u21A6", ttype:CONST},
457{input:"\\longleftarrow",	tag:"mo", output:"\u2190", ttype:LONG},
458{input:"\\longrightarrow",	tag:"mo", output:"\u2192", ttype:LONG},
459{input:"\\longleftrightarrow",	tag:"mo", output:"\u2194", ttype:LONG},
460{input:"\\Longleftarrow",	tag:"mo", output:"\u21D0", ttype:LONG},
461{input:"\\Longrightarrow",	tag:"mo", output:"\u21D2", ttype:LONG},
462{input:"\\Longleftrightarrow",  tag:"mo", output:"\u21D4", ttype:LONG},
463{input:"\\longmapsto",		tag:"mo", output:"\u21A6", ttype:CONST},
464							// disaster if LONG
465
466//commands with argument
467AMsqrt, AMroot, AMfrac, AMover, AMsub, AMsup, AMtext, AMmbox, AMatop, AMchoose,
468//AMdiv, AMquote,
469
470//diacritical marks
471{input:"\\acute",	tag:"mover",  output:"\u00B4", ttype:UNARY, acc:true},
472//{input:"\\acute",	  tag:"mover",  output:"\u0317", ttype:UNARY, acc:true},
473//{input:"\\acute",	  tag:"mover",  output:"\u0301", ttype:UNARY, acc:true},
474//{input:"\\grave",	  tag:"mover",  output:"\u0300", ttype:UNARY, acc:true},
475//{input:"\\grave",	  tag:"mover",  output:"\u0316", ttype:UNARY, acc:true},
476{input:"\\grave",	tag:"mover",  output:"\u0060", ttype:UNARY, acc:true},
477{input:"\\breve",	tag:"mover",  output:"\u02D8", ttype:UNARY, acc:true},
478{input:"\\check",	tag:"mover",  output:"\u02C7", ttype:UNARY, acc:true},
479{input:"\\dot",		tag:"mover",  output:".",      ttype:UNARY, acc:true},
480{input:"\\ddot",	tag:"mover",  output:"..",     ttype:UNARY, acc:true},
481//{input:"\\ddot",	  tag:"mover",  output:"\u00A8", ttype:UNARY, acc:true},
482{input:"\\mathring",	tag:"mover",  output:"\u00B0", ttype:UNARY, acc:true},
483{input:"\\vec",		tag:"mover",  output:"\u20D7", ttype:UNARY, acc:true},
484{input:"\\overrightarrow",tag:"mover",output:"\u20D7", ttype:UNARY, acc:true},
485{input:"\\overleftarrow",tag:"mover", output:"\u20D6", ttype:UNARY, acc:true},
486{input:"\\hat",		tag:"mover",  output:"\u005E", ttype:UNARY, acc:true},
487{input:"\\widehat",	tag:"mover",  output:"\u0302", ttype:UNARY, acc:true},
488{input:"\\tilde",	tag:"mover",  output:"~",      ttype:UNARY, acc:true},
489//{input:"\\tilde",	  tag:"mover",  output:"\u0303", ttype:UNARY, acc:true},
490{input:"\\widetilde",	tag:"mover",  output:"\u02DC", ttype:UNARY, acc:true},
491{input:"\\bar",		tag:"mover",  output:"\u203E", ttype:UNARY, acc:true},
492{input:"\\overbrace",	tag:"mover",  output:"\u23B4", ttype:UNARY, acc:true},
493{input:"\\overline",	tag:"mover",  output:"\u00AF", ttype:UNARY, acc:true},
494{input:"\\underbrace",  tag:"munder", output:"\u23B5", ttype:UNARY, acc:true},
495{input:"\\underline",	tag:"munder", output:"\u00AF", ttype:UNARY, acc:true},
496//{input:"underline",	tag:"munder", output:"\u0332", ttype:UNARY, acc:true},
497
498//typestyles and fonts
499{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true", ttype:UNARY},
500{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false", ttype:UNARY},
501{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1", ttype:UNARY},
502{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",a
502tval:"2", ttype:UNARY},
503{input:"\\textrm", tag:"mstyle", output:"\\mathrm", ttype: DEFINITION},
504{input:"\\mathbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY},
505{input:"\\textbf", tag:"mstyle", atname:"mathvariant", atval:"bold", ttype:UNARY},
506{input:"\\mathit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY},
507{input:"\\textit", tag:"mstyle", atname:"mathvariant", atval:"italic", ttype:UNARY},
508{input:"\\mathtt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY},
509{input:"\\texttt", tag:"mstyle", atname:"mathvariant", atval:"monospace", ttype:UNARY},
510{input:"\\mathsf", tag:"mstyle", atname:"mathvariant", atval:"sans-serif", ttype:UNARY},
511{input:"\\mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", ttype:UNARY, codes:AMbbb},
512{input:"\\mathcal",tag:"mstyle", atname:"mathvariant", atval:"script", ttype:UNARY, codes:AMcal},
513{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant", atval:"fraktur",ttype:UNARY, codes:AMfrk}
514];
515
516function compareNames(s1,s2) {
517  if (s1.input > s2.input) return 1
518  else return -1;
519}
520
521var AMnames = []; //list of input symbols
522
523function AMinitSymbols() {
524  AMsymbols.sort(compareNames);
525  for (i=0; i<AMsymbols.length; i++) AMnames[i] = AMsymbols[i].input;
526}
527
528var AMmathml = "http://www.w3.org/1998/Math/MathML";
529
530function AMcreateElementMathML(t) {
531  if (isIE) return document.createElement("m:"+t);
532  else return document.createElementNS(AMmathml,t);
533}
534
535function AMcreateMmlNode(t,frag) {
536//  var node = AMcreateElementMathML(name);
537  if (isIE) var node = document.createElement("m:"+t);
538  else var node = document.createElementNS(AMmathml,t);
539  node.appendChild(frag);
540  return node;
541}
542
543function newcommand(oldstr,newstr) {
544  AMsymbols = AMsymbols.concat([{input:oldstr, tag:"mo", output:newstr,
545                                 ttype:DEFINITION}]);
546}
547
548function AMremoveCharsAndBlanks(str,n) {
549//remove n characters and any following blanks
550  var st;
551  st = str.slice(n);
552  for (var i=0; i<st.length && st.charCodeAt(i)<=32; i=i+1);
553  return st.slice(i);
554}
555
556function AMposition(arr, str, n) {
557// return position >=n where str appears or would be inserted
558// assumes arr is sorted
559  if (n==0) {
560    var h,m;
561    n = -1;
562    h = arr.length;
563    while (n+1<h) {
564      m = (n+h) >> 1;
565      if (arr[m]<str) n = m; else h = m;
566    }
567    return h;
568  } else
569    for (var i=n; i<arr.length && arr[i]<str; i++);
570  return i; // i=arr.length || arr[i]>=str
571}
572
573function AMgetSymbol(str) {
574//return maximal initial substring of str that appears in names
575//return null if there is none
576  var k = 0; //new pos
577  var j = 0; //old pos
578  var mk; //match pos
579  var st;
580  var tagst;
581  var match = "";
582  var more = true;
583  for (var i=1; i<=str.length && more; i++) {
584    st = str.slice(0,i); //initial substring of length i
585    j = k;
586    k = AMposition(AMnames, st, j);
587    if (k<AMnames.length && str.slice(0,AMnames[k].length)==AMnames[k]){
588      match = AMnames[k];
589      mk = k;
590      i = match.length;
591    }
592    more = k<AMnames.length && str.slice(0,AMnames[k].length)>=AMnames[k];
593  }
594  AMpreviousSymbol=AMcurrentSymbol;
595  if (match!=""){
596    AMcurrentSymbol=AMsymbols[mk].ttype;
597    return AMsymbols[mk];
598  }
599  AMcurrentSymbol=CONST;
600  k = 1;
601  st = str.slice(0,1); //take 1 character
602  if ("0"<=st && st<="9") tagst = "mn";
603  else tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi");
604/*
605// Commented out by DRW (not fully understood, but probably to do with
606// use of "/" as an INFIX version of "\\frac", which we don't want):
607//}
608//if (st=="-" && AMpreviousSymbol==INFIX) {
609//  AMcurrentSymbol = INFIX;  //trick "/" into recognizing "-" on second parse
610//  return {input:st, tag:tagst, output:st, ttype:UNARY, func:true};
611//}
612*/
613  return {input:st, tag:tagst, output:st, ttype:CONST};
614}
615
616
617/*Parsing ASCII math expressions with the following grammar
618v ::= [A-Za-z] | greek letters | numbers | other constant symbols
619u ::= sqrt | text | bb | other unary symbols for font commands
620b ::= frac | root | stackrel	binary symbols
621l ::= { | \left			left brackets
622r ::= } | \right		right brackets
623S ::= v | lEr | uS | bSS	Simple expression
624I ::= S_S | S^S | S_S^S | S	Intermediate expression
625E ::= IE | I/I			Expression
626Each terminal symbol is translated into a corresponding mathml node.*/
627
628var AMpreviousSymbol,AMcurrentSymbol;
629
630function AMparseSexpr(str) { //parses str and returns [node,tailstr,(node)tag]
631  var symbol, node, result, result2, i, st,// rightvert = false,
632    newFrag = document.createDocumentFragment();
633  str = AMremoveCharsAndBlanks(str,0);
634  symbol = AMgetSymbol(str);             //either a token or a bracket or empty
635  if (symbol == null || symbol.ttype == RIGHTBRACKET)
636    return [null,str,null];
637  if (symbol.ttype == DEFINITION) {
638    str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);
639    symbol = AMgetSymbol(str);
640    if (symbol == null || symbol.ttype == RIGHTBRACKET)
641      return [null,str,null];
642  }
643  str = AMremoveCharsAndBlanks(str,symbol.input.length);
644  switch (symbol.ttype) {
645  case SPACE:
646    node = AMcreateElementMathML(symbol.tag);
647    node.setAttribute(symbol.atname,symbol.atval);
648    return [node,str,symbol.tag];
649  case UNDEROVER:
650    if (isIE) {
651      if (symbol.input.substr(0,4) == "\\big") {   // botch for missing symbols
652	str = "\\"+symbol.input.substr(4)+str;	   // make \bigcup = \cup etc.
653	symbol = AMgetSymbol(str);
654	symbol.ttype = UNDEROVER;
655	str = AMremoveCharsAndBlanks(str,symbol.input.length);
656      }
657    }
658    return [AMcreateMmlNode(symbol.tag,
659			document.createTextNode(symbol.output)),str,symbol.tag];
660  case CONST:
661    var output = symbol.output;
662    if (isIE) {
663      if (symbol.input == "'")
664	output = "\u2032";
665      else if (symbol.input == "''")
666	output = "\u2033";
667      else if (symbol.input == "'''")
668	output = "\u2033\u2032";
669      else if (symbol.input == "''''")
670	output = "\u2033\u2033";
671      else if (symbol.input == "\\square")
672	output = "\u25A1";	// same as \Box
673      else if (symbol.input.substr(0,5) == "\\frac") {
674						// botch for missing fractions
675	var denom = symbol.input.substr(6,1);
676	if (denom == "5" || denom == "6") {
677	  str = symbol.input.replace(/\\frac/,"\\frac ")+str;
678	  return [node,str,symbol.tag];
679	}
680      }
681    }
682    node = AMcreateMmlNode(symbol.tag,document.createTextNode(output));
683    return [node,str,symbol.tag];
684  case LONG:  // added by DRW
685    node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
686    node.setAttribute("minsize","1.5");
687    node.setAttribute("maxsize","1.5");
688    node = AMcreateMmlNode("mover",node);
689    node.appendChild(AMcreateElementMathML("mspace"));
690    return [node,str,symbol.tag];
691  case STRETCHY:  // added by DRW
692    if (isIE && symbol.input == "\\backslash")
693	symbol.output = "\\";	// doesn't expand, but then nor does "\u2216"
694    node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
695    if (symbol.input == "|" || symbol.input == "\\vert" ||
696	symbol.input == "\\|" || symbol.input == "\\Vert") {
697	  node.setAttribute("lspace","0em");
698	  node.setAttribute("rspace","0em");
699    }
700    node.setAttribute("maxsize",symbol.atval);  // don't allow to stretch here
701    if (symbol.rtag != null)
702      return [node,str,symbol.rtag];
703    else
704      return [node,str,symbol.tag];
705  case BIG:  // added by DRW
706    var atval = symbol.atval;
707    if (isIE)
708      atval = symbol.ieval;
709    symbol = AMgetSymbol(str);
710    if (symbol == null)
711	return [null,str,null];
712    str = AMremoveCharsAndBlanks(str,symbol.input.length);
713    node = AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));
714    if (isIE) {		// to get brackets to expand
715      var space = AMcreateElementMathML("mspace");
716      space.setAttribute("height",atval+"ex");
717      node = AMcreateMmlNode("mrow",node);
718      node.appendChild(space);
719    } else {		// ignored in IE
720      node.setAttribute("minsize",atval);
721      node.setAttribute("maxsize",atval);
722    }
723    return [node,str,symbol.tag];
724  case LEFTBRACKET:   //read (expr+)
725    if (symbol.input == "\\left") { // left what?
726      symbol = AMgetSymbol(str);
727      if (symbol != null) {
728	if (symbol.input == ".")
729	  symbol.invisible = true;
730	str = AMremoveCharsAndBlanks(str,symbol.input.length);
731      }
732    }
733    result = AMparseExpr(str,true,false);
734    if (symbol==null ||
735	(typeof symbol.invisible == "boolean" && symbol.invisible))
736      node = AMcreateMmlNode("mrow",result[0]);
737    else {
738      node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
739      node = AMcreateMmlNode("mrow",node);
740      node.appendChild(result[0]);
741    }
742    return [node,result[1],result[2]];
743  case MATRIX:	 //read (expr+)
744    if (symbol.input == "\\begin{array}") {
745      var mask = "";
746      symbol = AMgetSymbol(str);
747      str = AMremoveCharsAndBlanks(str,0);
748      if (symbol == null)
749	mask = "l";
750      else {
751	str = AMremoveCharsAndBlanks(str,symbol.input.length);
752	if (symbol.input != "{")
753	  mask = "l";
754	else do {
755	  symbol = AMgetSymbol(str);
756	  if (symbol != null) {
757	    str = AMremoveCharsAndBlanks(str,symbol.input.length);
758	    if (symbol.input != "}")
759	      mask = mask+symbol.input;
760	  }
761	} while (symbol != null && symbol.input != "" && symbol.input != "}");
762      }
763      result = AMparseExpr("{"+str,true,true);
764//    if (result[0]==null) return [AMcreateMmlNode("mo",
765//			   document.createTextNode(symbol.input)),str];
766      node = AMcreateMmlNode("mtable",result[0]);
767      mask = mask.replace(/l/g,"left ");
768      mask = mask.replace(/r/g,"right ");
769      mask = mask.replace(/c/g,"center ");
770      node.setAttribute("columnalign",mask);
771      node.setAttribute("displaystyle","false");
772      if (isIE)
773	return [node,result[1],null];
774// trying to get a *little* bit of space around the array
775// (IE already includes it)
776      var lspace = AMcreateElementMathML("mspace");
777      lspace.setAttribute("width","0.167em");
778      var rspace = AMcreateElementMathML("mspace");
779      rspace.setAttribute("width","0.167em");
780      var node1 = AMcreateMmlNode("mrow",lspace);
781      node1.appendChild(node);
782      node1.appendChild(rspace);
783      return [node1,result[1],null];
784    } else {	// eqnarray
785      result = AMparseExpr("{"+str,true,true);
786      node = AMcreateMmlNode("mtable",result[0]);
787      if (isIE)
788	node.setAttribute("columnspacing","0.25em"); // best in practice?
789      else
790	node.setAttribute("columnspacing","0.167em"); // correct (but ignored?)
791      node.setAttribute("columnalign","right center left");
792      node.setAttribute("displaystyle","true");
793      node = AMcreateMmlNode("mrow",node);
794      return [node,result[1],null];
795    }
796  case TEXT:
797      if (str.charAt(0)=="{") i=str.indexOf("}");
798      else i = 0;
799      if (i==-1)
800		 i = str.length;
801      st = str.slice(1,i);
802      if (st.charAt(0) == " ") {
803	node = AMcreateElementMathML("mspace");
804	node.setAttribute("width","0.33em");	// was 1ex
805	newFrag.appendChild(node);
806      }
807      newFrag.appendChild(
808        AMcreateMmlNode(symbol.tag,document.createTextNode(st)));
809      if (st.charAt(st.length-1) == " ") {
810	node = AMcreateElementMathML("mspace");
811	node.setAttribute("width","0.33em");	// was 1ex
812	newFrag.appendChild(node);
813      }
814      str = AMremoveCharsAndBlanks(str,i+1);
815      return [AMcreateMmlNode("mrow",newFrag),str,null];
816  case UNARY:
817      result = AMparseSexpr(str);
818      if (result[0]==null) return [AMcreateMmlNode(symbol.tag,
819                             document.createTextNode(symbol.output)),str];
820      if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
821	st = str.charAt(0);
822//	if (st=="^" || st=="_" || st=="/" || st=="|" || st==",") {
823	if (st=="^" || st=="_" || st==",") {
824	  return [AMcreateMmlNode(symbol.tag,
825		    document.createTextNode(symbol.output)),str,symbol.tag];
826        } else {
827	  node = AMcreateMmlNode("mrow",
828	   AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
829	  if (isIE) {
830	    var space = AMcreateElementMathML("mspace");
831	    space.setAttribute("width","0.167em");
832	    node.appendChild(space);
833	  }
834	  node.appendChild(result[0]);
835	  return [node,result[1],symbol.tag];
836        }
837      }
838      if (symbol.input == "\\sqrt") {		// sqrt
839	if (isIE) {	// set minsize, for \surd
840	  var space = AMcreateElementMathML("mspace");
841	  space.setAttribute("height","1.2ex");
842	  space.setAttribute("width","0em");	// probably no effect
843	  node = AMcreateMmlNode(symbol.tag,result[0])
844//	  node.setAttribute("minsize","1");	// ignored
845//	  node = AMcreateMmlNode("mrow",node);  // hopefully unnecessary
846	  node.appendChild(space);
847	  return [node,result[1],symbol.tag];
848	} else
849	  return [AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];
850      } else if (typeof symbol.acc == "boolean" && symbol.acc) {   // accent
851        node = AMcreateMmlNode(symbol.tag,result[0]);
852	var output = symbol.output;
853	if (isIE) {
854		if (symbol.input == "\\hat")
855			output = "\u0302";
856		else if (symbol.input == "\\widehat")
857			output = "\u005E";
858		else if (symbol.input == "\\bar")
859			output = "\u00AF";
860		else if (symbol.input == "\\grave")
861			output = "\u0300";
862		else if (symbol.input == "\\tilde")
863			output = "\u0303";
864	}
865	var node1 = AMcreateMmlNode("mo",document.createTextNode(output));
866	if (symbol.input == "\\vec" || symbol.input == "\\check")
867						// don't allow to stretch
868	    node1.setAttribute("maxsize","1.2");
869		 // why doesn't "1" work?  \vec nearly disappears in firefox
870	if (isIE && symbol.input == "\\bar")
871	    node1.setAttribute("maxsize","0.5");
872	if (symbol.input == "\\underbrace" || symbol.input == "\\underline")
873	  node1.setAttribute("accentunder","true");
874	else
875	  node1.setAttribute("accent","true");
876	node.appendChild(node1);
877	if (symbol.input == "\\overbrace" || symbol.input == "\\underbrace")
878	  node.ttype = UNDEROVER;
879	return [node,result[1],symbol.tag];
880      } else {			      // font change or displaystyle command
881        if (!isIE && typeof symbol.codes != "undefined") {
882          for (i=0; i<result[0].childNodes.length; i++)
883            if (result[0].childNodes[i].nodeName=="mi" || result[0].nodeName=="mi") {
884              st = (result[0].nodeName=="mi"?result[0].firstChild.nodeValue:
885                              result[0].childNodes[i].firstChild.nodeValue);
886              var newst = [];
887              for (var j=0; j<st.length; j++)
888                if (st.charCodeAt(j)>64 && st.charCodeAt(j)<91) newst = newst +
889                  String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);
890                else newst = newst + st.charAt(j);
891              if (result[0].nodeName=="mi")
892                result[0]=AMcreateElementMathML("mo").
893                          appendChild(document.createTextNode(newst));
894              else result[0].replaceChild(AMcreateElementMathML("mo").
895          appendChild(document.createTextNode(newst)),result[0].childNodes[i]);
896            }
897        }
898        node = AMcreateMmlNode(symbol.tag,result[0]);
899        node.setAttribute(symbol.atname,symbol.atval);
900	if (symbol.input == "\\scriptstyle" ||
901	    symbol.input == "\\scriptscriptstyle")
902		node.setAttribute("displaystyle","false");
903	return [node,result[1],symbol.tag];
904      }
905  case BINARY:
906    result = AMparseSexpr(str);
907    if (result[0]==null) return [AMcreateMmlNode("mo",
908			   document.createTextNode(symbol.input)),str,null];
909    result2 = AMparseSexpr(result[1]);
910    if (result2[0]==null) return [AMcreateMmlNode("mo",
911			   document.createTextNode(symbol.input)),str,null];
912    if (symbol.input=="\\root" || symbol.input=="\\stackrel")
913      newFrag.appendChild(result2[0]);
914    newFrag.appendChild(result[0]);
915    if (symbol.input=="\\frac") newFrag.appendChild(result2[0]);
916    return [AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];
917  case INFIX:
918    str = AMremoveCharsAndBlanks(str,symbol.input.length);
919    return [AMcreateMmlNode("mo",document.createTextNode(symbol.output)),
920	str,symbol.tag];
921  default:
922    return [AMcreateMmlNode(symbol.tag,        //its a constant
923	document.createTextNode(symbol.output)),str,symbol.tag];
924  }
925}
926
927function AMparseIexpr(str) {
928  var symbol, sym1, sym2, node, result, tag, underover;
929  str = AMremoveCharsAndBlanks(str,0);
930  sym1 = AMgetSymbol(str);
931  result = AMparseSexpr(str);
932  node = result[0];
933  str = result[1];
934  tag = result[2];
935  symbol = AMgetSymbol(str);
936  if (symbol.ttype == INFIX) {
937    str = AMremoveCharsAndBlanks(str,symbol.input.length);
938    result = AMparseSexpr(str);
939    if (result[0] == null) // show box in place of missing argument
940      result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1"));
941    str = result[1];
942    tag = result[2];
943    if (symbol.input == "_" || symbol.input == "^") {
944      sym2 = AMgetSymbol(str);
945      tag = null;	// no space between x^2 and a following sin, cos, etc.
946// This is for \underbrace and \overbrace
947      underover = ((sym1.ttype == UNDEROVER) || (node.ttype == UNDEROVER));
948//    underover = (sym1.ttype == UNDEROVER);
949      if (symbol.input == "_" && sym2.input == "^") {
950        str = AMremoveCharsAndBlanks(str,sym2.input.length);
951        var res2 = AMparseSexpr(str);
952	str = res2[1];
953	tag = res2[2];  // leave space between x_1^2 and a following sin etc.
954        node = AMcreateMmlNode((underover?"munderover":"msubsup"),node);
955        node.appendChild(result[0]);
956        node.appendChild(res2[0]);
957      } else if (symbol.input == "_") {
958	node = AMcreateMmlNode((underover?"munder":"msub"),node);
959        node.appendChild(result[0]);
960      } else {
961	node = AMcreateMmlNode((underover?"mover":"msup"),node);
962        node.appendChild(result[0]);
963      }
964      node = AMcreateMmlNode("mrow",node); // so sum does not stretch
965    } else {
966      node = AMcreateMmlNode(symbol.tag,node);
967      if (symbol.input == "\\atop" || symbol.input == "\\choose")
968	node.setAttribute("linethickness","0ex");
969      node.appendChild(result[0]);
970      if (symbol.input == "\\choose")
971	node = AMcreateMmlNode("mfenced",node);
972    }
973  }
974  return [node,str,tag];
975}
976
977function AMparseExpr(str,rightbracket,matrix) {
978  var symbol, node, result, i, tag,
979  newFrag = document.createDocumentFragment();
980  do {
981    str = AMremoveCharsAndBlanks(str,0);
982    result = AMparseIexpr(str);
983    node = result[0];
984    str = result[1];
985    tag = result[2];
986    symbol = AMgetSymbol(str);
987    if (node!=undefined) {
988      if ((tag == "mn" || tag == "mi") && symbol!=null &&
989	typeof symbol.func == "boolean" && symbol.func) {
990			// Add space before \sin in 2\sin x or x\sin x
991	  var space = AMcreateElementMathML("mspace");
992	  space.setAttribute("width","0.167em");
993	  node = AMcreateMmlNode("mrow",node);
994	  node.appendChild(space);
995      }
996      newFrag.appendChild(node);
997    }
998  } while ((symbol.ttype != RIGHTBRACKET)
999        && symbol!=null && symbol.output!="");
1000  tag = null;
1001  if (symbol.ttype == RIGHTBRACKET) {
1002    if (symbol.input == "\\right") { // right what?
1003      str = AMremoveCharsAndBlanks(str,symbol.input.length);
1004      symbol = AMgetSymbol(str);
1005      if (symbol != null && symbol.input == ".")
1006	symbol.invisible = true;
1007      if (symbol != null)
1008	tag = symbol.rtag;
1009    }
1010    if (symbol!=null)
1011      str = AMremoveCharsAndBlanks(str,symbol.input.length); // ready to return
1012    var len = newFrag.childNodes.length;
1013    if (matrix &&
1014      len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 &&
1015      newFrag.childNodes[len-2].nodeName == "mo" &&
1016      newFrag.childNodes[len-2].firstChild.nodeValue == "&") { //matrix
1017	var pos = []; // positions of ampersands
1018        var m = newFrag.childNodes.length;
1019        for (i=0; matrix && i<m; i=i+2) {
1020          pos[i] = [];
1021          node = newFrag.childNodes[i];
1022	  for (var j=0; j<node.childNodes.length; j++)
1023	    if (node.childNodes[j].firstChild.nodeValue=="&")
1024	      pos[i][pos[i].length]=j;
1025        }
1026	var row, frag, n, k, table = document.createDocumentFragment();
1027	for (i=0; i<m; i=i+2) {
1028	  row = document.createDocumentFragment();
1029	  frag = document.createDocumentFragment();
1030	  node = newFrag.firstChild; // <mrow> -&-&...&-&- </mrow>
1030
1031	  n = node.childNodes.length;
1032	  k = 0;
1033	  for (j=0; j<n; j++) {
1034	    if (typeof pos[i][k] != "undefined" && j==pos[i][k]){
1035	      node.removeChild(node.firstChild); //remove &
1036	      row.appendChild(AMcreateMmlNode("mtd",frag));
1037	      k++;
1038	    } else frag.appendChild(node.firstChild);
1039	  }
1040	  row.appendChild(AMcreateMmlNode("mtd",frag));
1041	  if (newFrag.childNodes.length>2) {
1042	    newFrag.removeChild(newFrag.firstChild); //remove <mrow> </mrow>
1043	    newFrag.removeChild(newFrag.firstChild); //remove <mo>&</mo>
1044	  }
1045	  table.appendChild(AMcreateMmlNode("mtr",row));
1046	}
1047	return [table,str];
1048    }
1049    if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
1050      node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
1051      newFrag.appendChild(node);
1052    }
1053  }
1054  return [newFrag,str,tag];
1055}
1056
1057function AMparseMath(str) {
1058  var result, node = AMcreateElementMathML("mstyle");
1059  if (mathcolor != "") node.setAttribute("mathcolor",mathcolor);
1060  if (mathfontfamily != "") node.setAttribute("fontfamily",mathfontfamily);
1061  node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);
1062  node = AMcreateMmlNode("math",node);
1063  if (showasciiformulaonhover)                      //fixed by djhsu so newline
1064    node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko
1065  if (mathfontfamily != "" && (isIE || mathfontfamily != "serif")) {
1066    var fnode = AMcreateElementXHTML("font");
1067    fnode.setAttribute("face",mathfontfamily);
1068    fnode.appendChild(node);
1069    return fnode;
1070  }
1071  return node;
1072}
1073
1074function AMstrarr2docFrag(arr, linebreaks) {
1075  var newFrag=document.createDocumentFragment();
1076  var expr = false;
1077  for (var i=0; i<arr.length; i++) {
1078    if (expr) newFrag.appendChild(AMparseMath(arr[i]));
1079    else {
1080      var arri = (linebreaks ? arr[i].split("\n\n") : [arr[i]]);
1081      newFrag.appendChild(AMcreateElementXHTML("span").
1082      appendChild(document.createTextNode(arri[0])));
1083      for (var j=1; j<arri.length; j++) {
1084        newFrag.appendChild(AMcreateElementXHTML("p"));
1085        newFrag.appendChild(AMcreateElementXHTML("span").
1086        appendChild(document.createTextNode(arri[j])));
1087      }
1088    }
1089    expr = !expr;
1090  }
1091  return newFrag;
1092}
1093
1094function AMprocessNodeR(n, linebreaks) {
1095  var mtch, str, arr, frg, i;
1096  if (n.childNodes.length == 0) {
1097   if ((n.nodeType!=8 || linebreaks) &&
1098    n.parentNode.nodeName!="form" && n.parentNode.nodeName!="FORM" &&
1099    n.parentNode.nodeName!="textarea" && n.parentNode.nodeName!="TEXTAREA" &&
1100    n.parentNode.nodeName!="pre" && n.parentNode.nodeName!="PRE") {
1101    str = n.nodeValue;
1102    if (!(str == null)) {
1103      str = str.replace(/\r\n\r\n/g,"\n\n");
1104      str = str.replace(/\x20+/g," ");
1105      str = str.replace(/\s*\r\n/g," ");
1106// DELIMITERS:
1107      mtch = (str.indexOf("\$")==-1 ? false : true);
1108      str = str.replace(/([^\\])\$/g,"$1 \$");
1109      str = str.replace(/^\$/," \$");	// in case \$ at start of string
1110      arr = str.split(" \$");
1111      for (i=0; i<arr.length; i++)
1112	arr[i]=arr[i].replace(/\\\$/g,"\$");
1113      if (arr.length>1 || mtch) {
1114        if (checkForMathML) {
1115          checkForMathML = false;
1116          var nd = AMisMathMLavailable();
1117          AMnoMathML = nd != null;
1118          if (AMnoMathML && notifyIfNoMathML)
1119            if (alertIfNoMathML)
1120              alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\n\
1121                or Firefox/Mozilla/Netscape");
1122            else AMbody.insertBefore(nd,AMbody.childNodes[0]);
1123        }
1124        if (!AMnoMathML) {
1125          frg = AMstrarr2docFrag(arr,n.nodeType==8);
1126          var len = frg.childNodes.length;
1127          n.parentNode.replaceChild(frg,n);
1128          return len-1;
1129        } else return 0;
1130      }
1131    }
1132   } else return 0;
1133  } else if (n.nodeName!="math") {
1134    for (i=0; i<n.childNodes.length; i++)
1135      i += AMprocessNodeR(n.childNodes[i], linebreaks);
1136  }
1137  return 0;
1138}
1139
1140function AMprocessNode(n, linebreaks, spanclassAM) {
1141  var frag,st;
1142  if (spanclassAM!=null) {
1143    frag = document.getElementsByTagName("span")
1144    for (var i=0;i<frag.length;i++)
1145      if (frag[i].className == "AM")
1146        AMprocessNodeR(frag[i],linebreaks);
1147  } else {
1148    try {
1149      st = n.innerHTML;
1150    } catch(err) {}
1151// DELIMITERS:
1152    if (st==null || st.indexOf("\$")!=-1)
1153      AMprocessNodeR(n,linebreaks);
1154  }
1155  if (isIE) { //needed to match size and font of formula to surrounding text
1156    frag = document.getElementsByTagName('math');
1157    for (var i=0;i<frag.length;i++) frag[i].update()
1158  }
1159}
1160
1161var AMbody;
1162var AMnoMathML = false, AMtranslated = false;
1163
1164function translate(spanclassAM) {
1165  if (!AMtranslated) { // run this only once
1166    AMtranslated = true;
1167    AMinitSymbols();
1168    AMbody = document.getElementsByTagName("body")[0];
1169    AMprocessNode(AMbody, false, spanclassAM);
1170  }
1171}
1172
1173if (isIE) { // avoid adding MathPlayer info explicitly to each webpage
1174  document.write("<object id=\"mathplayer\"\
1175  classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");
1176  document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");
1177}
1178
1179// GO1.1 Generic onload by Brothercake
1180// http://www.brothercake.com/
1181//onload function (replaces the onload="translate()" in the <body> tag)
1182function generic()
1183{
1184  translate();
1185};
1186//setup onload function
1187if(typeof window.addEventListener != 'undefined')
1188{
1189  //.. gecko, safari, konqueror and standard
1190  window.addEventListener('load', generic, false);
1191}
1192else if(typeof document.addEventListener != 'undefined')
1193{
1194  //.. opera 7
1195  document.addEventListener('load', generic, false);
1196}
1197else if(typeof window.attachEvent != 'undefined')
1198{
1199  //.. win/ie
1200  window.attachEvent('onload', generic);
1201}
1202//** remove this condition to degrade older browsers
1203else
1204{
1205  //.. mac/ie5 and anything else that gets this far
1206  //if there's an existing onload function
1207  if(typeof window.onload == 'function')
1208  {
1209    //store it
1210    var existing = onload;
1211    //add new onload handler
1212    window.onload = function()
1213    {
1214      //call existing onload function
1215      existing();
1216      //call generic onload function
1217      generic();
1218    };
1219  }
1220  else
1221  {
1222    //setup onload function
1223    window.onload = generic;
1224  }
1225}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.