1/*
2ASCIIMathML.js
3==============
4This file contains JavaScript functions to convert ASCII math notation
5to Presentation MathML. The conversion is done while the (X)HTML page
6loads, and should work with Firefox/Mozilla/Netscape 7+ and Internet
7Explorer 6+MathPlayer (http://www.dessci.com/en/products/mathplayer/).
8Just add the next line to your (X)HTML page with this file in the same folder:
9<script type="text/javascript" src="ASCIIMathML.js"></script>
10This is a convenient and inexpensive solution for authoring MathML.
11
12Version 1.4.7 Aug 14, 2005, (c) Peter Jipsen http://www.chapman.edu/~jipsen
13Latest version at http://www.chapman.edu/~jipsen/mathml/ASCIIMathML.js
14For changes see http://www.chapman.edu/~jipsen/mathml/asciimathchanges.txt
15If you use it on a webpage, please send the URL to jipsen@chapman.edu
16
17This program is free software; you can redistribute it and/or modify
18it under the terms of the GNU General Public License as published by
19the Free Software Foundation; either version 2 of the License, or (at
20your option) any later version.
21
22This program is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25General Public License (at http://www.gnu.org/copyleft/gpl.html)
26for more details.
27*/
28
29var checkForMathML = true;   // check if browser can display MathML
30var notifyIfNoMathML = true; // put note at top of page if no MathML capability
31var mathcolor = " ";       // change it to "" (to inherit) or any other color
32var mathfontfamily = "arial"; // change to "" to inherit (works in IE)
33                              // or another family (e.g. "arial")
34var displaystyle = true;      // puts limits above and below large operators
35var showasciiformulaonhover = true; // helps students learn ASCIIMath
36var decimalsign = ".";        // change to "," if you like, beware of `(1,2)`!
37var AMdelimiter1 = "$$", AMescape1 = "\\\\$"; // was $$ can use other characters
38var AMdelimiter2 = "```", AMescape2 = "\\\\\\`", AMdelimiter2regexp = "\\`";
39var doubleblankmathdelimiter = false; // if true,  x+1  is equal to `x+1`
40                                      // for IE this works only in <!--   -->
41//var separatetokens;// has been removed (email me if this is a problem)
42var isIE = document.createElementNS==null;
43
44if (document.getElementById==null)
45  alert("This webpage requires a recent browser such as\
46\nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
47
48// all further global variables start with "AM"
49
50function AMcreateElementXHTML(t) {
51  if (isIE) return document.createElement(t);
52  else return document.createElementNS("http://www.w3.org/1999/xhtml",t);
53}
54
55function AMnoMathMLNote() {
56  var nd = AMcreateElementXHTML("h3");
57  nd.setAttribute("align","center")
58  nd.appendChild(AMcreateElementXHTML("p"));
59  nd.appendChild(document.createTextNode("To view the "));
60  var an = AMcreateElementXHTML("a");
61  an.appendChild(document.createTextNode("ASCIIMathML"));
62  an.setAttribute("href","http://www.chapman.edu/~jipsen/asciimath.html");
63  nd.appendChild(an);
64  nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));
65  an = AMcreateElementXHTML("a");
66  an.appendChild(document.createTextNode("MathPlayer"));
67  an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");
68  nd.appendChild(an);
69  nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));
70  nd.appendChild(AMcreateElementXHTML("p"));
71  return nd;
72}
73
74function AMisMathMLavailable() {
75  if (navigator.appName.slice(0,8)=="Netscape")
76    if (navigator.appVersion.slice(0,1)>="5") return null;
77    else return AMnoMathMLNote();
78  else if (navigator.appName.slice(0,9)=="Microsoft")
79    try {
80        var ActiveX = new ActiveXObject("MathPlayer.Factory.1");
81        return null;
82    } catch (e) {
83        return AMnoMathMLNote();
84    }
85  else return AMnoMathMLNote();
86}
87
88// character lists for Mozilla/Netscape fonts
89var 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];
90var 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];
91var 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];
92
93var CONST = 0, UNARY = 1, BINARY = 2, INFIX = 3, LEFTBRACKET = 4,
94    RIGHTBRACKET = 5, SPACE = 6, UNDEROVER = 7, DEFINITION = 8,
95    LEFTRIGHT = 9, TEXT = 10; // token types
96
97var AMsqrt = {input:"sqrt", tag:"msqrt", output:"sqrt", tex:null, ttype:UNARY},
98  AMroot  = {input:"root", tag:"mroot", output:"root", tex:null, ttype:BINARY},
99  AMfrac  = {input:"frac", tag:"mfrac", output:"/",    tex:null, ttype:BINARY},
100  AMdiv   = {input:"/",    tag:"mfrac", output:"/",    tex:null, ttype:INFIX},
101  AMover  = {input:"stackrel", tag:"mover", output:"stackrel", tex:null, ttype:BINARY},
102  AMsub   = {input:"_",    tag:"msub",  output:"_",    tex:null, ttype:INFIX},
103  AMsup   = {input:"^",    tag:"msup",  output:"^",    tex:null, ttype:INFIX},
104  AMtext  = {input:"text", tag:"mtext", output:"text", tex:null, ttype:TEXT},
105  AMmbox  = {input:"mbox", tag:"mtext", output:"mbox", tex:null, ttype:TEXT},
106  AMquote = {input:"\"",   tag:"mtext", output:"mbox", tex:null, ttype:TEXT};
107
108var AMsymbols = [
109//some greek symbols
110{input:"alpha",  tag:"mi", output:"\u03B1", tex:null, ttype:CONST},
111{input:"beta",   tag:"mi", output:"\u03B2", tex:null, ttype:CONST},
112{input:"chi",    tag:"mi", output:"\u03C7", tex:null, ttype:CONST},
113{input:"delta",  tag:"mi", output:"\u03B4", tex:null, ttype:CONST},
114{input:"Delta",  tag:"mo", output:"\u0394", tex:null, ttype:CONST},
115{input:"epsi",   tag:"mi", output:"\u03B5", tex:"epsilon", ttype:CONST},
116{input:"varepsilon", tag:"mi", output:"\u025B", tex:null, ttype:CONST},
117{input:"eta",    tag:"mi", output:"\u03B7", tex:null, ttype:CONST},
118{input:"gamma",  tag:"mi", output:"\u03B3", tex:null, ttype:CONST},
119{input:"Gamma",  tag:"mo", output:"\u0393", tex:null, ttype:CONST},
120{input:"iota",   tag:"mi", output:"\u03B9", tex:null, ttype:CONST},
121{input:"kappa",  tag:"mi", output:"\u03BA", tex:null, ttype:CONST},
122{input:"lambda", tag:"mi", output:"\u03BB", tex:null, ttype:CONST},
123{input:"Lambda", tag:"mo", output:"\u039B", tex:null, ttype:CONST},
124{input:"mu",     tag:"mi", output:"\u03BC", tex:null, ttype:CONST},
125{input:"nu",     tag:"mi", output:"\u03BD", tex:null, ttype:CONST},
126{input:"omega",  tag:"mi", output:"\u03C9", tex:null, ttype:CONST},
127{input:"Omega",  tag:"mo", output:"\u03A9", tex:null, ttype:CONST},
128{input:"phi",    tag:"mi", output:"\u03C6", tex:null, ttype:CONST},
129{input:"varphi", tag:"mi", output:"\u03D5", tex:null, ttype:CONST},
130{input:"Phi",    tag:"mo", output:"\u03A6", tex:null, ttype:CONST},
131{input:"pi",     tag:"mi", output:"\u03C0", tex:null, ttype:CONST},
132{input:"Pi",     tag:"mo", output:"\u03A0", tex:null, ttype:CONST},
133{input:"psi",    tag:"mi", output:"\u03C8", tex:null, ttype:CONST},
134{input:"Psi",    tag:"mi", output:"\u03A8", tex:null, ttype:CONST},
135{input:"rho",    tag:"mi", output:"\u03C1", tex:null, ttype:CONST},
136{input:"sigma",  tag:"mi", output:"\u03C3", tex:null, ttype:CONST},
137{input:"Sigma",  tag:"mo", output:"\u03A3", tex:null, ttype:CONST},
138{input:"tau",    tag:"mi", output:"\u03C4", tex:null, ttype:CONST},
139{input:"theta",  tag:"mi", output:"\u03B8", tex:null, ttype:CONST},
140{input:"vartheta", tag:"mi", output:"\u03D1", tex:null, ttype:CONST},
141{input:"Theta",  tag:"mo", output:"\u0398", tex:null, ttype:CONST},
142{input:"upsilon", tag:"mi", output:"\u03C5", tex:null, ttype:CONST},
143{input:"xi",     tag:"mi", output:"\u03BE", tex:null, ttype:CONST},
144{input:"Xi",     tag:"mo", output:"\u039E", tex:null, ttype:CONST},
145{input:"zeta",   tag:"mi", output:"\u03B6", tex:null, ttype:CONST},
146
147//binary operation symbols
148{input:"*",  tag:"mo", output:"\u22C5", tex:"cdot", ttype:CONST},
149{input:"**", tag:"mo", output:"\u22C6", tex:"star", ttype:CONST},
150{input:"//", tag:"mo", output:"/",      tex:null, ttype:CONST},
151{input:"\\\\", tag:"mo", output:"\\",   tex:"backslash", ttype:CONST},
152{input:"setminus", tag:"mo", output:"\\", tex:null, ttype:CONST},
153{input:"xx", tag:"mo", output:"\u00D7", tex:"times", ttype:CONST},
154{input:"-:", tag:"mo", output:"\u00F7", tex:"divide", ttype:CONST},
155{input:"@",  tag:"mo", output:"\u2218", tex:"circ", ttype:CONST},
156{input:"o+", tag:"mo", output:"\u2295", tex:"oplus", ttype:CONST},
157{input:"ox", tag:"mo", output:"\u2297", tex:"otimes", ttype:CONST},
158{input:"o.", tag:"mo", output:"\u2299", tex:"odot", ttype:CONST},
159{input:"sum", tag:"mo", output:"\u2211", tex:null, ttype:UNDEROVER},
160{input:"prod", tag:"mo", output:"\u220F", tex:null, ttype:UNDEROVER},
161{input:"^^",  tag:"mo", output:"\u2227", tex:"wedge", ttype:CONST},
162{input:"^^^", tag:"mo", output:"\u22C0", tex:"bigwedge", ttype:UNDEROVER},
163{input:"vv",  tag:"mo", output:"\u2228", tex:"vee", ttype:CONST},
164{input:"vvv", tag:"mo", output:"\u22C1", tex:"bigvee", ttype:UNDEROVER},
165{input:"nn",  tag:"mo", output:"\u2229", tex:"cap", ttype:CONST},
166{input:"nnn", tag:"mo", output:"\u22C2", tex:"bigcap", ttype:UNDEROVER},
167{input:"uu",  tag:"mo", output:"\u222A", tex:"cup", ttype:CONST},
168{input:"uuu", tag:"mo", output:"\u22C3", tex:"bigcup", ttype:UNDEROVER},
169
170//binary relation symbols
171{input:"!=",  tag:"mo", output:"\u2260", tex:"ne", ttype:CONST},
172{input:":=",  tag:"mo", output:":=",     tex:null, ttype:CONST},
173{input:"lt",  tag:"mo", output:"<",      tex:null, ttype:CONST},
174{input:"<=",  tag:"mo", output:"\u2264", tex:"le", ttype:CONST},
175{input:"lt=", tag:"mo", output:"\u2264", tex:"leq", ttype:CONST},
176{input:">=",  tag:"mo", output:"\u2265", tex:"ge", ttype:CONST},
177{input:"geq", tag:"mo", output:"\u2265", tex:null, ttype:CONST},
178{input:"-<",  tag:"mo", output:"\u227A", tex:"prec", ttype:CONST},
179{input:"-lt", tag:"mo", output:"\u227A", tex:null, ttype:CONST},
180{input:">-",  tag:"mo", output:"\u227B", tex:"succ", ttype:CONST},
181{input:"in",  tag:"mo", output:"\u2208", tex:null, ttype:CONST},
182{input:"!in", tag:"mo", output:"\u2209", tex:"notin", ttype:CONST},
183{input:"sub", tag:"mo", output:"\u2282", tex:"subset", ttype:CONST},
184{input:"sup", tag:"mo", output:"\u2283", tex:"supset", ttype:CONST},
185{input:"sube", tag:"mo", output:"\u2286", tex:"subseteq", ttype:CONST},
186{input:"supe", tag:"mo", output:"\u2287", tex:"supseteq", ttype:CONST},
187{input:"-=",  tag:"mo", output:"\u2261", tex:"equiv", ttype:CONST},
188{input:"~=",  tag:"mo", output:"\u2245", tex:"cong", ttype:CONST},
189{input:"~~",  tag:"mo", output:"\u2248", tex:"approx", ttype:CONST},
190{input:"prop", tag:"mo", output:"\u221D", tex:"propto", ttype:CONST},
191
192//logical symbols
193{input:"and", tag:"mtext", output:"and", tex:null, ttype:SPACE},
194{input:"or",  tag:"mtext", output:"or",  tex:null, ttype:SPACE},
195{input:"not", tag:"mo", output:"\u00AC", tex:"neg", ttype:CONST},
196{input:"=>",  tag:"mo", output:"\u21D2", tex:"implies", ttype:CONST},
197{input:"if",  tag:"mo", output:"if",     tex:null, ttype:SPACE},
198{input:"<=>", tag:"mo", output:"\u21D4", tex:"iff", ttype:CONST},
199{input:"AA",  tag:"mo", output:"\u2200", tex:"forall", ttype:CONST},
200{input:"EE",  tag:"mo", output:"\u2203", tex:"exists", ttype:CONST},
201{input:"_|_", tag:"mo", output:"\u22A5", tex:"bot", ttype:CONST},
202{input:"TT",  tag:"mo", output:"\u22A4", tex:"top", ttype:CONST},
203{input:"|--",  tag:"mo", output:"\u22A2", tex:"vdash", ttype:CONST},
204{input:"|==",  tag:"mo", output:"\u22A8", tex:"models", ttype:CONST},
205
206//grouping brackets
207{input:"(", tag:"mo", output:"(", tex:null, ttype:LEFTBRACKET},
208{input:")", tag:"mo", output:")", tex:null, ttype:RIGHTBRACKET},
209{input:"[", tag:"mo", output:"[", tex:null, ttype:LEFTBRACKET},
210{input:"]", tag:"mo", output:"]", tex:null, ttype:RIGHTBRACKET},
211{input:"{", tag:"mo", output:"{", tex:null, ttype:LEFTBRACKET},
212{input:"}", tag:"mo", output:"}", tex:null, ttype:RIGHTBRACKET},
213{input:"|", tag:"mo", output:"|", tex:null, ttype:LEFTRIGHT},
214//{input:"||", tag:"mo", output:"||", tex:null, ttype:LEFTRIGHT},
215{input:"(:", tag:"mo", output:"\u2329", tex:"langle", ttype:LEFTBRACKET},
216{input:":)", tag:"mo", output:"\u232A", tex:"rangle", ttype:RIGHTBRACKET},
217{input:"<<", tag:"mo", output:"\u2329", tex:null, ttype:LEFTBRACKET},
218{input:">>", tag:"mo", output:"\u232A", tex:null, ttype:RIGHTBRACKET},
219{input:"{:", tag:"mo", output:"{:", tex:null, ttype:LEFTBRACKET, invisible:true},
220{input:":}", tag:"mo", output:":}", tex:null, ttype:RIGHTBRACKET, invisible:true},
221
222//miscellaneous symbols
223{input:"int",  tag:"mo", output:"\u222B", tex:null, ttype:CONST},
224{input:"dx",   tag:"mi", output:"{:d x:}", tex:null, ttype:DEFINITION},
225{input:"dy",   tag:"mi", output:"{:d y:}", tex:null, ttype:DEFINITION},
226{input:"dz",   tag:"mi", output:"{:d z:}", tex:null, ttype:DEFINITION},
227{input:"dt",   tag:"mi", output:"{:d t:}", tex:null, ttype:DEFINITION},
228{input:"oint", tag:"mo", output:"\u222E", tex:null, ttype:CONST},
229{input:"del",  tag:"mo", output:"\u2202", tex:"partial", ttype:CONST},
230{input:"grad", tag:"mo", output:"\u2207", tex:"nabla", ttype:CONST},
231{input:"+-",   tag:"mo", output:"\u00B1", tex:"pm", ttype:CONST},
232{input:"O/",   tag:"mo", output:"\u2205", tex:"emptyset", ttype:CONST},
233{input:"oo",   tag:"mo", output:"\u221E", tex:"infty", ttype:CONST},
234{input:"aleph", tag:"mo", output:"\u2135", tex:null, ttype:CONST},
235{input:"...",  tag:"mo", output:"...",    tex:"ldots", ttype:CONST},
236{input:":.",  tag:"mo", output:"\u2234",  tex:"therefore", ttype:CONST},
237{input:"/_",  tag:"mo", output:"\u2220",  tex:"angle", ttype:CONST},
238{input:"\\ ",  tag:"mo", output:"\u00A0", tex:null, ttype:CONST},
239{input:"quad", tag:"mo", output:"\u00A0\u00A0", tex:null, ttype:CONST},
240{input:"qquad", tag:"mo", output:"\u00A0\u00A0\u00A0\u00A0", tex:null, ttype:CONST},
241{input:"cdots", tag:"mo", output:"\u22EF", tex:null, ttype:CONST},
242{input:"vdots", tag:"mo", output:"\u22EE", tex:null, ttype:CONST},
243{input:"ddots", tag:"mo", output:"\u22F1", tex:null, ttype:CONST},
244{input:"diamond", tag:"mo", output:"\u22C4", tex:null, ttype:CONST},
245{input:"square", tag:"mo", output:"\u25A1", tex:null, ttype:CONST},
246{input:"|__", tag:"mo", output:"\u230A",  tex:"lfloor", ttype:CONST},
247{input:"__|", tag:"mo", output:"\u230B",  tex:"rfloor", ttype:CONST},
248{input:"|~", tag:"mo", output:"\u2308",  tex:"lceiling", ttype:CONST},
249{input:"~|", tag:"mo", output:"\u2309",  tex:"rceiling", ttype:CONST},
250{input:"CC",  tag:"mo", output:"\u2102", tex:null, ttype:CONST},
251{input:"NN",  tag:"mo", output:"\u2115", tex:null, ttype:CONST},
252{input:"QQ",  tag:"mo", output:"\u211A", tex:null, ttype:CONST},
253{input:"RR",  tag:"mo", output:"\u211D", tex:null, ttype:CONST},
254{input:"ZZ",  tag:"mo", output:"\u2124", tex:null, ttype:CONST},
255{input:"f",   tag:"mi", output:"f",      tex:null, ttype:UNARY, func:true},
256{input:"g",   tag:"mi", output:"g",      tex:null, ttype:UNARY, func:true},
257
258//standard functions
259{input:"lim",  tag:"mo", output:"lim", tex:null, ttype:UNDEROVER},
260{input:"Lim",  tag:"mo", output:"Lim", tex:null, ttype:UNDEROVER},
261{input:"sin",  tag:"mo", output:"sin", tex:null, ttype:UNARY, func:true},
262{input:"cos",  tag:"mo", output:"cos", tex:null, ttype:UNARY, func:true},
263{input:"tan",  tag:"mo", output:"tan", tex:null, ttype:UNARY, func:true},
264{input:"sinh", tag:"mo", output:"sinh", tex:null, ttype:UNARY, func:true},
265{input:"cosh", tag:"mo", output:"cosh", tex:null, ttype:UNARY, func:true},
266{input:"tanh", tag:"mo", output:"tanh", tex:null, ttype:UNARY, func:true},
267{input:"cot",  tag:"mo", output:"cot", tex:null, ttype:UNARY, func:true},
268{input:"sec",  tag:"mo", output:"sec", tex:null, ttype:UNARY, func:true},
269{input:"csc",  tag:"mo", output:"csc", tex:null, ttype:UNARY, func:true},
270{input:"log",  tag:"mo", output:"log", tex:null, ttype:UNARY, func:true},
271{input:"ln",   tag:"mo", output:"ln",  tex:null, ttype:UNARY, func:true},
272{input:"det",  tag:"mo", output:"det", tex:null, ttype:UNARY, func:true},
273{input:"dim",  tag:"mo", output:"dim", tex:null, ttype:CONST},
274{input:"mod",  tag:"mo", output:"mod", tex:null, ttype:CONST},
275{input:"gcd",  tag:"mo", output:"gcd", tex:null, ttype:UNARY, func:true},
276{input:"lcm",  tag:"mo", output:"lcm", tex:null, ttype:UNARY, func:true},
277{input:"lub",  tag:"mo", output:"lub", tex:null, ttype:CONST},
278{input:"glb",  tag:"mo", output:"glb", tex:null, ttype:CONST},
279{input:"min",  tag:"mo", output:"min", tex:null, ttype:UNDEROVER},
280{input:"max",  tag:"mo", output:"max", tex:null, ttype:UNDEROVER},
281
282//arrows
283{input:"uarr", tag:"mo", output:"\u2191", tex:"uparrow", ttype:CONST},
284{input:"darr", tag:"mo", output:"\u2193", tex:"downarrow", ttype:CONST},
285{input:"rarr", tag:"mo", output:"\u2192", tex:"rightarrow", ttype:CONST},
286{input:"->",   tag:"mo", output:"\u2192", tex:"to", ttype:CONST},
287{input:"|->",  tag:"mo", output:"\u21A6", tex:"mapsto", ttype:CONST},
288{input:"larr", tag:"mo", output:"\u2190", tex:"leftarrow", ttype:CONST},
289{input:"harr", tag:"mo", output:"\u2194", tex:"leftrightarrow", ttype:CONST},
290{input:"rArr", tag:"mo", output:"\u21D2", tex:"Rightarrow", ttype:CONST},
291{input:"lArr", tag:"mo", output:"\u21D0", tex:"Leftarrow", ttype:CONST},
292{input:"hArr", tag:"mo", output:"\u21D4", tex:"Leftrightarrow", ttype:CONST},
293
294//commands with argument
295AMsqrt, AMroot, AMfrac, AMdiv, AMover, AMsub, AMsup,
296{input:"hat", tag:"mover", output:"\u005E", tex:null, ttype:UNARY, acc:true},
297{input:"bar", tag:"mover", output:"\u00AF", tex:"overline", ttype:UNARY, acc:true},
298{input:"vec", tag:"mover", output:"\u2192", tex:null, ttype:UNARY, acc:true},
299{input:"dot", tag:"mover", output:".",      tex:null, ttype:UNARY, acc:true},
300{input:"ddot", tag:"mover", output:"..",    tex:null, ttype:UNARY, acc:true},
301{input:"ul", tag:"munder", output:"\u0332", tex:"underline", ttype:UNARY, acc:true},
302AMtext, AMmbox, AMquote,
303{input:"bb", tag:"mstyle", atname:"fontweight", atval:"bold", output:"bb", tex:null, ttype:UNARY},
304{input:"mathbf", tag:"mstyle", atname:"fontweight", atval:"bold", output:"mathbf", tex:null, ttype:UNARY},
305{input:"sf", tag:"mstyle", atname:"fontfamily", atval:"sans-serif", output:"sf", tex:null, ttype:UNARY},
306{input:"mathsf", tag:"mstyle", atname:"fontfamily", atval:"sans-serif", output:"mathsf", tex:null, ttype:UNARY},
307{input:"bbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"bbb", tex:null, ttype:UNARY, codes:AMbbb},
308{input:"mathbb", tag:"mstyle", atname:"mathvariant", atval:"double-struck", output:"mathbb", tex:null, ttype:UNARY, codes:AMbbb},
309{input:"cc",  tag:"mstyle", atname:"mathvariant", atval:"script", output:"cc", tex:null, ttype:UNARY, codes:AMcal},
310{input:"mathcal", tag:"mstyle", atname:"mathvariant", atval:"script", output:"mathcal", tex:null, ttype:UNARY, codes:AMcal},
311{input:"tt",  tag:"mstyle", atname:"fontfamily", atval:"monospace", output:"tt", tex:null, ttype:UNARY},
312{input:"mathtt", tag:"mstyle", atname:"fontfamily", atval:"monospace", output:"mathtt", tex:null, ttype:UNARY},
313{input:"fr",  tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"fr", tex:null, ttype:UNARY, codes:AMfrk},
314{input:"mathfrak",  tag:"mstyle", atname:"mathvariant", atval:"fraktur", output:"mathfrak", tex:null, ttype:UNARY, codes:AMfrk}
315];
316
317function compareNames(s1,s2) {
318  if (s1.input > s2.input) return 1
319  else return -1;
320}
321
322var AMnames = []; //list of input symbols
323
324function AMinitSymbols() {
325  var texsymbols = [], i;
326  for (i=0; i<AMsymbols.length; i++)
327    if (AMsymbols[i].tex)
328      texsymbols[texsymbols.length] = {input:AMsymbols[i].tex,
329        tag:AMsymbols[i].tag, output:AMsymbols[i].output, ttype:AMsymbols[i].ttype};
330  AMsymbols = AMsymbols.concat(texsymbols);
331  AMsymbols.sort(compareNames);
332  for (i=0; i<AMsymbols.length; i++) AMnames[i] = AMsymbols[i].input;
333}
334
335var AMmathml = "http://www.w3.org/1998/Math/MathML";
336
337function AMcreateElementMathML(t) {
338  if (isIE) return document.createElement("m:"+t);
339  else return document.createElementNS(AMmathml,t);
340}
341
342function AMcreateMmlNode(t,frag) {
343//  var node = AMcreateElementMathML(name);
344  if (isIE) var node = document.createElement("m:"+t);
345  else var node = document.createElementNS(AMmathml,t);
346  node.appendChild(frag);
347  return node;
348}
349
350function newcommand(oldstr,newstr) {
351  AMsymbols = AMsymbols.concat([{input:oldstr, tag:"mo", output:newstr,
352                                 tex:null, ttype:DEFINITION}]);
353}
354
355function AMremoveCharsAndBlanks(str,n) {
356//remove n characters and any following blanks
357  var st;
358  if (str.charAt(n)=="\\" && str.charAt(n+1)!="\\" && str.charAt(n+1)!=" ")
359    st = str.slice(n+1);
360  else st = str.slice(n);
361  for (var i=0; i<st.length && st.charCodeAt(i)<=32; i=i+1);
362  return st.slice(i);
363}
364
365function AMposition(arr, str, n) {
366// return position >=n where str appears or would be inserted
367// assumes arr is sorted
368  if (n==0) {
369    var h,m;
370    n = -1;
371    h = arr.length;
372    while (n+1<h) {
373      m = (n+h) >> 1;
374      if (arr[m]<str) n = m; else h = m;
375    }
376    return h;
377  } else
378    for (var i=n; i<arr.length && arr[i]<str; i++);
379  return i; // i=arr.length || arr[i]>=str
380}
381
382function AMgetSymbol(str) {
383//return maximal initial substring of str that appears in names
384//return null if there is none
385  var k = 0; //new pos
386  var j = 0; //old pos
387  var mk; //match pos
388  var st;
389  var tagst;
390  var match = "";
391  var more = true;
392  for (var i=1; i<=str.length && more; i++) {
393    st = str.slice(0,i); //initial substring of length i
394    j = k;
395    k = AMposition(AMnames, st, j);
396    if (k<AMnames.length && str.slice(0,AMnames[k].length)==AMnames[k]){
397      match = AMnames[k];
398      mk = k;
399      i = match.length;
400    }
401    more = k<AMnames.length && str.slice(0,AMnames[k].length)>=AMnames[k];
402  }
403  AMpreviousSymbol=AMcurrentSymbol;
404  if (match!=""){
405    AMcurrentSymbol=AMsymbols[mk].ttype;
406    return AMsymbols[mk];
407  }
408// if str[0] is a digit or - return maxsubstring of digits.digits
409  AMcurrentSymbol=CONST;
410  k = 1;
411  st = str.slice(0,1);
412  var integ = true;
413  while ("0"<=st && st<="9" && k<=str.length) {
414    st = str.slice(k,k+1);
415    k++;
416  }
417  if (st == decimalsign) {
418    st = str.slice(k,k+1);
419    if ("0"<=st && st<="9") {
420      integ = false;
421      k++;
422      while ("0"<=st && st<="9" && k<=str.length) {
423        st = str.slice(k,k+1);
424        k++;
425      }
426    }
427  }
428  if ((integ && k>1) || k>2) {
429    st = str.slice(0,k-1);
430    tagst = "mn";
431  } else {
432    k = 2;
433    st = str.slice(0,1); //take 1 character
434    tagst = (("A">st || st>"Z") && ("a">st || st>"z")?"mo":"mi");
435  }
436  if (st=="-" && AMpreviousSymbol==INFIX)
437    return {input:st, tag:tagst, output:st, ttype:UNARY, func:true};
438  return {input:st, tag:tagst, output:st, ttype:CONST};
439}
440
441function AMremoveBrackets(node) {
442  var st;
443  if (node.nodeName=="mrow") {
444    st = node.firstChild.firstChild.nodeValue;
445    if (st=="(" || st=="[" || st=="{") node.removeChild(node.firstChild);
446  }
447  if (node.nodeName=="mrow") {
448    st = node.lastChild.firstChild.nodeValue;
449    if (st==")" || st=="]" || st=="}") node.removeChild(node.lastChild);
450  }
451}
452
453/*Parsing ASCII math expressions with the following grammar
454v ::= [A-Za-z] | greek letters | numbers | other constant symbols
455u ::= sqrt | text | bb | other unary symbols for font commands
456b ::= frac | root | stackrel         binary symbols
457l ::= ( | [ | { | (: | {:            left brackets
458r ::= ) | ] | } | :) | :}            right brackets
459S ::= v | lEr | uS | bSS             Simple expression
460I ::= S_S | S^S | S_S^S | S          Intermediate expression
461E ::= IE | I/I                       Expression
462Each terminal symbol is translated into a corresponding mathml node.*/
463
464var AMnestingDepth,AMpreviousSymbol,AMcurrentSymbol;
465
466function AMparseSexpr(str) { //parses str and returns [node,tailstr]
467  var symbol, node, result, i, st,// rightvert = false,
468    newFrag = document.createDocumentFragment();
469  str = AMremoveCharsAndBlanks(str,0);
470  symbol = AMgetSymbol(str);             //either a token or a bracket or empty
471  if (symbol == null || symbol.ttype == RIGHTBRACKET && AMnestingDepth > 0) {
472    return [null,str];
473  }
474  if (symbol.ttype == DEFINITION) {
475    str = symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);
476    symbol = AMgetSymbol(str);
477  }
478  switch (symbol.ttype) {
479  case UNDEROVER:
480  case CONST:
481    str = AMremoveCharsAndBlanks(str,symbol.input.length);
482    return [AMcreateMmlNode(symbol.tag,        //its a constant
483                             document.createTextNode(symbol.output)),str];
484  case LEFTBRACKET:   //read (expr+)
485    AMnestingDepth++;
486    str = AMremoveCharsAndBlanks(str,symbol.input.length);
487    result = AMparseExpr(str,true);
488    AMnestingDepth--;
489    if (typeof symbol.invisible == "boolean" && symbol.invisible)
490      node = AMcreateMmlNode("mrow",result[0]);
491    else {
492      node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
493      node = AMcreateMmlNode("mrow",node);
494      node.appendChild(result[0]);
495    }
496    return [node,result[1]];
497  case TEXT:
498      if (symbol!=AMquote) str = AMremoveCharsAndBlanks(str,symbol.input.length);
499      if (str.charAt(0)=="{") i=str.indexOf("}");
500      else if (str.charAt(0)=="(") i=str.indexOf(")");
501      else if (str.charAt(0)=="[") i=str.indexOf("]");
502      else if (symbol==AMquote) i=str.slice(1).indexOf("\"")+1;
503      else i = 0;
504      if (i==-1) i = str.length;
505      st = str.slice(1,i);
506      if (st.charAt(0) == " ") {
507        node = AMcreateElementMathML("mspace");
508        node.setAttribute("width","1ex");
509        newFrag.appendChild(node);
510      }
511      newFrag.appendChild(
512        AMcreateMmlNode(symbol.tag,document.createTextNode(st)));
513      if (st.charAt(st.length-1) == " ") {
514        node = AMcreateElementMathML("mspace");
515        node.setAttribute("width","1ex");
516        newFrag.appendChild(node);
517      }
518      str = AMremoveCharsAndBlanks(str,i+1);
519      return [AMcreateMmlNode("mrow",newFrag),str];
520  case UNARY:
521      str = AMremoveCharsAndBlanks(str,symbol.input.length);
522      result = AMparseSexpr(str);
523      if (result[0]==null) return [AMcreateMmlNode(symbol.tag,
524                             document.createTextNode(symbol.output)),str];
525      if (typeof symbol.func == "boolean" && symbol.func) { // functions hack
526        st = str.charAt(0);
527        if (st=="^" || st=="_" || st=="/" || st=="|") {
528          return [AMcreateMmlNode(symbol.tag,
529                    document.createTextNode(symbol.output)),str];
530        } else {
531          node = AMcreateMmlNode("mrow",
532           AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
533          node.appendChild(result[0]);
534          return [node,result[1]];
535        }
536      }
537      AMremoveBrackets(result[0]);
538      if (symbol.input == "sqrt") {           // sqrt
539        return [AMcreateMmlNode(symbol.tag,result[0]),result[1]];
540      } else if (typeof symbol.acc == "boolean" && symbol.acc) {   // accent
541        node = AMcreateMmlNode(symbol.tag,result[0]);
542        node.appendChild(AMcreateMmlNode("mo",document.createTextNode(symbol.output)));
543        return [node,result[1]];
544      } else {                        // font change command
545        if (!isIE && typeof symbol.codes != "undefined") {
546          for (i=0; i<result[0].childNodes.length; i++)
547            if (result[0].childNodes[i].nodeName=="mi" || result[0].nodeName=="mi") {
548              st = (result[0].nodeName=="mi"?result[0].firstChild.nodeValue:
549                              result[0].childNodes[i].firstChild.nodeValue);
550              var newst = [];
551              for (var j=0; j<st.length; j++)
552                if (st.charCodeAt(j)>64 && st.charCodeAt(j)<91) newst = newst +
553                  String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);
554                else newst = newst + st.charAt(j);
555              if (result[0].nodeName=="mi")
556                result[0]=AMcreateElementMathML("mo").
557                          appendChild(document.createTextNode(newst));
558              else result[0].replaceChild(AMcreateElementMathML("mo").
559          appendChild(document.createTextNode(newst)),result[0].childNodes[i]);
560            }
561        }
562        node = AMcreateMmlNode(symbol.tag,result[0]);
563        node.setAttribute(symbol.atname,symbol.atval);
564        return [node,result[1]];
565      }
566  case BINARY:
567    str = AMremoveCharsAndBlanks(str,symbol.input.length);
568    result = AMparseSexpr(str);
569    if (result[0]==null) return [AMcreateMmlNode("mo",
570                           document.createTextNode(symbol.input)),str];
571    AMremoveBrackets(result[0]);
572    var result2 = AMparseSexpr(result[1]);
573    if (result2[0]==null) return [AMcreateMmlNode("mo",
574                           document.createTextNode(symbol.input)),str];
575    AMremoveBrackets(result2[0]);
576    if (symbol.input=="root" || symbol.input=="stackrel")
577      newFrag.appendChild(result2[0]);
578    newFrag.appendChild(result[0]);
579    if (symbol.input=="frac") newFrag.appendChild(result2[0]);
580    return [AMcreateMmlNode(symbol.tag,newFrag),result2[1]];
581  case INFIX:
582    str = AMremoveCharsAndBlanks(str,symbol.input.length);
583    return [AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str];
584  case SPACE:
585    str = AMremoveCharsAndBlanks(str,symbol.input.length);
586    node = AMcreateElementMathML("mspace");
587    node.setAttribute("width","1ex");
588    newFrag.appendChild(node);
589    newFrag.appendChild(
590      AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));
591    node = AMcreateElementMathML("mspace");
592    node.setAttribute("width","1ex");
593    newFrag.appendChild(node);
594    return [AMcreateMmlNode("mrow",newFrag),str];
595  case LEFTRIGHT:
596//    if (rightvert) return [null,str]; else rightvert = true;
597    AMnestingDepth++;
598    str = AMremoveCharsAndBlanks(str,symbol.input.length);
599    result = AMparseExpr(str,false);
600    AMnestingDepth--;
601    var st = "";
602    if (result[0].lastChild!=null)
603      st = result[0].lastChild.firstChild.nodeValue;
604//alert(result[0].lastChild+"***"+st);
605    if (st == "|") { // its an absolute value subterm
606      node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
607      node = AMcreateMmlNode("mrow",node);
608      node.appendChild(result[0]);
609      return [node,result[1]];
610    } else { // the "|" is a \mid
611      node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
612      node = AMcreateMmlNode("mrow",node);
613      return [node,str];
614    }
615  default:
616//alert("default");
617    str = AMremoveCharsAndBlanks(str,symbol.input.length);
618    return [AMcreateMmlNode(symbol.tag,        //its a constant
619                             document.createTextNode(symbol.output)),str];
620  }
621}
622
623function AMparseIexpr(str) {
624  var symbol, sym1, sym2, node, result, underover;
625  str = AMremoveCharsAndBlanks(str,0);
626  sym1 = AMgetSymbol(str);
627  result = AMparseSexpr(str);
628  node = result[0];
629  str = result[1];
630  symbol = AMgetSymbol(str);
631  if (symbol.ttype == INFIX && symbol.input != "/") {
632    str = AMremoveCharsAndBlanks(str,symbol.input.length);
633//    if (symbol.input == "/") result = AMparseIexpr(str); else ...
634    result = AMparseSexpr(str);
635    if (result[0] == null) // show box in place of missing argument
636      result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1"));
637    else AMremoveBrackets(result[0]);
638    str = result[1];
639//    if (symbol.input == "/") AMremoveBrackets(node);
640    if (symbol.input == "_") {
641      sym2 = AMgetSymbol(str);
642      underover = (sym1.ttype == UNDEROVER);
643      if (sym2.input == "^") {
644        str = AMremoveCharsAndBlanks(str,sym2.input.length);
645        var res2 = AMparseSexpr(str);
646        AMremoveBrackets(res2[0]);
647        str = res2[1];
648        node = AMcreateMmlNode((underover?"munderover":"msubsup"),node);
649        node.appendChild(result[0]);
650        node.appendChild(res2[0]);
651        node = AMcreateMmlNode("mrow",node); // so sum does not stretch
652      } else {
653        node = AMcreateMmlNode((underover?"munder":"msub"),node);
654        node.appendChild(result[0]);
655      }
656    } else {
657      node = AMcreateMmlNode(symbol.tag,node);
658      node.appendChild(result[0]);
659    }
660  }
661  return [node,str];
662}
663
664function AMparseExpr(str,rightbracket) {
665  var symbol, node, result, i, nodeList = [],
666  newFrag = document.createDocumentFragment();
667  do {
668    str = AMremoveCharsAndBlanks(str,0);
669    result = AMparseIexpr(str);
670    node = result[0];
671    str = result[1];
672    symbol = AMgetSymbol(str);
673    if (symbol.ttype == INFIX && symbol.input == "/") {
674      str = AMremoveCharsAndBlanks(str,symbol.input.length);
675      result = AMparseIexpr(str);
676      if (result[0] == null) // show box in place of missing argument
677        result[0] = AMcreateMmlNode("mo",document.createTextNode("\u25A1"));
678      else AMremoveBrackets(result[0]);
679      str = result[1];
680      AMremoveBrackets(node);
681      node = AMcreateMmlNode(symbol.tag,node);
682      node.appendChild(result[0]);
683      newFrag.appendChild(node);
684      symbol = AMgetSymbol(str);
685    }
686    else if (node!=undefined) newFrag.appendChild(node);
687  } while ((symbol.ttype != RIGHTBRACKET &&
688           (symbol.ttype != LEFTRIGHT || rightbracket)
689           || AMnestingDepth == 0) && symbol!=null && symbol.output!="");
690  if (symbol.ttype == RIGHTBRACKET || symbol.ttype == LEFTRIGHT) {
691//    if (AMnestingDepth > 0) AMnestingDepth--;
692    var len = newFrag.childNodes.length;
693    if (len>0 && newFrag.childNodes[len-1].nodeName == "mrow" && len>1 &&
694      newFrag.childNodes[len-2].nodeName == "mo" &&
695      newFrag.childNodes[len-2].firstChild.nodeValue == ",") { //matrix
696      var right = newFrag.childNodes[len-1].lastChild.firstChild.nodeValue;
697      if (right==")" || right=="]") {
698        var left = newFrag.childNodes[len-1].firstChild.firstChild.nodeValue;
699        if (left=="(" && right==")" && symbol.output != "}" ||
700            left=="[" && right=="]") {
701        var pos = []; // positions of commas
702        var matrix = true;
703        var m = newFrag.childNodes.length;
704        for (i=0; matrix && i<m; i=i+2) {
705          pos[i] = [];
706          node = newFrag.childNodes[i];
707          if (matrix) matrix = node.nodeName=="mrow" &&
708            (i==m-1 || node.nextSibling.nodeName=="mo" &&
709            node.nextSibling.firstChild.nodeValue==",")&&
710            node.firstChild.firstChild.nodeValue==left &&
711            node.lastChild.firstChild.nodeValue==right;
712          if (matrix)
713            for (var j=0; j<node.childNodes.length; j++)
714              if (node.childNodes[j].firstChild.nodeValue==",")
715                pos[i][pos[i].length]=j;
716          if (matrix && i>1) matrix = pos[i].length == pos[i-2].length;
717        }
718        if (matrix) {
719          var row, frag, n, k, table = document.createDocumentFragment();
720          for (i=0; i<m; i=i+2) {
721            row = document.createDocumentFragment();
722            frag = document.createDocumentFragment();
723            node = newFrag.firstChild; // <mrow>(-,-,...,-,-)</mrow>
724            n = node.childNodes.length;
725            k = 0;
726            node.removeChild(node.firstChild); //remove (
727            for (j=1; j<n-1; j++) {
728              if (typeof pos[i][k] != "undefined" && j==pos[i][k]){
729                node.removeChild(node.firstChild); //remove ,
730                row.appendChild(AMcreateMmlNode("mtd",frag));
731                k++;
732              } else frag.appendChild(node.firstChild);
733            }
734            row.appendChild(AMcreateMmlNode("mtd",frag));
735            if (newFrag.childNodes.length>2) {
736              newFrag.removeChild(newFrag.firstChild); //remove <mrow>)</mrow>
737              newFrag.removeChild(newFrag.firstChild); //remove <mo>,</mo>
738            }
739            table.appendChild(AMcreateMmlNode("mtr",row));
740          }
741          node = AMcreateMmlNode("mtable",table);
742          if (typeof symbol.invisible == "boolean" && symbol.invisible) node.setAttribute("columnalign","left");
743          newFrag.replaceChild(node,newFrag.firstChild);
744        }
745       }
746      }
747    }
748    str = AMremoveCharsAndBlanks(str,symbol.input.length);
749    if (typeof symbol.invisible != "boolean" || !symbol.invisible) {
750      node = AMcreateMmlNode("mo",document.createTextNode(symbol.output));
751      newFrag.appendChild(node);
752    }
753  }
754  return [newFrag,str];
755}
756
757function AMparseMath(str) {
758  var result, node = AMcreateElementMathML("mstyle");
759  if (mathcolor != "") node.setAttribute("mathcolor",mathcolor);
760  if (displaystyle) node.setAttribute("displaystyle","true");
761  if (mathfontfamily != "") node.setAttribute("fontfamily",mathfontfamily);
762  AMnestingDepth = 0;
763  node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false)[0]);
764  node = AMcreateMmlNode("math",node);
765  if (showasciiformulaonhover)                      //fixed by djhsu so newline
766    node.setAttribute("title",str.replace(/\s+/g," "));//does not show in Gecko
767  if (mathfontfamily != "" && (isIE || mathfontfamily != "serif")) {
768    var fnode = AMcreateElementXHTML("font");
769    fnode.setAttribute("face",mathfontfamily);
770    fnode.appendChild(node);
771    return fnode;
772  }
773  return node;
774}
775
776function AMstrarr2docFrag(arr, linebreaks) {
777  var newFrag=document.createDocumentFragment();
778  var expr = false;
779  for (var i=0; i<arr.length; i++) {
780    if (expr) newFrag.appendChild(AMparseMath(arr[i]));
781    else {
782      var arri = (linebreaks ? arr[i].split("\n\n") : [arr[i]]);
783      newFrag.appendChild(AMcreateElementXHTML("span").
784      appendChild(document.createTextNode(arri[0])));
785      for (var j=1; j<arri.length; j++) {
786        newFrag.appendChild(AMcreateElementXHTML("p"));
787        newFrag.appendChild(AMcreateElementXHTML("span").
788        appendChild(document.createTextNode(arri[j])));
789      }
790    }
791    expr = !expr;
792  }
793  return newFrag;
794}
795
796function AMprocessNodeR(n, linebreaks) {
797  var mtch, str, arr, frg, i;
798  if (n.childNodes.length == 0) {
799   if ((n.nodeType!=8 || linebreaks) &&
800    n.parentNode.nodeName!="form" && n.parentNode.nodeName!="FORM" &&
801    n.parentNode.nodeName!="textarea" && n.parentNode.nodeName!="TEXTAREA" &&
802    n.parentNode.nodeName!="pre" && n.parentNode.nodeName!="PRE") {
803    str = n.nodeValue;
804    if (!(str == null)) {
805      str = str.replace(/\r\n\r\n/g,"\n\n");
806      if (doubleblankmathdelimiter) {
807        str = str.replace(/\x20\x20\./g," "+AMdelimiter1+".");
808        str = str.replace(/\x20\x20,/g," "+AMdelimiter1+",");
809        str = str.replace(/\x20\x20/g," "+AMdelimiter1+" ");
810      }
811      str = str.replace(/\x20+/g," ");
812      str = str.replace(/\s*\r\n/g," ");
813      mtch = false;
814      str = str.replace(new RegExp(AMescape2, "g"),
815              function(st){mtch=true;return "AMescape2"});
816      str = str.replace(new RegExp(AMescape1, "g"),
817              function(st){mtch=true;return "AMescape1"});
818      str = str.replace(new RegExp(AMdelimiter2regexp, "g"),AMdelimiter1);
819      arr = str.split(AMdelimiter1);
820      for (i=0; i<arr.length; i++)
821        arr[i]=arr[i].replace(/AMescape2/g,AMdelimiter2).
822                      replace(/AMescape1/g,AMdelimiter1);
823      if (arr.length>1 || mtch) {
824        if (checkForMathML) {
825          checkForMathML = false;
826          var nd = AMisMathMLavailable();
827          AMnoMathML = nd != null
828          if (AMnoMathML && notifyIfNoMathML)
829            AMbody.insertBefore(nd,AMbody.childNodes[0]);
830        }
831        if (!AMnoMathML) {
832          frg = AMstrarr2docFrag(arr,n.nodeType==8);
833          var len = frg.childNodes.length;
834          n.parentNode.replaceChild(frg,n);
835          return len-1;
836        } else return 0;
837      }
838    }
839   } else return 0;
840  } else if (n.nodeName!="math") {
841    for (i=0; i<n.childNodes.length; i++)
842      i += AMprocessNodeR(n.childNodes[i], linebreaks);
843  }
844  return 0;
845}
846
847function AMprocessNode(n, linebreaks, spanclassAM) {
848  var frag,st;
849  if (spanclassAM!=null) {
850    frag = document.getElementsByTagName("span")
851    for (var i=0;i<frag.length;i++)
852      if (frag[i].className == "AM")
853        AMprocessNodeR(frag[i],linebreaks);
854  } else {
855    try {
856      st = n.innerHTML;
857    } catch(err) {}
858    if (st==null ||
859        st.indexOf(AMdelimiter1)!=-1 || st.indexOf(AMdelimiter2)!=-1)
860      AMprocessNodeR(n,linebreaks);
861  }
862  if (isIE) { //needed to match size and font of formula to surrounding text
863    frag = document.getElementsByTagName('math');
864    for (var i=0;i<frag.length;i++) frag[i].update()
865  }
866}
867
868var AMbody;
869var AMnoMathML = false, AMtranslated = false;
870
871function translate(spanclassAM) {
872  if (!AMtranslated) { // run this only once
873    AMtranslated = true;
874    AMinitSymbols();
875    AMbody = document.getElementsByTagName("body")[0];
876    AMprocessNode(AMbody, false, spanclassAM);
877  }
878}
879
880if (isIE) { // avoid adding MathPlayer info explicitly to each webpage
881  document.write("<object id=\"mathplayer\"\
882  classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");
883  document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");
884}
885
886// GO1.1 Generic onload by Brothercake
887// http://www.brothercake.com/
888//onload function (replaces the onload="translate()" in the <body> tag)
889function generic()
890{
891  translate();
892};
893//setup onload function
894if(typeof window.addEventListener != 'undefined')
895{
896  //.. gecko, safari, konqueror and standard
897  window.addEventListener('load', generic, false);
898}
899else if(typeof document.addEventListener != 'undefined')
900{
901  //.. opera 7
902  document.addEventListener('load', generic, false);
903}
904else if(typeof window.attachEvent != 'undefined')
905{
906  //.. win/ie
907  window.attachEvent('onload', generic);
908}
909//** remove this condition to degrade older browsers
910else
911{
912  //.. mac/ie5 and anything else that gets this far
913  //if there's an existing onload function
914  if(typeof window.onload == 'function')
915  {
916    //store it
917    var existing = onload;
918    //add new onload handler
919    window.onload = function()
920    {
921      //call existing onload function
922      existing();
923      //call generic onload function
924      generic();
925    };
926  }
927  else
928  {
929    //setup onload function
930    window.onload = generic;
931  }
932}
933