User:CBM2/jsMath/jsMath.js

/*****************************************************************************

*

* jsMath: Mathematics on the Web

*

* This jsMath package makes it possible to display mathematics in HTML pages

* that are viewable by a wide range of browsers on both the Mac and the IBM PC,

* including browsers that don't process MathML. See

*

* http://www.math.union.edu/locate/jsMath

*

* for the latest version, and for documentation on how to use jsMath.

*

* Copyright 2004-2010 by Davide P. Cervone

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*

*****************************************************************************/

/*

* Prevent running everything again if this file is loaded twice

*/

if (!window.jsMath || !window.jsMath.loaded) {

var jsMath_old = window.jsMath; // save user customizations

//

// debugging routine

//

/*

* function ShowObject (obj,spaces) {

* var s = ''; if (!spaces) {spaces = ""}

* for (var i in obj) {

* if (obj[i] != null) {

* if (typeof(obj[i]) == "object") {

* s += spaces + i + ": {\n"

* + ShowObject(obj[i],spaces + ' ')

* + spaces + "}\n";

* } else if (typeof(obj[i]) != "function") {

* s += spaces + i + ': ' + obj[i] + "\n";

* }

* }

* }

* return s;

* }

*/

/***************************************************************************/

//

// Check for DOM support

//

if (!document.getElementById || !document.childNodes || !document.createElement) {

alert('The mathematics on this page requires W3C DOM support in its JavaScript. '

+ 'Unfortunately, your browser doesn\'t seem to have this.');

} else {

/***************************************************************************/

window.jsMath = {

version: "3.6e", // change this if you edit the file, but don't edit this file

document: document, // the document loading jsMath

window: window, // the window of the of loading document

platform: (navigator.platform.match(/Mac/) ? "mac" :

navigator.platform.match(/Win/) ? "pc" : "unix"),

// Font sizes for \tiny, \small, etc. (must match styles below)

sizes: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249],

//

// The styles needed for the TeX fonts and other jsMath elements

//

styles: {

'.math': { // unprocessed mathematics

'font-family': 'serif',

'font-style': 'normal',

'font-weight': 'normal'

},

'.typeset': { // final typeset mathematics

'font-family': 'serif',

'font-style': 'normal',

'font-weight': 'normal',

'line-height': 'normal',

'text-indent': '0px',

'white-space': 'normal'

},

'.typeset .normal': { // \hbox contents style

'font-family': 'serif',

'font-style': 'normal',

'font-weight': 'normal'

},

'div.typeset': { // display mathematics

'text-align': 'center',

margin: '1em 0px'

},

'span.typeset': { // in-line mathematics

'text-align': 'left'

},

'.typeset span': { // prevent outside CSS from setting these

'text-align': 'left',

border: '0px',

margin: '0px',

padding: '0px'

},

'a .typeset img, .typeset a img': { // links in image mode

border: '0px',

'border-bottom': '1px solid blue;'

},

// Font sizes

'.typeset .size0': {'font-size': '50%'}, // tiny (\scriptscriptsize)

'.typeset .size1': {'font-size': '60%'}, // (50% of \large for consistency)

'.typeset .size2': {'font-size': '70%'}, // scriptsize

'.typeset .size3': {'font-size': '85%'}, // small (70% of \large for consistency)

'.typeset .size4': {'font-size': '100%'}, // normalsize

'.typeset .size5': {'font-size': '120%'}, // large

'.typeset .size6': {'font-size': '144%'}, // Large

'.typeset .size7': {'font-size': '173%'}, // LARGE

'.typeset .size8': {'font-size': '207%'}, // huge

'.typeset .size9': {'font-size': '249%'}, // Huge

// TeX fonts

'.typeset .cmr10': {'font-family': 'jsMath-cmr10, serif'},

'.typeset .cmbx10': {'font-family': 'jsMath-cmbx10, jsMath-cmr10'},

'.typeset .cmti10': {'font-family': 'jsMath-cmti10, jsMath-cmr10'},

'.typeset .cmmi10': {'font-family': 'jsMath-cmmi10'},

'.typeset .cmsy10': {'font-family': 'jsMath-cmsy10'},

'.typeset .cmex10': {'font-family': 'jsMath-cmex10'},

'.typeset .textit': {'font-family': 'serif', 'font-style': 'italic'},

'.typeset .textbf': {'font-family': 'serif', 'font-weight': 'bold'},

'.typeset .link': {'text-decoration': 'none'}, // links in mathematics

'.typeset .error': { // in-line error messages

'font-size': '90%',

'font-style': 'italic',

'background-color': '#FFFFCC',

padding: '1px',

border: '1px solid #CC0000'

},

'.typeset .blank': { // internal use

display: 'inline-block',

overflow: 'hidden',

border: '0px none',

width: '0px',

height: '0px'

},

'.typeset .spacer': { // internal use

display: 'inline-block'

},

'#jsMath_hiddenSpan': { // used for measuring BBoxes

visibility: 'hidden',

position: 'absolute',

top: '0px',

left: '0px',

'line-height': 'normal',

'text-indent': '0px'

},

'#jsMath_message': { // percentage complete message

position: 'fixed',

bottom: '1px',

left: '2px',

'background-color': '#E6E6E6',

border: 'solid 1px #959595',

margin: '0px',

padding: '1px 8px',

'z-index': '102',

color: 'black',

'font-size': 'small',

width: 'auto'

},

'#jsMath_panel': { // control panel

position: 'fixed',

bottom: '1.75em',

right: '1.5em',

padding: '.8em 1.6em',

'background-color': '#DDDDDD',

border: 'outset 2px',

'z-index': '103',

width: 'auto',

color: 'black',

'font-size': '10pt',

'font-style': 'normal'

},

'#jsMath_panel .disabled': {color: '#888888'}, // disabled items in the panel

'#jsMath_panel .infoLink': {'font-size': '85%'}, // links to web pages

// avoid CSS polution from outside the panel

'#jsMath_panel *': {

'font-size': 'inherit',

'font-style': 'inherit',

'font-family': 'inherit',

'line-height': 'normal'

},

'#jsMath_panel div': {'background-color': 'inherit', color: 'inherit'},

'#jsMath_panel span': {'background-color': 'inherit', color: 'inherit'},

'#jsMath_panel td': {

border: '0px', padding: '0px', margin: '0px',

'background-color': 'inherit', color: 'inherit'

},

'#jsMath_panel tr': {

border: '0px', padding: '0px', margin: '0px',

'background-color': 'inherit', color: 'inherit'

},

'#jsMath_panel table': {

border: '0px', padding: '0px', margin: '0px',

'background-color': 'inherit', color: 'inherit',

height: 'auto', width: 'auto'

},

'#jsMath_button': { // the jsMath floating button (to open control panel)

position: 'fixed',

bottom: '1px',

right: '2px',

'background-color': 'white',

border: 'solid 1px #959595',

margin: '0px',

padding: '0px 3px 1px 3px',

'z-index': '102',

color: 'black',

'text-decoration': 'none',

'font-size': 'x-small',

width: 'auto',

cursor: 'hand'

},

'#jsMath_button *': {

padding: '0px', border: '0px', margin: '0px', 'line-height': 'normal',

'font-size': 'inherit', 'font-style': 'inherit', 'font-family': 'inherit'

},

'#jsMath_global': {'font-style': 'italic'}, // 'global' in jsMath button

'#jsMath_noFont .message': { // missing font message window

'text-align': 'center',

padding: '.8em 1.6em',

border: '3px solid #DD0000',

'background-color': '#FFF8F8',

color: '#AA0000',

'font-size': 'small',

width: 'auto'

},

'#jsMath_noFont .link': {

padding: '0px 5px 2px 5px',

border: '2px outset',

'background-color': '#E8E8E8',

color: 'black',

'font-size': '80%',

width: 'auto',

cursor: 'hand'

},

'#jsMath_PrintWarning .message': { // warning on print pages

'text-align': 'center',

padding: '.8em 1.6em',

border: '3px solid #DD0000',

'background-color': '#FFF8F8',

color: '#AA0000',

'font-size': 'x-small',

width: 'auto'

},

'@media print': {

'#jsMath_button': {display: 'none'},

'#jsMath_Warning': {display: 'none'}

},

'@media screen': {

'#jsMath_PrintWarning': {display:'none'}

}

},

/***************************************************************************/

/*

* Get a jsMath DOM element

*/

Element: function (name) {return jsMath.document.getElementById('jsMath_'+name)},

/*

* Get the width and height (in pixels) of an HTML string

*/

BBoxFor: function (s) {

this.hidden.innerHTML =

''+s+'';

var math = (jsMath.Browser.msieBBoxBug ? this.hidden.firstChild.firstChild : this.hidden);

var bbox = {w: math.offsetWidth, h: this.hidden.offsetHeight};

this.hidden.innerHTML = '';

return bbox;

},

/*

* Get the width and height (in ems) of an HTML string.

* Check the cache first to see if we've already measured it.

*/

EmBoxFor: function (s) {

var cache = jsMath.Global.cache.R;

if (!cache[this.em]) {cache[this.em] = {}}

if (!cache[this.em][s]) {

var bbox = this.BBoxFor(s);

cache[this.em][s] = {w: bbox.w/this.em, h: bbox.h/this.em};

}

return cache[this.em][s];

},

/*

* Initialize jsMath. This determines the em size, and a variety

* of other parameters used throughout jsMath.

*/

Init: function () {

if (jsMath.Setup.inited != 1) {

if (!jsMath.Setup.inited) {jsMath.Setup.Body()}

if (jsMath.Setup.inited != 1) {

if (jsMath.Setup.inited == -100) return;

alert("It looks like jsMath failed to set up properly (error code "

+ jsMath.Setup.inited + "). "

+ "I will try to keep going, but it could get ugly.");

jsMath.Setup.inited = 1;

}

}

this.em = this.CurrentEm();

var cache = jsMath.Global.cache.B;

if (!cache[this.em]) {

cache[this.em] = {};

cache[this.em].bb = this.BBoxFor('x'); var hh = cache[this.em].bb.h;

cache[this.em].d = this.BBoxFor('x'+jsMath.HTML.Strut(hh/this.em)).h - hh;

}

jsMath.Browser.italicCorrection = cache[this.em].ic;

var bb = cache[this.em].bb; var h = bb.h; var d = cache[this.em].d

this.h = (h-d)/this.em; this.d = d/this.em;

this.hd = this.h + this.d;

this.Setup.TeXfonts();

var x_height = this.EmBoxFor('M').w/2;

this.TeX.M_height = x_height*(26/14);

this.TeX.h = this.h; this.TeX.d = this.d; this.TeX.hd = this.hd;

this.Img.Scale();

if (!this.initialized) {

this.Setup.Sizes();

this.Img.UpdateFonts();

}

// factor for \big and its brethren

this.p_height = (this.TeX.cmex10[0].h + this.TeX.cmex10[0].d) / .85;

this.initialized = 1;

},

/*

* Get the x size and if it has changed, reinitialize the sizes

*/

ReInit: function () {

if (this.em != this.CurrentEm()) {this.Init()}

},

/*

* Find the em size in effect at the current text location

*/

CurrentEm: function () {

var em = this.BBoxFor('').w/27;

if (em > 0) {return em}

// handle older browsers

return this.BBoxFor('').w/13;

},

/*

* Mark jsMath as loaded and copy any user-provided overrides

*/

Loaded: function () {

if (jsMath_old) {

var override = ['Process', 'ProcessBeforeShowing','ProcessElement',

'ConvertTeX','ConvertTeX2','ConvertLaTeX','ConvertCustom',

'CustomSearch', 'Synchronize', 'Macro', 'document'];

for (var i = 0; i < override.length; i++) {

if (jsMath_old[override[i]]) {delete jsMath_old[override[i]]}

}

}

if (jsMath_old) {this.Insert(jsMath,jsMath_old)}

jsMath_old = null;

jsMath.loaded = 1;

},

/*

* Manage JavaScript objects:

*

* Add: add/replace items in an object

* Insert: add items to an object

* Package: add items to an object prototype

*/

Add: function (dst,src) {for (var id in src) {dst[id] = src[id]}},

Insert: function (dst,src) {

for (var id in src) {

if (dst[id] && typeof(src[id]) == 'object'

&& (typeof(dst[id]) == 'object'

|| typeof(dst[id]) == 'function')) {

this.Insert(dst[id],src[id]);

} else {

dst[id] = src[id];

}

}

},

Package: function (obj,def) {this.Insert(obj.prototype,def)}

};

/***************************************************************************/

/*

* Implements items associated with the global cache.

*

* This object will be replaced by a global version when

* (and if) jsMath-global.html is loaded.

*/

jsMath.Global = {

isLocal: 1, // a local copy if jsMath-global.html hasn't been loaded

cache: {T: {}, D: {}, R: {}, B: {}},

/*

* Clear the global (or local) cache

*/

ClearCache: function () {jsMath.Global.cache = {T: {}, D: {}, R: {}, B: {}}},

/*

* Initiate global mode

*/

GoGlobal: function (cookie) {

var url = String(jsMath.window.location);

var c = (jsMath.isCHMmode ? '#' : '?');

if (cookie) {url = url.replace(/\?.*/,'') + '?' + cookie}

jsMath.Controls.Reload(jsMath.root + "jsMath-global.html" + c +escape(url));

},

/*

* Check if we need to go to global mode

*/

Init: function () {

if (jsMath.Controls.cookie.global == "always" && !jsMath.noGoGlobal) {

if (navigator.accentColorName) return; // OmniWeb crashes on GoGlobal

if (!jsMath.window) {jsMath.window = window}

jsMath.Controls.loaded = 1;

jsMath.Controls.defaults.hiddenGlobal = null;

this.GoGlobal(jsMath.Controls.SetCookie(2));

}

},

/*

* Try to register with a global.html window that contains us

*/

Register: function () {

var parent = jsMath.window.parent;

if (!jsMath.isCHMmode)

{jsMath.isCHMmode = (jsMath.window.location.protocol == 'mk:')}

try {

if (!jsMath.isCHMmode) this.Domain();

if (parent.jsMath && parent.jsMath.isGlobal)

{parent.jsMath.Register(jsMath.window)}

} catch (err) {jsMath.noGoGlobal = 1}

},

/*

* If we're not the parent window, try to set the domain to

* match the parent's domain (so we can use the Global data

* if the surrounding frame is a Global frame).

*/

Domain: function () {

// MSIE/Mac can't do domain changes, so don't bother trying

if (navigator.appName == 'Microsoft Internet Explorer' &&

jsMath.platform == 'mac' && navigator.userProfile != null) return;

// MSIE/PC can do domain change, but gets mixed up if we don't

// find a domain that works, and then can't look in window.location

// any longer. So don't try, since we can't afford to leave it confused.

if (jsMath.document.all && !jsMath.window.opera) return;

if (window == parent) return;

var oldDomain = jsMath.document.domain;

try {

while (true) {

try {if (parent.document.title != null) return} catch (err) {}

if (!document.domain.match(/\..*\./)) break;

jsMath.document.domain = jsMath.document.domain.replace(/^[^.]*\./,'');

}

} catch (err) {}

jsMath.document.domain = oldDomain;

}

};

/***************************************************************************/

/*

*

* Implement loading of remote scripts using XMLHttpRequest, if

* possible, otherwise use a hidden IFRAME and fake it. That

* method runs asynchronously, which causes lots of headaches.

* Solve these using Push command, which queues actions

* until files have loaded.

*/

jsMath.Script = {

request: null, // the XMLHttpRequest object

/*

* Create the XMLHttpRequest object, if we can.

* Otherwise, use the iframe-based fallback method.

*/

Init: function () {

if (!(jsMath.Controls.cookie.asynch && jsMath.Controls.cookie.progress)) {

if (window.XMLHttpRequest) {

try {this.request = new XMLHttpRequest} catch (err) {}

// MSIE and FireFox3 can't use xmlRequest on local files,

// but we don't have jsMath.browser yet to tell, so use this check

if (this.request && jsMath.root.match(/^file:\/\//)) {

try {

this.request.open("GET",jsMath.root+"jsMath.js",false);

this.request.send(null);

} catch (err) {

this.request = null;

// Firefox3 has window.postMessage for inter-window communication.

// It can be used to handle the new file:// security model,

// so set up the listener.

if (window.postMessage && window.addEventListener) {

this.mustPost = 1;

jsMath.window.addEventListener("message",jsMath.Post.Listener,false);

}

}

}

}

if (!this.request && window.ActiveXObject && !this.mustPost) {

var xml = ["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0",

"MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];

for (var i = 0; i < xml.length && !this.request; i++) {

try {this.request = new ActiveXObject(xml[i])} catch (err) {}

}

}

}

//

// Use the delayed-script fallback for MSIE/Mac and old versions

// of several browsers (Opera 7.5, OmniWeb 4.5).

//

if (!this.request || jsMath.Setup.domainChanged)

{this.Load = this.delayedLoad; this.needsBody = 1}

},

/*

* Load a script and evaluate it in the window's context

*/

Load: function (url,show) {

if (show) {

jsMath.Message.Set("Loading "+url);

jsMath.Script.Delay(1);

jsMath.Script.Push(this,'xmlRequest',url);

jsMath.Script.Push(jsMath.Message,'Clear');

} else {

jsMath.Script.Push(this,'xmlRequest',url);

}

},

/*

* Load a URL and run the contents of the file

*/

xmlRequest: function (url) {

this.blocking = 1;

// this.debug('xmlRequest: '+url);

try {

this.request.open("GET",url,false);

this.request.send(null);

} catch (err) {

this.blocking = 0;

if (jsMath.Translate.restart && jsMath.Translate.asynchronous) {return ""}

throw Error("jsMath can't load the file '"+url+"'\n"

+ "Message: "+err.message);

}

if (this.request.status != null && (this.request.status >= 400 || this.request.status < 0)) {

// Do we need to deal with redirected links?

this.blocking = 0;

if (jsMath.Translate.restart && jsMath.Translate.asynchronous) {return ""}

throw Error("jsMath can't load the file '"+url+"'\n"

+ "Error status: "+this.request.status);

}

if (!url.match(/\.js$/)) {return(this.request.responseText)}

var tmpQueue = this.queue; this.queue = [];

// this.debug('xml Eval ['+tmpQueue.length+']');

jsMath.window.eval(this.request.responseText);

// this.debug('xml Done ['+this.queue.length+' + '+tmpQueue.length+']');

this.blocking = 0; this.queue = this.queue.concat(tmpQueue);

this.Process();

return "";

},

/********************************************************************

*

* Implement asynchronous loading and execution of scripts

* (via hidden IFRAME) interleved with other JavaScript commands

* that must be synchronized with the file loading. (Basically, this

* is for MSIE/Mac and Opera 7.5, which don't have XMLHttpRequest.)

*/

cancelTimeout: 30*1000, // delay for canceling load (30 sec)

blocking: 0, // true when an asynchronous action is being performed

cancelTimer: null, // timer to cancel load if it takes too long

needsBody: 0, // true if loading files requires BODY to be present

queue: [], // the stack of pending actions

/*

* Provide mechanism for synchronizing with the asynchronous jsMath

* file-loading mechanism. 'code' can be a string or a function.

*/

Synchronize: function (code,data) {

if (typeof(code) != 'string') {jsMath.Script.Push(null,code,data)}

else {jsMath.Script.Push(jsMath.window,'eval',code)}

},

/*

* Queue a function to be processed.

* If nothing is being loaded, do the pending commands.

*/

Push: function (object,method,data) {

// this.debug('Pushing: '+method+' at '+this.queue.length); // debug

this.queue[this.queue.length] = [object,method,data];

if (!(this.blocking || (this.needsBody && !jsMath.document.body))) this.Process();

},

/*

* Do any pending functions (stopping if a file load is started)

*/

Process: function () {

while (this.queue.length && !this.blocking) {

var call = this.queue[0]; this.queue = this.queue.slice(1);

var savedQueue = this.SaveQueue();

var object = call[0]; var method = call[1]; var data = call[2];

// this.debug('Calling: '+method+' ['+savedQueue.length+']'); // debug

if (object) {object[method](data)} else if (method) {method(data)}

// this.debug('Done: '+method+' ['+this.queue.length+' + '+savedQueue.length+'] ('+this.blocking+')'); // debug

this.RestoreQueue(savedQueue);

}

},

/*

* Allows pushes to occur at the FRONT of the queue

* (so a command acts as a single unit, including anything

* that it pushes on to the command stack)

*/

SaveQueue: function () {

var queue = this.queue;

this.queue = [];

return queue;

},

RestoreQueue: function (queue) {

this.queue = this.queue.concat(queue);

},

/*

* Handle loading of scripts that run asynchronously

*/

delayedLoad: function (url) {

// this.debug('Loading: '+url);

this.Push(this,'startLoad',url);

},

startLoad: function (url) {

var iframe = jsMath.document.createElement('iframe');

iframe.style.visibility = 'hidden';

iframe.style.position = 'absolute';

iframe.style.width = '0px';

iframe.style.height = '0px';

if (jsMath.document.body.firstChild) {

jsMath.document.body.insertBefore(iframe,jsMath.document.body.firstChild);

} else {

jsMath.document.body.appendChild(iframe);

}

this.blocking = 1; this.url = url;

if (url.substr(0,jsMath.root.length) == jsMath.root)

{url = url.substr(jsMath.root.length)}

jsMath.Message.Set("Loading "+url);

this.cancelTimer = setTimeout('jsMath.Script.cancelLoad()',this.cancelTimeout);

if (this.mustPost) {iframe.src = jsMath.Post.startLoad(url,iframe)}

else if (url.match(/\.js$/)) {iframe.src = jsMath.root+"jsMath-loader.html"}

else {iframe.src = this.url}

},

endLoad: function (action) {

if (this.cancelTimer) {clearTimeout(this.cancelTimer); this.cancelTimer = null}

jsMath.Post.endLoad();

jsMath.Message.Clear();

if (action != 'cancel') {this.blocking = 0; this.Process()}

},

Start: function () {

// this.debug('Starting: ['+this.queue.length+'] '+this.url);

this.tmpQueue = this.queue; this.queue = [];

},

End: function () {

// this.debug('Ending: ['+this.queue.length+' + '+this.tmpQueue.length+'] '+this.url);

this.queue = this.queue.concat(this.tmpQueue); delete this.tmpQueue;

},

/*

* If the loading takes too long, cancel it and end the load.

*/

cancelLoad: function (message,delay) {

if (this.cancelTimer) {clearTimeout(this.cancelTimer); this.cancelTimer = null}

if (message == null) {message = "Can't load file"}

if (delay == null) {delay = 2000}

jsMath.Message.Set(message);

setTimeout('jsMath.Script.endLoad("cancel")',delay);

},

/*

* Perform a delay (to let the browser catch up)

*/

Delay: function (time) {

this.blocking = 1;

setTimeout('jsMath.Script.endDelay()',time);

},

endDelay: function () {

// this.debug('endDelay');

this.blocking = 0;

this.Process();

},

/*

* Load an image and wait for it

* (so MSIE won't load extra copies of it)

*/

imageCount: 0,

WaitForImage: function (file) {

this.blocking = 1; this.imageCount++;

if (this.img == null) {this.img = []}

var img = new Image(); this.img[this.img.length] = img;

img.onload = function () {if (--jsMath.Script.imageCount == 0) jsMath.Script.endDelay()}

img.onerror = img.onload; img.onabort = img.onload;

img.src = file;

},

/*

* The code uncompressor

*/

Uncompress: function (data) {

for (var k = 0; k < data.length; k++) {

var d = data[k]; var n = d.length;

for (var i = 0; i < n; i++) {if (typeof(d[i]) == 'number') {d[i] = d[d[i]]}}

data[k] = d.join('');

}

window.eval(data.join(''));

}

/*

* for debugging the event queue

*/

/*

* ,debug: function (message) {

* if (jsMath.document.body && jsMath.window.debug) {jsMath.window.debug(message)}

* else {alert(message)}

* }

*/

};

/***************************************************************************/

/*

* Handle window.postMessage() events in Firefox3

*/

jsMath.Post = {

window: null, // iframe we are listening to

Listener: function (event) {

if (event.source != jsMath.Post.window) return;

var domain = event.origin.replace(/^file:\/\//,'');

var ddomain = document.domain.replace(/^file:\/\//,'');

if (domain == null || domain == "" || domain == "null") {domain = "localhost"}

if (ddomain == null || ddomain == "" || ddomain == "null") {ddomain = "localhost"}

if (domain != ddomain || !event.data.substr(0,6).match(/jsM(CP|LD|AL):/)) return;

var type = event.data.substr(6,3).replace(/ /g,'');

var message = event.data.substr(10);

if (jsMath.Post.Commands[type]) (jsMath.Post.Commands[type])(message);

// cancel event?

},

/*

* Commands that can be performed by the listener

*/

Commands: {

SCR: function (message) {jsMath.window.eval(message)},

ERR: function (message) {jsMath.Script.cancelLoad(message,3000)},

BGN: function (message) {jsMath.Script.Start()},

END: function (message) {if (message) jsMath.Script.End(); jsMath.Script.endLoad()}

},

startLoad: function (url,iframe) {

this.window = iframe.contentWindow;

if (!url.match(/\.js$/)) {return jsMath.root+url}

return jsMath.root+"jsMath-loader-post.html?"+url;

},

endLoad: function () {this.window = null}

};

/***************************************************************************/

/*

* Message and screen blanking facility

*/

jsMath.Message = {

blank: null, // the div to blank out the screen

message: null, // the div for the messages

text: null, // the text node for messages

clear: null, // timer for clearing message

/*

* Create the elements needed for the message box

*/

Init: function () {

if (!jsMath.document.body || !jsMath.Controls.cookie.progress) return;

this.message = jsMath.Element('message');

if (!this.message) {

if (jsMath.Setup.stylesReady) {

this.message = jsMath.Setup.DIV('message',{visibility:'hidden'},jsMath.fixedDiv);

} else {

this.message = jsMath.Setup.DIV('message',{

visibility:'hidden', position:'absolute', bottom:'1px', left:'2px',

backgroundColor:'#E6E6E6', border:'solid 1px #959595',

margin:'0px', padding:'1px 8px', zIndex:102,

color:'black', fontSize:'small', width:'auto'

},jsMath.fixedDiv);

}

}

this.text = jsMath.document.createTextNode('');

this.message.appendChild(this.text);

this.message.onmousedown = jsMath.Translate.Cancel;

},

/*

* Set the contents of the message box, or use the window status line

*/

Set: function (text,canCancel) {

if (this.clear) {clearTimeout(this.clear); this.clear = null}

if (jsMath.Controls.cookie.progress) {

if (!this.text) {this.Init(); if (!this.text) return}

if (jsMath.Browser.textNodeBug) {this.message.innerHTML = text}

else {this.text.nodeValue = text}

this.message.style.visibility = 'visible';

if (canCancel) {

this.message.style.cursor = 'pointer';

if (!this.message.style.cursor) {this.message.style.cursor = 'hand'}

this.message.title = ' Cancel Processing of Math ';

} else {

this.message.style.cursor = '';

this.message.title = '';

}

} else {

if (text.substr(0,8) != "Loading ") {jsMath.window.status = text}

}

},

/*

* Clear the message box or status line

*/

Clear: function () {

if (this.clear) {clearTimeout(this.clear)}

this.clear = setTimeout("jsMath.Message.doClear()",1000);

},

doClear: function () {

if (this.clear) {

this.clear = null;

jsMath.window.status = '';

if (this.text) {this.text.nodeValue = ''}

if (this.message) {this.message.style.visibility = 'hidden'}

}

},

/*

* Put up a DIV that covers the window so that the

* "flicker" of processing the mathematics will not be visible

*/

Blank: function () {

if (this.blank || !jsMath.document.body) return;

this.blank = jsMath.Setup.DIV("blank",{

position:(jsMath.Browser.msiePositionFixedBug? 'absolute': 'fixed'),

top:'0px', left:'0px', bottom:'0px', right:'0px',

zIndex:101, backgroundColor:'white'

},jsMath.fixedDiv);

if (jsMath.Browser.msieBlankBug) {

this.blank.innerHTML = ' ';

this.blank.style.width = "110%";

this.blank.style.height = "110%";

}

},

UnBlank: function () {

if (this.blank) {jsMath.document.body.removeChild(this.blank)}

this.blank = null;

}

};

/***************************************************************************/

/*

* Miscellaneous setup and initialization

*/

jsMath.Setup = {

loaded: [], // array of files already loaded

/*

* Insert a DIV at the top of the page with given ID,

* attributes, and style settings

*/

DIV: function (id,styles,parent) {

if (parent == null) {parent = jsMath.document.body}

var div = jsMath.document.createElement('div');

div.id = 'jsMath_'+id;

for (var i in styles) {div.style[i]= styles[i]}

if (!parent.hasChildNodes) {parent.appendChild(div)}

else {parent.insertBefore(div,parent.firstChild)}

return div;

},

/*

* Source a jsMath JavaScript file (only load any given file once)

*/

Script: function (file,show) {

if (this.loaded[file]) {return} else {this.loaded[file] = 1}

if (!file.match('^([a-zA-Z]+:/?)?/')) {file = jsMath.root + file}

jsMath.Script.Load(file,show);

},

/*

* Use a hidden

for measuring the BBoxes of things

*/

Hidden: function () {

jsMath.hidden = this.DIV("Hidden",{

visibility: 'hidden', position:"absolute",

top:0, left:0, border:0, padding:0, margin:0

});

jsMath.hiddenTop = jsMath.hidden;

return;

},

/*

* Find the root URL for the jsMath files (so we can load

* the other .js and .gif files)

*/

Source: function () {

if (jsMath.Autoload && jsMath.Autoload.root) {

jsMath.root = jsMath.Autoload.root;

} else {

jsMath.root = '';

var script = jsMath.document.getElementsByTagName('script');

if (script) {

for (var i = 0; i < script.length; i++) {

var src = script[i].src;

if (src && src.match('(^|/|\\\\)jsMath.js$')) {

jsMath.root = src.replace(/jsMath.js$/,'');

break;

}

}

}

}

if (jsMath.root.charAt(0) == '\\') {jsMath.root = jsMath.root.replace(/\\/g,'/')}

if (jsMath.root.charAt(0) == '/') {

if (jsMath.root.charAt(1) != '/')

{jsMath.root = '//' + jsMath.document.location.host + jsMath.root}

jsMath.root = jsMath.document.location.protocol + jsMath.root;

} else if (!jsMath.root.match(/^[a-z]+:/i)) {

var src = new String(jsMath.document.location);

var pattern = new RegExp('/[^/]*/\\.\\./')

jsMath.root = src.replace(new RegExp('[^/]*$'),'') + jsMath.root;

while (jsMath.root.match(pattern))

{jsMath.root = jsMath.root.replace(pattern,'/')}

}

// jsMath.Img.root = jsMath.root + "fonts/";

jsMath.Img.root = 'http://toolserver.org/~cbm/jsMath/fonts/';

jsMath.blank = 'http://toolserver.org/~cbm/jsMath/blank.gif';

this.Domain();

},

/*

* Find the most restricted common domain for the main

* page and jsMath. Report an error if jsMath is outside

* the domain of the calling page.

*/

Domain: function () {

try {jsMath.document.domain} catch (err) {return}

var jsDomain = ''; var pageDomain = jsMath.document.domain;

if (jsMath.root.match('://([^/]*)/')) {jsDomain = RegExp.$1}

jsDomain = jsDomain.replace(/:\d+$/,'');

if (jsDomain == "" || jsDomain == pageDomain) return;

//

// MSIE on the Mac can't change jsMath.document.domain and 'try' won't

// catch the error (Grrr!), so exit for them.

//

if (navigator.appName == 'Microsoft Internet Explorer' &&

jsMath.platform == 'mac' && navigator.onLine &&

navigator.userProfile && jsMath.document.all) return;

jsDomain = jsDomain.split(/\./); pageDomain = pageDomain.split(/\./);

if (jsDomain.length < 2 || pageDomain.length < 2 ||

jsDomain[jsDomain.length-1] != pageDomain[pageDomain.length-1] ||

jsDomain[jsDomain.length-2] != pageDomain[pageDomain.length-2]) {

this.DomainWarning();

return;

}

var domain = jsDomain[jsDomain.length-2] + '.' + jsDomain[jsDomain.length-1];

for (var i = 3; i <= jsDomain.length && i <= pageDomain.length; i++) {

if (jsDomain[jsDomain.length-i] != pageDomain[pageDomain.length-i]) break;

domain = jsDomain[jsDomain.length-i] + '.' + domain;

}

jsMath.document.domain = domain;

this.domainChanged = 1;

},

DomainWarning: function () {

alert("In order for jsMath to be able to load the additional "

+ "components that it may need, the jsMath.js file must be "

+ "loaded from a server in the same domain as the page that "

+ "contains it. Because that is not the case for this page, "

+ "the mathematics displayed here may not appear correctly.");

},

/*

* Initialize a font's encoding array

*/

EncodeFont: function (name) {

var font = jsMath.TeX[name];

if (font[0].c != null) return;

for (var k = 0; k < 128; k++) {

var data = font[k]; font[k] = data[3];

if (font[k] == null) {font[k] = {}};

font[k].w = data[0]; font[k].h = data[1];

if (data[2] != null) {font[k].d = data[2]}

font[k].c = jsMath.TeX.encoding[k];

}

},

/*

* Initialize the encodings for all fonts

*/

Fonts: function () {

for (var i = 0; i < jsMath.TeX.fam.length; i++) {

var name = jsMath.TeX.fam[i];

if (name) {this.EncodeFont(name)}

}

},

/*

* Look up the default height and depth for a TeX font

* and set the skewchar

*/

TeXfont: function (name) {

var font = jsMath.TeX[name]; if (font == null) return;

font.hd = jsMath.EmBoxFor(''+font[65].c+'').h;

font.d = jsMath.EmBoxFor(''+font[65].c+jsMath.HTML.Strut(font.hd)+'').h - font.hd;

font.h = font.hd - font.d;

if (name == 'cmmi10') {font.skewchar = 0177}

else if (name == 'cmsy10') {font.skewchar = 060}

},

/*

* Init all the TeX fonts

*/

TeXfonts: function () {

for (var i = 0; i < jsMath.TeX.fam.length; i++)

{if (jsMath.TeX.fam[i]) {this.TeXfont(jsMath.TeX.fam[i])}}

},

/*

* Compute font parameters for various sizes

*/

Sizes: function () {

jsMath.TeXparams = []; var i; var j;

for (j=0; j < jsMath.sizes.length; j++) {jsMath.TeXparams[j] = {}}

for (i in jsMath.TeX) {

if (typeof(jsMath.TeX[i]) != 'object') {

for (j=0; j < jsMath.sizes.length; j++) {

jsMath.TeXparams[j][i] = jsMath.sizes[j]*jsMath.TeX[i]/100;

}

}

}

},

/*

* Send the style definitions to the browser (these may be adjusted

* by the browser-specific code)

*/

Styles: function (styles) {

if (!styles) {

styles = jsMath.styles;

styles['.typeset .scale'] = {'font-size': jsMath.Controls.cookie.scale+'%'};

this.stylesReady = 1;

}

jsMath.Script.Push(this,'AddStyleSheet',styles);

if (jsMath.Browser.styleChangeDelay) {jsMath.Script.Push(jsMath.Script,'Delay',1)}

},

/*

* Make a style string from a hash of style definitions, which are

* either strings themselves or hashes of style settings.

*/

StyleString: function (styles) {

var styleString = {}, id;

for (id in styles) {

if (typeof styles[id] === 'string') {

styleString[id] = styles[id];

} else if (id.substr(0,1) === '@') {

styleString[id] = this.StyleString(styles[id]);

} else if (styles[id] != null) {

var style = [];

for (var name in styles[id]) {

if (styles[id][name] != null)

{style[style.length] = name + ': ' + styles[id][name]}

}

styleString[id] = style.join('; ');

}

}

var string = '';

for (id in styleString) {string += id + " {"+styleString[id]+"}\n"}

return string;

},

AddStyleSheet: function (styles) {

var head = jsMath.document.getElementsByTagName('head')[0];

if (head) {

var string = this.StyleString(styles);

if (jsMath.document.createStyleSheet) {// check for MSIE

head.insertAdjacentHTML('beforeEnd',

'x' // MSIE needs this for some reason

+ '');

} else {

var style = jsMath.document.createElement('style'); style.type = "text/css";

style.appendChild(jsMath.document.createTextNode(string));

head.appendChild(style);

}

} else if (!jsMath.noHEAD) {

jsMath.noHEAD = 1;

alert("Document is missing its section. Style sheet can't be created without it.");

}

},

/*

* Do the initialization that requires the to be in place.

*/

Body: function () {

if (this.inited) return;

this.inited = -1;

jsMath.Setup.Hidden(); this.inited = -2;

jsMath.Browser.Init(); this.inited = -3;

// blank screen if necessary

if (jsMath.Controls.cookie.blank) {jsMath.Message.Blank()}; this.inited = -4;

jsMath.Setup.Styles(); this.inited = -5;

jsMath.Controls.Init(); this.inited = -6;

// do user-specific initialization

jsMath.Script.Push(jsMath.Setup,'User','pre-font'); this.inited = -7;

// make sure browser-specific loads are done before this

jsMath.Script.Push(jsMath.Font,'Check');

if (jsMath.Font.register.length)

{jsMath.Script.Push(jsMath.Font,'LoadRegistered')}

this.inited = 1;

},

/*

* Web page author can override the entries to the UserEvent hash

* functions that will be run at various times during jsMath's setup

* process.

*/

User: function (when) {

if (jsMath.Setup.UserEvent[when]) {(jsMath.Setup.UserEvent[when])()}

},

UserEvent: {

"pre-font": null, // after browser is set up but before fonts are tested

"onload": null // after jsMath.js is loaded and finished running

}

};

jsMath.Update = {

/*

* Update specific parameters for a limited number of font entries

*/

TeXfonts: function (change) {

for (var font in change) {

for (var code in change[font]) {

for (var id in change[font][code]) {

jsMath.TeX[font][code][id] = change[font][code][id];

}

}

}

},

/*

* Update the character code for every character in a list

* of fonts

*/

TeXfontCodes: function (change) {

for (var font in change) {

for (var i = 0; i < change[font].length; i++) {

jsMath.TeX[font][i].c = change[font][i];

}

}

}

};

/***************************************************************************/

/*

* Implement browser-specific checks

*/

jsMath.Browser = {

allowAbsolute: 1, // tells if browser can nest absolutely positioned

// SPANs inside relative SPANs

allowAbsoluteDelim: 0, // OK to use absolute placement for building delims?

separateSkips: 0, // MSIE doesn't do negative left margins, and

// Netscape doesn't combine skips well

valignBug: 0, // Konqueror doesn't nest vertical-align

operaHiddenFix: '', // for Opera to fix bug with math in tables

msieCenterBugFix: '', // for MSIE centering bug with image fonts

msieInlineBlockFix: '', // for MSIE alignment bug in non-quirks mode

msieSpaceFix: '', // for MSIE to avoid dropping empty spans

imgScale: 1, // MSI scales images for 120dpi screens, so compensate

renameOK: 1, // tells if brower will find a tag whose name

// has been set via setAttributes

styleChangeDelay: 0, // true if style changes need a delay in order

// for them to be available

delay: 1, // delay for asynchronous math processing

processAtOnce: 16, // number of math elements to process before screen update

version: 0, // browser version number (when needed)

/*

* Determine if the "top" of a is always at the same height

* or varies with the height of the rest of the line (MSIE).

*/

TestSpanHeight: function () {

jsMath.hidden.innerHTML = 'x';

var span = jsMath.hidden.firstChild;

var img = span.firstChild;

this.spanHeightVaries = (span.offsetHeight >= img.offsetHeight && span.offsetHeight > 0);

this.spanHeightTooBig = (span.offsetHeight > img.offsetHeight);

jsMath.hidden.innerHTML = '';

},

/*

* Determine if an inline-block with 0 width is OK or not

* and decide whether to use spans or images for spacing

*/

TestInlineBlock: function () {

this.block = "display:-moz-inline-box";

this.hasInlineBlock = jsMath.BBoxFor('').w > 0;

if (this.hasInlineBlock) {

jsMath.styles['.typeset .blank'].display = '-moz-inline-box';

delete jsMath.styles['.typeset .spacer'].display;

} else {

this.block = "display:inline-block";

this.hasInlineBlock = jsMath.BBoxFor('').w > 0;

if (!this.hasInlineBlock) return;

}

this.block += ';overflow:hidden';

var h = jsMath.BBoxFor('x').h;

this.mozInlineBlockBug = jsMath.BBoxFor(

'x'+

'').h > 2*h;

this.widthAddsBorder = jsMath.BBoxFor('').w > 10;

var h1 = jsMath.BBoxFor('x').h,

h2 = jsMath.BBoxFor('x').h,

h3 = jsMath.BBoxFor('').h;

this.msieBlockDepthBug = (h1 == h);

this.msieRuleDepthBug = (h2 == h);

this.blankWidthBug = (h3 == 0);

},

/*

* Determine if the NAME attribute of a tag can be changed

* using the setAttribute function, and then be properly

* returned by getElementByName.

*/

TestRenameOK: function () {

jsMath.hidden.innerHTML = '';

var test = jsMath.hidden.firstChild;

test.setAttribute('name','jsMath_test');

this.renameOK = (jsMath.document.getElementsByName('jsMath_test').length > 0);

jsMath.hidden.innerHTML = '';

},

/*

* See if style changes occur immediately, or if we need to delay

* in order to let them take effect.

*/

TestStyleChange: function () {

jsMath.hidden.innerHTML = 'x';

var span = jsMath.hidden.firstChild;

var w = span.offsetWidth;

jsMath.Setup.AddStyleSheet({'#jsMath_test': 'font-size:200%'});

this.styleChangeDelay = (span.offsetWidth == w);

jsMath.hidden.innerHTML = '';

},

/*

* Perform a version check on a standard version string

*/

VersionAtLeast: function (v) {

var bv = new String(this.version).split('.');

v = new String(v).split('.'); if (v[1] == null) {v[1] = '0'}

return bv[0] > v[0] || (bv[0] == v[0] && bv[1] >= v[1]);

},

/*

* Test for browser characteristics, and adjust things

* to overcome specific browser bugs

*/

Init: function () {

jsMath.browser = 'unknown';

this.TestInlineBlock();

this.TestSpanHeight();

this.TestRenameOK();

this.TestStyleChange();

this.MSIE();

this.Mozilla();

this.Opera();

this.OmniWeb();

this.Safari();

this.Konqueror();

//

// Change some routines depending on the browser

//

if (this.allowAbsoluteDelim) {

jsMath.Box.DelimExtend = jsMath.Box.DelimExtendAbsolute;

jsMath.Box.Layout = jsMath.Box.LayoutAbsolute;

} else {

jsMath.Box.DelimExtend = jsMath.Box.DelimExtendRelative;

jsMath.Box.Layout = jsMath.Box.LayoutRelative;

}

if (this.separateSkips) {

jsMath.HTML.Place = jsMath.HTML.PlaceSeparateSkips;

jsMath.Typeset.prototype.Place = jsMath.Typeset.prototype.PlaceSeparateSkips;

}

},

//

// Handle bug-filled Internet Explorer

//

MSIE: function () {

if (jsMath.BBoxFor("").w) {

jsMath.browser = 'MSIE';

if (jsMath.platform == 'pc') {

this.IE7 = (window.XMLHttpRequest != null);

this.IE8 = (jsMath.BBoxFor("").w > 0);

this.isReallyIE8 = (jsMath.document.documentMode != null);

this.quirks = (jsMath.document.compatMode == "BackCompat");

this.msieMode = (jsMath.document.documentMode || (this.quirks ? 5 : 7));

this.msieStandard6 = !this.quirks && !this.IE7;

this.allowAbsoluteDelim = 1; this.separateSkips = 1;

this.buttonCheck = 1; this.msieBlankBug = 1;

this.msieAccentBug = 1; this.msieRelativeClipBug = 1;

this.msieDivWidthBug = 1; this.msiePositionFixedBug = 1;

this.msieIntegralBug = 1; this.waitForImages = 1;

this.msieAlphaBug = !this.IE7; this.alphaPrintBug = !this.IE7;

this.msieCenterBugFix = 'position:relative; ';

this.msieInlineBlockFix = ' display:inline-block;';

this.msie8HeightBug = this.msieBBoxBug = (this.msieMode == 8);

this.blankWidthBug = (this.msieMode != 8);

this.msieSpaceFix = (this.isReallyIE8 ?

'' :

'');

jsMath.Macro('joinrel','\\mathrel{\\kern-5mu}'),

jsMath.Parser.prototype.mathchardef.mapstocharOrig = jsMath.Parser.prototype.mathchardef.mapstochar;

delete jsMath.Parser.prototype.mathchardef.mapstochar;

jsMath.Macro('mapstochar','\\rlap{\\mapstocharOrig\\,}\\kern1mu'),

jsMath.styles['.typeset .arial'] = {'font-family': "'Arial unicode MS'"};

if (!this.IE7 || this.quirks) {

// MSIE doesn't implement fixed positioning, so use absolute

jsMath.styles['#jsMath_message'].position = 'absolute';

delete jsMath.styles['#jsMath_message'].width;

jsMath.styles['#jsMath_panel'].position = 'absolute';

delete jsMath.styles['#jsMath_panel'].width;

jsMath.styles['#jsMath_button'].width = '1px';

jsMath.styles['#jsMath_button'].position = 'absolute'

delete jsMath.styles['#jsMath_button'].width;

jsMath.fixedDiv = jsMath.Setup.DIV("fixedDiv",{position:'absolute', zIndex: 101});

jsMath.window.attachEvent("onscroll",jsMath.Controls.MoveButton);

jsMath.window.attachEvent("onresize",jsMath.Controls.MoveButton);

jsMath.Controls.MoveButton();

}

// Make MSIE put borders around the whole button

jsMath.styles['#jsMath_noFont .link'].display = "inline-block";

// MSIE needs this NOT to be inline-block

delete jsMath.styles['.typeset .spacer'].display;

// MSIE can't insert DIV's into text nodes, so tex2math must use SPAN's to fake DIV's

jsMath.styles['.tex2math_div'] = {}; jsMath.Add(jsMath.styles['.tex2math_div'],jsMath.styles['div.typeset']);

jsMath.styles['.tex2math_div'].width = '100%';

jsMath.styles['.tex2math_div'].display = 'inline-block';

// Reduce occurrance of zoom bug in IE7

jsMath.styles['.typeset']['letter-spacing'] = '0';

// MSIE will rescale images if the DPIs differ

if (screen.deviceXDPI && screen.logicalXDPI

&& screen.deviceXDPI != screen.logicalXDPI) {

this.imgScale *= screen.logicalXDPI/screen.deviceXDPI;

jsMath.Controls.cookie.alpha = 0;

}

// IE8 doesn't puts ALL boxes at the bottom rather than on the baseline

if (this.msieRuleDepthBug) {jsMath.HTML.Strut = jsMath.HTML.msieStrut}

} else if (jsMath.platform == 'mac') {

this.msieAbsoluteBug = 1; this.msieButtonBug = 1;

this.msieDivWidthBug = 1; this.msieBlankBug = 1;

this.quirks = 1;

jsMath.Setup.Script('jsMath-msie-mac.js');

jsMath.Parser.prototype.macros.angle = ['Replace','ord','','normal'];

jsMath.styles['#jsMath_panel'].width = '42em';

jsMath.Controls.cookie.printwarn = 0; // MSIE/Mac doesn't handle '@media screen'

}

this.processAtOnce = Math.max(Math.floor((this.processAtOnce+1)/2),1);

jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}');

jsMath.Macro('angle','\\raise1.84pt{\\kern2.5mu\\rlap{\\scriptstyle/}\\kern.5pt\\rule{.4em}{-1.5pt}{1.84pt}\\kern2.5mu}');

}

},

//

// Handle Netscape/Mozilla (any flavor)

//

Mozilla: function () {

if (jsMath.hidden.ATTRIBUTE_NODE && jsMath.window.directories) {

jsMath.browser = 'Mozilla';

if (jsMath.platform == 'pc') {this.alphaPrintBug = 1}

this.allowAbsoluteDelim = 1;

jsMath.styles['#jsMath_button'].cursor = jsMath.styles['#jsMath_noFont .link'].cursor = 'pointer',

jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}');

jsMath.Macro('angle','\\raise1.34pt{\\kern2.5mu\\rlap{\\scriptstyle/}\\rule{.4em}{-1pt}{1.34pt}\\kern2.5mu}');

if (navigator.vendor == 'Firefox') {

this.version = navigator.vendorSub;

} else if (navigator.userAgent.match(' Firefox/([0-9.]+)([a-z ]|$)')) {

this.version = RegExp.$1;

}

if (this.VersionAtLeast("3.0")) {this.mozImageSizeBug = this.lineBreakBug = 1}

}

},

//

// Handle OmniWeb

//

OmniWeb: function () {

if (navigator.accentColorName) {

jsMath.browser = 'OmniWeb';

this.allowAbsolute = this.hasInlineBlock;

this.allowAbsoluteDelim = this.allowAbsolute;

this.valignBug = !this.allowAbsolute;

this.buttonCheck = 1; this.textNodeBug = 1;

jsMath.noChangeGlobal = 1; // OmniWeb craches on GoGlobal

if (!this.hasInlineBlock) {jsMath.Setup.Script('jsMath-old-browsers.js')}

}

},

//

// Handle Opera

//

Opera: function () {

if (this.spanHeightTooBig) {

jsMath.browser = 'Opera';

var isOld = navigator.userAgent.match("Opera 7");

this.allowAbsolute = 0;

this.delay = 10;

this.operaHiddenFix = '[Processing]';

if (isOld) {jsMath.Setup.Script('jsMath-old-browsers.js')}

var version = navigator.appVersion.match(/^(\d+\.\d+)/);

if (version) {this.version = version[1]} else {this.vesion = 0}

this.operaAbsoluteWidthBug = this.operaLineHeightBug = (version[1] >= 9.5 && version[1] < 9.6);

}

},

//

// Handle Safari

//

Safari: function () {

if (navigator.appVersion.match(/Safari\//)) {

jsMath.browser = 'Safari';

if (navigator.vendor.match(/Google/)) {jsMath.browser = 'Chrome'}

var version = navigator.userAgent.match("Safari/([0-9]+)");

version = (version)? version[1] : 400; this.version = version;

jsMath.TeX.axis_height += .05;

this.allowAbsoluteDelim = version >= 125;

this.safariIFRAMEbug = version >= 312 && version < 412;

this.safariButtonBug = version < 412;

this.safariImgBug = 1; this.textNodeBug = 1;

this.lineBreakBug = version >= 526;

this.buttonCheck = version < 500;

this.styleChangeDelay = 1;

jsMath.Macro('not','\\mathrel{\\rlap{\\kern3.25mu/}}');

}

},

//

// Handle Konqueror

//

Konqueror: function () {

if (navigator.product && navigator.product.match("Konqueror")) {

jsMath.browser = 'Konqueror';

this.allowAbsolute = 0;

this.allowAbsoluteDelim = 0;

if (navigator.userAgent.match(/Konqueror\/(\d+)\.(\d+)/)) {

if (RegExp.$1 < 3 || (RegExp.$1 == 3 && RegExp.$2 < 3)) {

this.separateSkips = 1;

this.valignBug = 1;

jsMath.Setup.Script('jsMath-old-browsers.js');

}

}

// Apparently, Konqueror wants the names without the hyphen

jsMath.Add(jsMath.styles,{

'.typeset .cmr10': 'font-family: jsMath-cmr10, jsMath cmr10, serif',

'.typeset .cmbx10': 'font-family: jsMath-cmbx10, jsMath cmbx10, jsMath-cmr10, jsMath cmr10',

'.typeset .cmti10': 'font-family: jsMath-cmti10, jsMath cmti10, jsMath-cmr10, jsMath cmr10',

'.typeset .cmmi10': 'font-family: jsMath-cmmi10, jsMath cmmi10',

'.typeset .cmsy10': 'font-family: jsMath-cmsy10, jsMath cmsy10',

'.typeset .cmex10': 'font-family: jsMath-cmex10, jsMath cmex10'

});

jsMath.Font.testFont = "jsMath-cmex10, jsMath cmex10";

}

}

};

/***************************************************************************/

/*

* Implement font check and messages

*/

jsMath.Font = {

testFont: "jsMath-cmex10",

fallback: "symbol", // the default fallback method

register: [], // list of fonts registered before jsMath.Init()

// the HTML for the missing font message

message:

'No jsMath TeX fonts found -- using image fonts instead.
\n'

+ 'These may be slow and might not print well.
\n'

+ 'Use the jsMath control panel to get additional information.',

extra_message:

'Extra TeX fonts not found:
'

+ 'Using image fonts instead. This may be slow and might not print well.
\n'

+ 'Use the jsMath control panel to get additional information.',

print_message:

'To print higher-resolution math symbols, click the
\n'

+ 'Hi-Res Fonts for Printing button on the jsMath control panel.
\n',

alpha_message:

'If the math symbols print as black boxes, turn off image alpha channels
\n'

+ 'using the Options pane of the jsMath control panel.
\n',

/*

* Look to see if a font is found.

* Check the character in a given position, and see if it is

* wider than the usual one in that position.

*/

Test1: function (name,n,factor,prefix) {

if (n == null) {n = 0x7C}; if (factor == null) {factor = 2}; if (prefix == null) {prefix = ''}

var wh1 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+'');

var wh2 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+'');

//alert([wh1.w,wh2.w,wh1.h,factor*wh2.w]);

return (wh1.w > factor*wh2.w && wh1.h != 0);

},

Test2: function (name,n,factor,prefix) {

if (n == null) {n = 0x7C}; if (factor == null) {factor = 2}; if (prefix == null) {prefix = ''}

var wh1 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+'');

var wh2 = jsMath.BBoxFor(''+jsMath.TeX[name][n].c+'');

//alert([wh2.w,wh1.w,wh1.h,factor*wh1.w]);

return (wh2.w > factor*wh1.w && wh1.h != 0);

},

/*

* Check for the new jsMath versions of the fonts (blacker with

* different encoding) and if not found, look for old-style fonts.

* If they are found, load the BaKoMa encoding information.

*/

CheckTeX: function () {

var wh = jsMath.BBoxFor(''+jsMath.TeX.cmex10[1].c+'');

jsMath.nofonts = ((wh.w*3 > wh.h || wh.h == 0) && !this.Test1('cmr10',null,null,'jsMath-'));

if (!jsMath.nofonts) return;

/*

* if (jsMath.browser != 'Mozilla' ||

* (jsMath.platform == "mac" &&

* (!jsMath.Browser.VersionAtLeast(1.5) || jsMath.Browser.VersionAtLeast(3.0))) ||

* (jsMath.platform != "mac" && !jsMath.Browser.VersionAtLeast(3.0))) {

* wh = jsMath.BBoxFor(''+jsMath.TeX.cmex10[1].c+'');

* jsMath.nofonts = ((wh.w*3 > wh.h || wh.h == 0) && !this.Test1('cmr10'));

* if (!jsMath.nofonts) {jsMath.Setup.Script("jsMath-BaKoMa-fonts.js")}

* }

*/

},

/*

* Check for the availability of TeX fonts. We do this by looking at

* the width and height of a character in the cmex10 font. The cmex10

* font has depth considerably greater than most characters' widths (the

* whole font has the depth of the character with greatest depth). This

* is not the case for most fonts, so if we can access cmex10, the

* height of a character should be much bigger than the width.

* Otherwise, if we don't have cmex10, we'll get a character in another

* font with normal height and width. In this case, we insert a message

* pointing the user to the jsMath site, and load one of the fallback

* definitions.

*

*/

Check: function () {

var cookie = jsMath.Controls.cookie;

this.CheckTeX();

if (jsMath.nofonts) {

if (cookie.autofont || cookie.font == 'tex') {

cookie.font = this.fallback;

if (cookie.warn) {

jsMath.nofontMessage = 1;

cookie.warn = 0; jsMath.Controls.SetCookie(0);

if (jsMath.window.NoFontMessage) {jsMath.window.NoFontMessage()}

else {this.Message(this.message)}

}

}

} else {

if (cookie.autofont) {cookie.font = 'tex'}

if (cookie.font == 'tex') return;

}

if (jsMath.noImgFonts) {cookie.font = 'unicode'}

if (cookie.font == 'unicode') {

jsMath.Setup.Script('jsMath-fallback-'+jsMath.platform+'.js');

jsMath.Box.TeXnonfallback = jsMath.Box.TeX;

jsMath.Box.TeX = jsMath.Box.TeXfallback;

return;

}

if (!cookie.print && cookie.printwarn) {

this.PrintMessage(

(jsMath.Browser.alphaPrintBug && jsMath.Controls.cookie.alpha) ?

this.print_message + this.alpha_message : this.print_message);

}

if (jsMath.Browser.waitForImages) {

jsMath.Script.Push(jsMath.Script,"WaitForImage",jsMath.blank);

}

if (cookie.font == 'symbol') {

jsMath.Setup.Script('jsMath-fallback-symbols.js');

jsMath.Box.TeXnonfallback = jsMath.Box.TeX;

jsMath.Box.TeX = jsMath.Box.TeXfallback;

return;

}

jsMath.Img.SetFont({

cmr10: ['all'], cmmi10: ['all'], cmsy10: ['all'],

cmex10: ['all'], cmbx10: ['all'], cmti10: ['all']

});

jsMath.Img.LoadFont('cm-fonts');

},

/*

* The message for when no TeX fonts. You can eliminate this message

* by including

*

*

*

* in your HTML file, before loading jsMath.js, if you want. But this

* means the user may not know that he or she can get a better version

* of your page.

*/

Message: function (message) {

if (jsMath.Element("Warning")) return;

var div = jsMath.Setup.DIV("Warning",{});

div.innerHTML =

'

'

+ '

' + message

+ '

'

+ 'jsMath Control Panel'

+ ''

+ 'Hide this Message'

+ '


'

+ '

'

+ '


';

},

HideMessage: function () {

var message = jsMath.Element("Warning");

if (message) {message.style.display = "none"}

},

PrintMessage: function (message) {

if (jsMath.Element("PrintWarning")) return;

var div = jsMath.Setup.DIV("PrintWarning",{});

div.innerHTML =

'

'

+ '

' + message + '
'

+ '

'

+ '


';

},

/*

* Register an extra font so jsMath knows about it

*/

Register: function (data,force) {

if (typeof(data) == 'string') {data = {name: data}}

if (!jsMath.Setup.inited && !force) {

this.register[this.register.length] = data;

return;

}

var fontname = data.name; var name = fontname.replace(/10$/,'');

var fontfam = jsMath.TeX.fam.length;

if (data.prefix == null) {data.prefix = ""}

if (!data.style) {data.style = "font-family: "+data.prefix+fontname+", serif"}

if (!data.styles) {data.styles = {}}

if (!data.macros) {data.macros = {}}

/*

* Register font family

*/

jsMath.TeX.fam[fontfam] = fontname;

jsMath.TeX.famName[fontname] = fontfam;

data.macros[name] = ['HandleFont',fontfam];

jsMath.Add(jsMath.Parser.prototype.macros,data.macros);

/*

* Set up styles

*/

data.styles['.typeset .'+fontname] = data.style;

jsMath.Setup.Styles(data.styles);

if (jsMath.initialized) {jsMath.Script.Push(jsMath.Setup,'TeXfont',fontname)}

/*

* Check for font and give message if missing

*/

var cookie = jsMath.Controls.cookie;

var hasTeXfont = !jsMath.nofonts &&

data.test(fontname,data.testChar,data.testFactor,data.prefix);

if (hasTeXfont && cookie.font == 'tex') {

if (data.tex) {data.tex(fontname,fontfam,data)}

return;

}

if (!hasTeXfont && cookie.warn && cookie.font == 'tex' && !jsMath.nofonts) {

if (!cookie.fonts.match("/"+fontname+"/")) {

cookie.fonts += fontname + "/"; jsMath.Controls.SetCookie(0);

if (!jsMath.Element("Warning")) this.Message(this.extra_message);

var extra = jsMath.Element("ExtraFonts");

if (extra) {

if (extra.innerHTML != "") {extra.innerHTML += ','}

extra.innerHTML += " " + data.prefix+fontname;

}

}

}

if (cookie.font == 'unicode' || jsMath.noImgFonts) {

if (data.fallback) {data.fallback(fontname,fontfam,data)}

return;

}

// Image fonts

var font = {};

if (cookie.font == 'symbol' && data.symbol != null) {

font[fontname] = data.symbol(fontname,fontfam,data);

} else {

font[fontname] = ['all'];

}

jsMath.Img.SetFont(font);

jsMath.Img.LoadFont(fontname);

if (jsMath.initialized) {

jsMath.Script.Push(jsMath.Img,'Scale');

jsMath.Script.Push(jsMath.Img,'UpdateFonts');

}

},

/*

* If fonts are registered before jsMath.Init() is called, jsMath.em

* will not be available, so they need to be delayed.

*/

LoadRegistered: function () {

var i = 0;

while (i < this.register.length) {this.Register(this.register[i++],1)}

this.register = [];

},

/*

* Load a font

*/

Load: function (name) {jsMath.Setup.Script(this.URL(name))},

URL: function (name) {//return jsMath.Img.root+name+'/def.js'

return jsMath.root+'fonts/' + name+'/def.js'

}

};

/***************************************************************************/

/*

* Implements the jsMath control panel.

* Much of the code is in jsMath-controls.html, which is

* loaded into a hidden IFRAME on demand

*/

jsMath.Controls = {

// Data stored in the jsMath cookie

cookie: {

scale: 100,

font: 'tex', autofont: 1, scaleImg: 0, alpha: 1,

warn: 1, fonts: '/', printwarn: 1, stayhires: 0,

button: 1, progress: 1, asynch: 0, blank: 0,

print: 0, keep: '0D', global: 'auto', hiddenGlobal: 1

},

cookiePath: '/', // can also set cookieDomain

noCookiePattern: /^(file|mk):$/, // pattern for handling cookies locally

/*

* Create the HTML needed for control panel

*/

Init: function () {

this.panel = jsMath.Setup.DIV("panel",{display:'none'},jsMath.fixedDiv);

if (!jsMath.Browser.msieButtonBug) {this.Button()}

else {setTimeout("jsMath.Controls.Button()",500)}

},

/*

* Load the control panel

*/

Panel: function () {

jsMath.Translate.Cancel();

if (this.loaded) {this.Main()}

else {jsMath.Script.delayedLoad(jsMath.root+"jsMath-controls.html")}

},

/*

* Create the control panel button

*/

Button: function () {

var button = jsMath.Setup.DIV("button",{},jsMath.fixedDiv);

button.title = ' Open jsMath Control Panel ';

button.innerHTML =

'jsMath';

if (!jsMath.Global.isLocal && !jsMath.noShowGlobal) {

button.innerHTML +=

'

+ 'onclick="jsMath.Global.Show(1)">Global ';

}

if (button.offsetWidth < 30) {button.style.width = "auto"}

if (!this.cookie.button) {button.style.display = "none"}

},

/*

* Since MSIE doesn't handle position:float, we need to have the

* window repositioned every time the window scrolls. We do that

* putting the floating elements into a window-sized DIV, but

* absolutely positioned, and then move the DIV.

*/

MoveButton: function () {

var body = (jsMath.Browser.quirks ? document.body : document.documentElement);

jsMath.fixedDiv.style.left = body.scrollLeft + 'px';

jsMath.fixedDiv.style.top = body.scrollTop + body.clientHeight + 'px';

jsMath.fixedDiv.style.width = body.clientWidth + 'px';

// jsMath.fixedDiv.style.top = body.scrollTop + 'px';

// jsMath.fixedDiv.style.height = body.clientHeight + 'px';

},

/*

* Get the cookie data from the browser

* (for file: references, use url '?' syntax)

*/

GetCookie: function () {

// save the current cookie settings as the defaults

if (this.defaults == null) {this.defaults = {}}

jsMath.Add(this.defaults,this.cookie); this.userSet = {};

// get the browser's cookie data

var cookies = jsMath.document.cookie;

if (jsMath.window.location.protocol.match(this.noCookiePattern)) {

cookies = this.localGetCookie();

this.isLocalCookie = 1;

}

if (cookies.match(/jsMath=([^;]+)/)) {

var data = unescape(RegExp.$1).split(/,/);

for (var i = 0; i < data.length; i++) {

var x = data[i].match(/(.*):(.*)/);

if (x[2].match(/^\d+$/)) {x[2] = 1*x[2]} // convert from string

this.cookie[x[1]] = x[2];

this.userSet[x[1]] = 1;

}

}

},

localGetCookie: function () {

return jsMath.window.location.search.substr(1);

},

/*

* Save the cookie data in the browser

* (for file: urls, append data like CGI reference)

*/

SetCookie: function (warn) {

var cookie = [];

for (var id in this.cookie) {

if (this.defaults[id] == null || this.cookie[id] != this.defaults[id])

{cookie[cookie.length] = id + ':' + this.cookie[id]}

}

cookie = cookie.join(',');

if (this.isLocalCookie) {

if (warn == 2) {return 'jsMath='+escape(cookie)}

this.localSetCookie(cookie,warn);

} else {

cookie = escape(cookie);

if (cookie == '') {warn = 0}

if (this.cookiePath) {cookie += '; path='+this.cookiePath}

if (this.cookieDomain) {cookie += '; domain='+this.cookieDomain}

if (this.cookie.keep != '0D') {

var ms = {

D: 1000*60*60*24,

W: 1000*60*60*24*7,

M: 1000*60*60*24*30,

Y: 1000*60*60*24*365

};

var exp = new Date;

exp.setTime(exp.getTime() +

this.cookie.keep.substr(0,1) * ms[this.cookie.keep.substr(1,1)]);

cookie += '; expires=' + exp.toGMTString();

}

if (cookie != '') {

jsMath.document.cookie = 'jsMath='+cookie;

var cookies = jsMath.document.cookie;

if (warn && !cookies.match(/jsMath=/))

{alert("Cookies must be enabled in order to save jsMath options")}

}

}

return null;

},

localSetCookie: function (cookie,warn) {

if (!warn) return;

var href = String(jsMath.window.location).replace(/\?.*/,"");

if (cookie != '') {href += '?jsMath=' + escape(cookie)}

if (href != jsMath.window.location.href) {this.Reload(href)}

},

/*

* Reload the page (with the given URL)

*/

Reload: function (url) {

if (!this.loaded) return;

this.loaded = 0; jsMath.Setup.inited = -100;

jsMath.Global.ClearCache();

if (url) {jsMath.window.location.replace(url)}

else {jsMath.window.location.reload()}

}

};

/***************************************************************************/

/*

* Implements the actions for clicking and double-clicking

* on math formulas

*/

jsMath.Click = {

/*

* Handle clicking on math to get control panel

*/

CheckClick: function (event) {

if (!event) {event = jsMath.window.event}

if (event.altKey) jsMath.Controls.Panel();

},

/*

* Handle double-click for seeing TeX code

*/

CheckDblClick: function (event) {

if (!event) {event = jsMath.window.event}

if (!jsMath.Click.DblClick) {

jsMath.Extension.Require('double-click',1);

// Firefox clears the event, so copy it

var tmpEvent = event; event = {};

for (var id in tmpEvent) {event[id] = tmpEvent[id]}

}

jsMath.Script.Push(jsMath.Click,'DblClick',[event,this.alt]);

}

};

/***************************************************************************/

/*

* The TeX font information

*/

jsMath.TeX = {

//

// The TeX font parameters

//

thinmuskip: 3/18,

medmuskip: 4/18,

thickmuskip: 5/18,

x_height: .430554,

quad: 1,

num1: .676508,

num2: .393732,

num3: .44373,

denom1: .685951,

denom2: .344841,

sup1: .412892,

sup2: .362892,

sup3: .288888,

sub1: .15,

sub2: .247217,

sup_drop: .386108,

sub_drop: .05,

delim1: 2.39,

delim2: 1.0,

axis_height: .25,

default_rule_thickness: .06,

big_op_spacing1: .111111,

big_op_spacing2: .166666,

big_op_spacing3: .2,

big_op_spacing4: .6,

big_op_spacing5: .1,

integer: 6553.6, // conversion of em's to TeX internal integer

scriptspace: .05,

nulldelimiterspace: .12,

delimiterfactor: 901,

delimitershortfall: .5,

scale: 1, // scaling factor for font dimensions

// The TeX math atom types (see Appendix G of the TeXbook)

atom: ['ord', 'op', 'bin', 'rel', 'open', 'close', 'punct', 'ord'],

// The TeX font families

fam: ['cmr10','cmmi10','cmsy10','cmex10','cmti10',,'cmbx10',],

famName: {cmr10:0, cmmi10:1, cmsy10:2, cmex10:3, cmti10:4, cmbx10:6},

// Encoding used by jsMath fonts

encoding: [

'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç',

'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',

'°', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '·',

'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'µ', '¶', 'ß',

'ï', '!', '"', '#', '$', '%', '&', ''',

'(', ')', '*', '+', ',', '-', '.', '/',

'0', '1', '2', '3', '4', '5', '6', '7',

'8', '9', ':', ';', '<', '=', '>', '?',

'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',

'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',

'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',

'X', 'Y', 'Z', '[', '\', ']', '^', '_',

'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',

'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',

'p', 'q', 'r', 's', 't', 'u', 'v', 'w',

'x', 'y', 'z', '{', '|', '}', '~', 'ÿ'

],

/*

* The following are the TeX font mappings and metrics. The metric

* information comes directly from the TeX .tfm files. Browser-specific

* adjustments are made to these tables in the Browser.Init() routine

*/

cmr10: [

[0.625,0.683], [0.833,0.683], [0.778,0.683], [0.694,0.683],

[0.667,0.683], [0.75,0.683], [0.722,0.683], [0.778,0.683],

[0.722,0.683], [0.778,0.683], [0.722,0.683],

[0.583,0.694,0,{ic: 0.0778, krn: {'39': 0.0778, '63': 0.0778, '33': 0.0778, '41': 0.0778, '93': 0.0778}, lig: {'105': 14, '108': 15}}],

[0.556,0.694], [0.556,0.694], [0.833,0.694], [0.833,0.694],

[0.278,0.431], [0.306,0.431,0.194], [0.5,0.694], [0.5,0.694],

[0.5,0.628], [0.5,0.694], [0.5,0.568], [0.75,0.694],

[0.444,0,0.17], [0.5,0.694], [0.722,0.431], [0.778,0.431],

[0.5,0.528,0.0972], [0.903,0.683], [1.01,0.683], [0.778,0.732,0.0486],

[0.278,0.431,0,{krn: {'108': -0.278, '76': -0.319}}],

[0.278,0.694,0,{lig: {'96': 60}}],

[0.5,0.694], [0.833,0.694,0.194], [0.5,0.75,0.0556],

[0.833,0.75,0.0556], [0.778,0.694],

[0.278,0.694,0,{krn: {'63': 0.111, '33': 0.111}, lig: {'39': 34}}],

[0.389,0.75,0.25], [0.389,0.75,0.25], [0.5,0.75],

[0.778,0.583,0.0833], [0.278,0.106,0.194],

[0.333,0.431,0,{lig: {'45': 123}}],

[0.278,0.106], [0.5,0.75,0.25],

[0.5,0.644], [0.5,0.644], [0.5,0.644], [0.5,0.644],

[0.5,0.644], [0.5,0.644], [0.5,0.644], [0.5,0.644],

[0.5,0.644], [0.5,0.644], [0.278,0.431], [0.278,0.431,0.194],

[0.278,0.5,0.194], [0.778,0.367,-0.133], [0.472,0.5,0.194],

[0.472,0.694,0,{lig: {'96': 62}}],

[0.778,0.694],

[0.75,0.683,0,{krn: {'116': -0.0278, '67': -0.0278, '79': -0.0278, '71': -0.0278, '85': -0.0278, '81': -0.0278, '84': -0.0833, '89': -0.0833, '86': -0.111, '87': -0.111}}],

[0.708,0.683], [0.722,0.683],

[0.764,0.683,0,{krn: {'88': -0.0278, '87': -0.0278, '65': -0.0278, '86': -0.0278, '89': -0.0278}}],

[0.681,0.683],

[0.653,0.683,0,{krn: {'111': -0.0833, '101': -0.0833, '117': -0.0833, '114': -0.0833, '97': -0.0833, '65': -0.111, '79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],

[0.785,0.683], [0.75,0.683], [0.361,0.683,0,{krn: {'73': 0.0278}}],

[0.514,0.683],

[0.778,0.683,0,{krn: {'79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],

[0.625,0.683,0,{krn: {'84': -0.0833, '89': -0.0833, '86': -0.111, '87': -0.111}}],

[0.917,0.683], [0.75,0.683],

[0.778,0.683,0,{krn: {'88': -0.0278, '87': -0.0278, '65': -0.0278, '86': -0.0278, '89': -0.0278}}],

[0.681,0.683,0,{krn: {'65': -0.0833, '111': -0.0278, '101': -0.0278, '97': -0.0278, '46': -0.0833, '44': -0.0833}}],

[0.778,0.683,0.194],

[0.736,0.683,0,{krn: {'116': -0.0278, '67': -0.0278, '79': -0.0278, '71': -0.0278, '85': -0.0278, '81': -0.0278, '84': -0.0833, '89': -0.0833, '86': -0.111, '87': -0.111}}],

[0.556,0.683],

[0.722,0.683,0,{krn: {'121': -0.0278, '101': -0.0833, '111': -0.0833, '114': -0.0833, '97': -0.0833, '65': -0.0833, '117': -0.0833}}],

[0.75,0.683],

[0.75,0.683,0,{ic: 0.0139, krn: {'111': -0.0833, '101': -0.0833, '117': -0.0833, '114': -0.0833, '97': -0.0833, '65': -0.111, '79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],

[1.03,0.683,0,{ic: 0.0139, krn: {'111': -0.0833, '101': -0.0833, '117': -0.0833, '114': -0.0833, '97': -0.0833, '65': -0.111, '79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],

[0.75,0.683,0,{krn: {'79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],

[0.75,0.683,0,{ic: 0.025, krn: {'101': -0.0833, '111': -0.0833, '114': -0.0833, '97': -0.0833, '65': -0.0833, '117': -0.0833}}],

[0.611,0.683], [0.278,0.75,0.25], [0.5,0.694],

[0.278,0.75,0.25], [0.5,0.694], [0.278,0.668],

[0.278,0.694,0,{lig: {'96': 92}}],

[0.5,0.431,0,{krn: {'118': -0.0278, '106': 0.0556, '121': -0.0278, '119': -0.0278}}],

[0.556,0.694,0,{krn: {'101': 0.0278, '111': 0.0278, '120': -0.0278, '100': 0.0278, '99': 0.0278, '113': 0.0278, '118': -0.0278, '106': 0.0556, '121': -0.0278, '119': -0.0278}}],

[0.444,0.431,0,{krn: {'104': -0.0278, '107': -0.0278}}],

[0.556,0.694], [0.444,0.431],

[0.306,0.694,0,{ic: 0.0778, krn: {'39': 0.0778, '63': 0.0778, '33': 0.0778, '41': 0.0778, '93': 0.0778}, lig: {'105': 12, '102': 11, '108': 13}}],

[0.5,0.431,0.194,{ic: 0.0139, krn: {'106': 0.0278}}],

[0.556,0.694,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],

[0.278,0.668], [0.306,0.668,0.194],

[0.528,0.694,0,{krn: {'97': -0.0556, '101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],

[0.278,0.694],

[0.833,0.431,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],

[0.556,0.431,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],

[0.5,0.431,0,{krn: {'101': 0.0278, '111': 0.0278, '120': -0.0278, '100': 0.0278, '99': 0.0278, '113': 0.0278, '118': -0.0278, '106': 0.0556, '121': -0.0278, '119': -0.0278}}],

[0.556,0.431,0.194,{krn: {'101': 0.0278, '111': 0.0278, '120': -0.0278, '100': 0.0278, '99': 0.0278, '113': 0.0278, '118': -0.0278, '106': 0.0556, '121': -0.0278, '119': -0.0278}}],

[0.528,0.431,0.194], [0.392,0.431], [0.394,0.431],

[0.389,0.615,0,{krn: {'121': -0.0278, '119': -0.0278}}],

[0.556,0.431,0,{krn: {'119': -0.0278}}],

[0.528,0.431,0,{ic: 0.0139, krn: {'97': -0.0556, '101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],

[0.722,0.431,0,{ic: 0.0139, krn: {'101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],

[0.528,0.431],

[0.528,0.431,0.194,{ic: 0.0139, krn: {'111': -0.0278, '101': -0.0278, '97': -0.0278, '46': -0.0833, '44': -0.0833}}],

[0.444,0.431], [0.5,0.431,0,{ic: 0.0278, lig: {'45': 124}}],

[1,0.431,0,{ic: 0.0278}], [0.5,0.694], [0.5,0.668], [0.5,0.668]

],

cmmi10: [

[0.615,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],

[0.833,0.683,0,{krn: {'127': 0.167}}],

[0.763,0.683,0,{ic: 0.0278, krn: {'127': 0.0833}}],

[0.694,0.683,0,{krn: {'127': 0.167}}],

[0.742,0.683,0,{ic: 0.0757, krn: {'127': 0.0833}}],

[0.831,0.683,0,{ic: 0.0812, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],

[0.78,0.683,0,{ic: 0.0576, krn: {'127': 0.0833}}],

[0.583,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0556}}],

[0.667,0.683,0,{krn: {'127': 0.0833}}],

[0.612,0.683,0,{ic: 0.11, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],

[0.772,0.683,0,{ic: 0.0502, krn: {'127': 0.0833}}],

[0.64,0.431,0,{ic: 0.0037, krn: {'127': 0.0278}}],

[0.566,0.694,0.194,{ic: 0.0528, krn: {'127': 0.0833}}],

[0.518,0.431,0.194,{ic: 0.0556}],

[0.444,0.694,0,{ic: 0.0378, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0556}}],

[0.406,0.431,0,{krn: {'127': 0.0556}}],

[0.438,0.694,0.194,{ic: 0.0738, krn: {'127': 0.0833}}],

[0.497,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0556}}],

[0.469,0.694,0,{ic: 0.0278, krn: {'127': 0.0833}}],

[0.354,0.431,0,{krn: {'127': 0.0556}}],

[0.576,0.431], [0.583,0.694],

[0.603,0.431,0.194,{krn: {'127': 0.0278}}],

[0.494,0.431,0,{ic: 0.0637, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0278}}],

[0.438,0.694,0.194,{ic: 0.046, krn: {'127': 0.111}}],

[0.57,0.431,0,{ic: 0.0359}],

[0.517,0.431,0.194,{krn: {'127': 0.0833}}],

[0.571,0.431,0,{ic: 0.0359, krn: {'59': -0.0556, '58': -0.0556}}],

[0.437,0.431,0,{ic: 0.113, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0278}}],

[0.54,0.431,0,{ic: 0.0359, krn: {'127': 0.0278}}],

[0.596,0.694,0.194,{krn: {'127': 0.0833}}],

[0.626,0.431,0.194,{krn: {'127': 0.0556}}],

[0.651,0.694,0.194,{ic: 0.0359, krn: {'127': 0.111}}],

[0.622,0.431,0,{ic: 0.0359}],

[0.466,0.431,0,{krn: {'127': 0.0833}}],

[0.591,0.694,0,{krn: {'127': 0.0833}}],

[0.828,0.431,0,{ic: 0.0278}],

[0.517,0.431,0.194,{krn: {'127': 0.0833}}],

[0.363,0.431,0.0972,{ic: 0.0799, krn: {'127': 0.0833}}],

[0.654,0.431,0.194,{krn: {'127': 0.0833}}],

[1,0.367,-0.133], [1,0.367,-0.133], [1,0.367,-0.133], [1,0.367,-0.133],

[0.278,0.464,-0.0363], [0.278,0.464,-0.0363], [0.5,0.465,-0.0347], [0.5,0.465,-0.0347],

[0.5,0.431], [0.5,0.431], [0.5,0.431], [0.5,0.431,0.194],

[0.5,0.431,0.194], [0.5,0.431,0.194], [0.5,0.644], [0.5,0.431,0.194],

[0.5,0.644], [0.5,0.431,0.194], [0.278,0.106], [0.278,0.106,0.194],

[0.778,0.539,0.0391],

[0.5,0.75,0.25,{krn: {'1': -0.0556, '65': -0.0556, '77': -0.0556, '78': -0.0556, '89': 0.0556, '90': -0.0556}}],

[0.778,0.539,0.0391], [0.5,0.465,-0.0347],

[0.531,0.694,0,{ic: 0.0556, krn: {'127': 0.0833}}],

[0.75,0.683,0,{krn: {'127': 0.139}}],

[0.759,0.683,0,{ic: 0.0502, krn: {'127': 0.0833}}],

[0.715,0.683,0,{ic: 0.0715, krn: {'61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],

[0.828,0.683,0,{ic: 0.0278, krn: {'127': 0.0556}}],

[0.738,0.683,0,{ic: 0.0576, krn: {'127': 0.0833}}],

[0.643,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],

[0.786,0.683,0,{krn: {'127': 0.0833}}],

[0.831,0.683,0,{ic: 0.0812, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],

[0.44,0.683,0,{ic: 0.0785, krn: {'127': 0.111}}],

[0.555,0.683,0,{ic: 0.0962, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.167}}],

[0.849,0.683,0,{ic: 0.0715, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],

[0.681,0.683,0,{krn: {'127': 0.0278}}],

[0.97,0.683,0,{ic: 0.109, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],

[0.803,0.683,0,{ic: 0.109, krn: {'61': -0.0833, '61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],

[0.763,0.683,0,{ic: 0.0278, krn: {'127': 0.0833}}],

[0.642,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],

[0.791,0.683,0.194,{krn: {'127': 0.0833}}],

[0.759,0.683,0,{ic: 0.00773, krn: {'127': 0.0833}}],

[0.613,0.683,0,{ic: 0.0576, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],

[0.584,0.683,0,{ic: 0.139, krn: {'61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],

[0.683,0.683,0,{ic: 0.109, krn: {'59': -0.111, '58': -0.111, '61': -0.0556, '127': 0.0278}}],

[0.583,0.683,0,{ic: 0.222, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],

[0.944,0.683,0,{ic: 0.139, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],

[0.828,0.683,0,{ic: 0.0785, krn: {'61': -0.0833, '61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],

[0.581,0.683,0,{ic: 0.222, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],

[0.683,0.683,0,{ic: 0.0715, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],

[0.389,0.75], [0.389,0.694,0.194], [0.389,0.694,0.194],

[1,0.358,-0.142], [1,0.358,-0.142],

[0.417,0.694,0,{krn: {'127': 0.111}}],

[0.529,0.431], [0.429,0.694], [0.433,0.431,0,{krn: {'127': 0.0556}}],

[0.52,0.694,0,{krn: {'89': 0.0556, '90': -0.0556, '106': -0.111, '102': -0.167, '127': 0.167}}],

[0.466,0.431,0,{krn: {'127': 0.0556}}],

[0.49,0.694,0.194,{ic: 0.108, krn: {'59': -0.0556, '58': -0.0556, '127': 0.167}}],

[0.477,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0278}}],

[0.576,0.694,0,{krn: {'127': -0.0278}}], [0.345,0.66],

[0.412,0.66,0.194,{ic: 0.0572, krn: {'59': -0.0556, '58': -0.0556}}],

[0.521,0.694,0,{ic: 0.0315}], [0.298,0.694,0,{ic: 0.0197, krn: {'127': 0.0833}}],

[0.878,0.431], [0.6,0.431], [0.485,0.431,0,{krn: {'127': 0.0556}}],

[0.503,0.431,0.194,{krn: {'127': 0.0833}}],

[0.446,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0833}}],

[0.451,0.431,0,{ic: 0.0278, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0556}}],

[0.469,0.431,0,{krn: {'127': 0.0556}}], [0.361,0.615,0,{krn: {'127': 0.0833}}],

[0.572,0.431,0,{krn: {'127': 0.0278}}],

[0.485,0.431,0,{ic: 0.0359, krn: {'127': 0.0278}}],

[0.716,0.431,0,{ic: 0.0269, krn: {'127': 0.0833}}],

[0.572,0.431,0,{krn: {'127': 0.0278}}],

[0.49,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0556}}],

[0.465,0.431,0,{ic: 0.044, krn: {'127': 0.0556}}],

[0.322,0.431,0,{krn: {'127': 0.0278}}],

[0.384,0.431,0.194,{krn: {'127': 0.0833}}],

[0.636,0.431,0.194,{krn: {'127': 0.111}}],

[0.5,0.714,0,{ic: 0.154}], [0.278,0.694,0,{ic: 0.399}]

],

cmsy10: [

[0.778,0.583,0.0833], [0.278,0.444,-0.0556], [0.778,0.583,0.0833],

[0.5,0.465,-0.0347], [0.778,0.583,0.0833], [0.5,0.444,-0.0556],

[0.778,0.583,0.0833], [0.778,0.583,0.0833], [0.778,0.583,0.0833],

[0.778,0.583,0.0833], [0.778,0.583,0.0833], [0.778,0.583,0.0833],

[0.778,0.583,0.0833], [1,0.694,0.194], [0.5,0.444,-0.0556], [0.5,0.444,-0.0556],

[0.778,0.464,-0.0363], [0.778,0.464,-0.0363], [0.778,0.636,0.136],

[0.778,0.636,0.136], [0.778,0.636,0.136], [0.778,0.636,0.136],

[0.778,0.636,0.136], [0.778,0.636,0.136], [0.778,0.367,-0.133],

[0.778,0.483,-0.0169], [0.778,0.539,0.0391], [0.778,0.539,0.0391],

[1,0.539,0.0391], [1,0.539,0.0391], [0.778,0.539,0.0391], [0.778,0.539,0.0391],

[1,0.367,-0.133], [1,0.367,-0.133], [0.5,0.694,0.194], [0.5,0.694,0.194],

[1,0.367,-0.133], [1,0.694,0.194], [1,0.694,0.194], [0.778,0.464,-0.0363],

[1,0.367,-0.133], [1,0.367,-0.133], [0.611,0.694,0.194], [0.611,0.694,0.194],

[1,0.367,-0.133], [1,0.694,0.194], [1,0.694,0.194], [0.778,0.431],

[0.275,0.556], [1,0.431], [0.667,0.539,0.0391], [0.667,0.539,0.0391],

[0.889,0.694,0.194], [0.889,0.694,0.194], [0,0.694,0.194], [0,0.367,-0.133],

[0.556,0.694], [0.556,0.694], [0.667,0.431], [0.5,0.75,0.0556],

[0.722,0.694], [0.722,0.694], [0.778,0.694], [0.778,0.694],

[0.611,0.694], [0.798,0.683,0,{krn: {'48': 0.194}}],

[0.657,0.683,0,{ic: 0.0304, krn: {'48': 0.139}}],

[0.527,0.683,0,{ic: 0.0583, krn: {'48': 0.139}}],

[0.771,0.683,0,{ic: 0.0278, krn: {'48': 0.0833}}],

[0.528,0.683,0,{ic: 0.0894, krn: {'48': 0.111}}],

[0.719,0.683,0,{ic: 0.0993, krn: {'48': 0.111}}],

[0.595,0.683,0.0972,{ic: 0.0593, krn: {'48': 0.111}}],

[0.845,0.683,0,{ic: 0.00965, krn: {'48': 0.111}}],

[0.545,0.683,0,{ic: 0.0738, krn: {'48': 0.0278}}],

[0.678,0.683,0.0972,{ic: 0.185, krn: {'48': 0.167}}],

[0.762,0.683,0,{ic: 0.0144, krn: {'48': 0.0556}}],

[0.69,0.683,0,{krn: {'48': 0.139}}], [1.2,0.683,0,{krn: {'48': 0.139}}],

[0.82,0.683,0,{ic: 0.147, krn: {'48': 0.0833}}],

[0.796,0.683,0,{ic: 0.0278, krn: {'48': 0.111}}],

[0.696,0.683,0,{ic: 0.0822, krn: {'48': 0.0833}}],

[0.817,0.683,0.0972,{krn: {'48': 0.111}}],

[0.848,0.683,0,{krn: {'48': 0.0833}}],

[0.606,0.683,0,{ic: 0.075, krn: {'48': 0.139}}],

[0.545,0.683,0,{ic: 0.254, krn: {'48': 0.0278}}],

[0.626,0.683,0,{ic: 0.0993, krn: {'48': 0.0833}}],

[0.613,0.683,0,{ic: 0.0822, krn: {'48': 0.0278}}],

[0.988,0.683,0,{ic: 0.0822, krn: {'48': 0.0833}}],

[0.713,0.683,0,{ic: 0.146, krn: {'48': 0.139}}],

[0.668,0.683,0.0972,{ic: 0.0822, krn: {'48': 0.0833}}],

[0.725,0.683,0,{ic: 0.0794, krn: {'48': 0.139}}],

[0.667,0.556], [0.667,0.556], [0.667,0.556], [0.667,0.556], [0.667,0.556],

[0.611,0.694], [0.611,0.694], [0.444,0.75,0.25], [0.444,0.75,0.25],

[0.444,0.75,0.25], [0.444,0.75,0.25], [0.5,0.75,0.25], [0.5,0.75,0.25],

[0.389,0.75,0.25], [0.389,0.75,0.25], [0.278,0.75,0.25], [0.5,0.75,0.25],

[0.5,0.75,0.25], [0.611,0.75,0.25], [0.5,0.75,0.25], [0.278,0.694,0.194],

[0.833,0.04,0.96], [0.75,0.683], [0.833,0.683], [0.417,0.694,0.194,{ic: 0.111}],

[0.667,0.556], [0.667,0.556], [0.778,0.636,0.136], [0.778,0.636,0.136],

[0.444,0.694,0.194], [0.444,0.694,0.194], [0.444,0.694,0.194],

[0.611,0.694,0.194], [0.778,0.694,0.13], [0.778,0.694,0.13],

[0.778,0.694,0.13], [0.778,0.694,0.13]

],

cmex10: [

[0.458,0.04,1.16,{n: 16}], [0.458,0.04,1.16,{n: 17}],

[0.417,0.04,1.16,{n: 104}], [0.417,0.04,1.16,{n: 105}],

[0.472,0.04,1.16,{n: 106}], [0.472,0.04,1.16,{n: 107}],

[0.472,0.04,1.16,{n: 108}], [0.472,0.04,1.16,{n: 109}],

[0.583,0.04,1.16,{n: 110}], [0.583,0.04,1.16,{n: 111}],

[0.472,0.04,1.16,{n: 68}], [0.472,0.04,1.16,{n: 69}],

[0.333,0,0.6,{delim: {rep: 12}}], [0.556,0,0.6,{delim: {rep: 13}}],

[0.578,0.04,1.16,{n: 46}], [0.578,0.04,1.16,{n: 47}],

[0.597,0.04,1.76,{n: 18}], [0.597,0.04,1.76,{n: 19}],

[0.736,0.04,2.36,{n: 32}], [0.736,0.04,2.36,{n: 33}],

[0.528,0.04,2.36,{n: 34}], [0.528,0.04,2.36,{n: 35}],

[0.583,0.04,2.36,{n: 36}], [0.583,0.04,2.36,{n: 37}],

[0.583,0.04,2.36,{n: 38}], [0.583,0.04,2.36,{n: 39}],

[0.75,0.04,2.36,{n: 40}], [0.75,0.04,2.36,{n: 41}],

[0.75,0.04,2.36,{n: 42}], [0.75,0.04,2.36,{n: 43}],

[1.04,0.04,2.36,{n: 44}], [1.04,0.04,2.36,{n: 45}],

[0.792,0.04,2.96,{n: 48}], [0.792,0.04,2.96,{n: 49}],

[0.583,0.04,2.96,{n: 50}], [0.583,0.04,2.96,{n: 51}],

[0.639,0.04,2.96,{n: 52}], [0.639,0.04,2.96,{n: 53}],

[0.639,0.04,2.96,{n: 54}], [0.639,0.04,2.96,{n: 55}],

[0.806,0.04,2.96,{n: 56}], [0.806,0.04,2.96,{n: 57}],

[0.806,0.04,2.96], [0.806,0.04,2.96],

[1.28,0.04,2.96], [1.28,0.04,2.96],

[0.811,0.04,1.76,{n: 30}], [0.811,0.04,1.76,{n: 31}],

[0.875,0.04,1.76,{delim: {top: 48, bot: 64, rep: 66}}],

[0.875,0.04,1.76,{delim: {top: 49, bot: 65, rep: 67}}],

[0.667,0.04,1.76,{delim: {top: 50, bot: 52, rep: 54}}],

[0.667,0.04,1.76,{delim: {top: 51, bot: 53, rep: 55}}],

[0.667,0.04,1.76,{delim: {bot: 52, rep: 54}}],

[0.667,0.04,1.76,{delim: {bot: 53, rep: 55}}],

[0.667,0,0.6,{delim: {top: 50, rep: 54}}],

[0.667,0,0.6,{delim: {top: 51, rep: 55}}],

[0.889,0,0.9,{delim: {top: 56, mid: 60, bot: 58, rep: 62}}],

[0.889,0,0.9,{delim: {top: 57, mid: 61, bot: 59, rep: 62}}],

[0.889,0,0.9,{delim: {top: 56, bot: 58, rep: 62}}],

[0.889,0,0.9,{delim: {top: 57, bot: 59, rep: 62}}],

[0.889,0,1.8,{delim: {rep: 63}}],

[0.889,0,1.8,{delim: {rep: 119}}],

[0.889,0,0.3,{delim: {rep: 62}}],

[0.667,0,0.6,{delim: {top: 120, bot: 121, rep: 63}}],

[0.875,0.04,1.76,{delim: {top: 56, bot: 59, rep: 62}}],

[0.875,0.04,1.76,{delim: {top: 57, bot: 58, rep: 62}}],

[0.875,0,0.6,{delim: {rep: 66}}], [0.875,0,0.6,{delim: {rep: 67}}],

[0.611,0.04,1.76,{n: 28}], [0.611,0.04,1.76,{n: 29}],

[0.833,0,1,{n: 71}], [1.11,0.1,1.5], [0.472,0,1.11,{ic: 0.194, n: 73}],

[0.556,0,2.22,{ic: 0.444}], [1.11,0,1,{n: 75}], [1.51,0.1,1.5],

[1.11,0,1,{n: 77}], [1.51,0.1,1.5], [1.11,0,1,{n: 79}], [1.51,0.1,1.5],

[1.06,0,1,{n: 88}], [0.944,0,1,{n: 89}], [0.472,0,1.11,{ic: 0.194, n: 90}],

[0.833,0,1,{n: 91}], [0.833,0,1,{n: 92}], [0.833,0,1,{n: 93}],

[0.833,0,1,{n: 94}], [0.833,0,1,{n: 95}], [1.44,0.1,1.5],

[1.28,0.1,1.5], [0.556,0,2.22,{ic: 0.444}], [1.11,0.1,1.5],

[1.11,0.1,1.5], [1.11,0.1,1.5], [1.11,0.1,1.5], [1.11,0.1,1.5],

[0.944,0,1,{n: 97}], [1.28,0.1,1.5], [0.556,0.722,0,{n: 99}],

[1,0.75,0,{n: 100}], [1.44,0.75], [0.556,0.722,0,{n: 102}],

[1,0.75,0,{n: 103}], [1.44,0.75], [0.472,0.04,1.76,{n: 20}],

[0.472,0.04,1.76,{n: 21}], [0.528,0.04,1.76,{n: 22}],

[0.528,0.04,1.76,{n: 23}], [0.528,0.04,1.76,{n: 24}],

[0.528,0.04,1.76,{n: 25}], [0.667,0.04,1.76,{n: 26}],

[0.667,0.04,1.76,{n: 27}],

[1,0.04,1.16,{n: 113}], [1,0.04,1.76,{n: 114}], [1,0.04,2.36,{n: 115}],

[1,0.04,2.96,{n: 116}], [1.06,0,1.8,{delim: {top: 118, bot: 116, rep: 117}}],

[1.06,0,0.6], [1.06,0.04,0.56],

[0.778,0,0.6,{delim: {top: 126, bot: 127, rep: 119}}],

[0.667,0,0.6,{delim: {top: 120, rep: 63}}],

[0.667,0,0.6,{delim: {bot: 121, rep: 63}}],

[0.45,0.12], [0.45,0.12], [0.45,0.12], [0.45,0.12],

[0.778,0,0.6,{delim: {top: 126, rep: 119}}],

[0.778,0,0.6,{delim: {bot: 127, rep: 119}}]

],

cmti10: [

[0.627,0.683,0,{ic: 0.133}], [0.818,0.683], [0.767,0.683,0,{ic: 0.094}],

[0.692,0.683], [0.664,0.683,0,{ic: 0.153}], [0.743,0.683,0,{ic: 0.164}],

[0.716,0.683,0,{ic: 0.12}], [0.767,0.683,0,{ic: 0.111}],

[0.716,0.683,0,{ic: 0.0599}], [0.767,0.683,0,{ic: 0.111}],

[0.716,0.683,0,{ic: 0.103}],

[0.613,0.694,0.194,{ic: 0.212, krn: {'39': 0.104, '63': 0.104, '33': 0.104, '41': 0.104, '93': 0.104}, lig: {'105': 14, '108': 15}}],

[0.562,0.694,0.194,{ic: 0.103}], [0.588,0.694,0.194,{ic: 0.103}],

[0.882,0.694,0.194,{ic: 0.103}], [0.894,0.694,0.194,{ic: 0.103}],

[0.307,0.431,0,{ic: 0.0767}], [0.332,0.431,0.194,{ic: 0.0374}],

[0.511,0.694], [0.511,0.694,0,{ic: 0.0969}], [0.511,0.628,0,{ic: 0.083}],

[0.511,0.694,0,{ic: 0.108}], [0.511,0.562,0,{ic: 0.103}], [0.831,0.694],

[0.46,0,0.17], [0.537,0.694,0.194,{ic: 0.105}], [0.716,0.431,0,{ic: 0.0751}],

[0.716,0.431,0,{ic: 0.0751}], [0.511,0.528,0.0972,{ic: 0.0919}],

[0.883,0.683,0,{ic: 0.12}], [0.985,0.683,0,{ic: 0.12}],

[0.767,0.732,0.0486,{ic: 0.094}],

[0.256,0.431,0,{krn: {'108': -0.256, '76': -0.321}}],

[0.307,0.694,0,{ic: 0.124, lig: {'96': 60}}],

[0.514,0.694,0,{ic: 0.0696}], [0.818,0.694,0.194,{ic: 0.0662}],

[0.769,0.694], [0.818,0.75,0.0556,{ic: 0.136}],

[0.767,0.694,0,{ic: 0.0969}],

[0.307,0.694,0,{ic: 0.124, krn: {'63': 0.102, '33': 0.102}, lig: {'39': 34}}],

[0.409,0.75,0.25,{ic: 0.162}], [0.409,0.75,0.25,{ic: 0.0369}],

[0.511,0.75,0,{ic: 0.149}], [0.767,0.562,0.0567,{ic: 0.0369}],

[0.307,0.106,0.194], [0.358,0.431,0,{ic: 0.0283, lig: {'45': 123}}],

[0.307,0.106], [0.511,0.75,0.25,{ic: 0.162}],

[0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],

[0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],

[0.511,0.644,0.194,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],

[0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0.194,{ic: 0.136}],

[0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],

[0.307,0.431,0,{ic: 0.0582}], [0.307,0.431,0.194,{ic: 0.0582}],

[0.307,0.5,0.194,{ic: 0.0756}], [0.767,0.367,-0.133,{ic: 0.0662}],

[0.511,0.5,0.194], [0.511,0.694,0,{ic: 0.122, lig: {'96': 62}}],

[0.767,0.694,0,{ic: 0.096}],

[0.743,0.683,0,{krn: {'110': -0.0256, '108': -0.0256, '114': -0.0256, '117': -0.0256, '109': -0.0256, '116': -0.0256, '105': -0.0256, '67': -0.0256, '79': -0.0256, '71': -0.0256, '104': -0.0256, '98': -0.0256, '85': -0.0256, '107': -0.0256, '118': -0.0256, '119': -0.0256, '81': -0.0256, '84': -0.0767, '89': -0.0767, '86': -0.102, '87': -0.102, '101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.704,0.683,0,{ic: 0.103}], [0.716,0.683,0,{ic: 0.145}],

[0.755,0.683,0,{ic: 0.094, krn: {'88': -0.0256, '87': -0.0256, '65': -0.0256, '86': -0.0256, '89': -0.0256}}],

[0.678,0.683,0,{ic: 0.12}],

[0.653,0.683,0,{ic: 0.133, krn: {'111': -0.0767, '101': -0.0767, '117': -0.0767, '114': -0.0767, '97': -0.0767, '65': -0.102, '79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],

[0.774,0.683,0,{ic: 0.0872}], [0.743,0.683,0,{ic: 0.164}],

[0.386,0.683,0,{ic: 0.158}], [0.525,0.683,0,{ic: 0.14}],

[0.769,0.683,0,{ic: 0.145, krn: {'79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],

[0.627,0.683,0,{krn: {'84': -0.0767, '89': -0.0767, '86': -0.102, '87': -0.102, '101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.897,0.683,0,{ic: 0.164}], [0.743,0.683,0,{ic: 0.164}],

[0.767,0.683,0,{ic: 0.094, krn: {'88': -0.0256, '87': -0.0256, '65': -0.0256, '86': -0.0256, '89': -0.0256}}],

[0.678,0.683,0,{ic: 0.103, krn: {'65': -0.0767}}],

[0.767,0.683,0.194,{ic: 0.094}],

[0.729,0.683,0,{ic: 0.0387, krn: {'110': -0.0256, '108': -0.0256, '114': -0.0256, '117': -0.0256, '109': -0.0256, '116': -0.0256, '105': -0.0256, '67': -0.0256, '79': -0.0256, '71': -0.0256, '104': -0.0256, '98': -0.0256, '85': -0.0256, '107': -0.0256, '118': -0.0256, '119': -0.0256, '81': -0.0256, '84': -0.0767, '89': -0.0767, '86': -0.102, '87': -0.102, '101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.562,0.683,0,{ic: 0.12}],

[0.716,0.683,0,{ic: 0.133, krn: {'121': -0.0767, '101': -0.0767, '111': -0.0767, '114': -0.0767, '97': -0.0767, '117': -0.0767, '65': -0.0767}}],

[0.743,0.683,0,{ic: 0.164}],

[0.743,0.683,0,{ic: 0.184, krn: {'111': -0.0767, '101': -0.0767, '117': -0.0767, '114': -0.0767, '97': -0.0767, '65': -0.102, '79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],

[0.999,0.683,0,{ic: 0.184, krn: {'65': -0.0767}}],

[0.743,0.683,0,{ic: 0.158, krn: {'79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],

[0.743,0.683,0,{ic: 0.194, krn: {'101': -0.0767, '111': -0.0767, '114': -0.0767, '97': -0.0767, '117': -0.0767, '65': -0.0767}}],

[0.613,0.683,0,{ic: 0.145}], [0.307,0.75,0.25,{ic: 0.188}],

[0.514,0.694,0,{ic: 0.169}], [0.307,0.75,0.25,{ic: 0.105}],

[0.511,0.694,0,{ic: 0.0665}], [0.307,0.668,0,{ic: 0.118}],

[0.307,0.694,0,{ic: 0.124, lig: {'96': 92}}], [0.511,0.431,0,{ic: 0.0767}],

[0.46,0.694,0,{ic: 0.0631, krn: {'101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.46,0.431,0,{ic: 0.0565, krn: {'101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.511,0.694,0,{ic: 0.103, krn: {'108': 0.0511}}],

[0.46,0.431,0,{ic: 0.0751, krn: {'101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.307,0.694,0.194,{ic: 0.212, krn: {'39': 0.104, '63': 0.104, '33': 0.104, '41': 0.104, '93': 0.104}, lig: {'105': 12, '102': 11, '108': 13}}],

[0.46,0.431,0.194,{ic: 0.0885}], [0.511,0.694,0,{ic: 0.0767}],

[0.307,0.655,0,{ic: 0.102}], [0.307,0.655,0.194,{ic: 0.145}],

[0.46,0.694,0,{ic: 0.108}], [0.256,0.694,0,{ic: 0.103, krn: {'108': 0.0511}}],

[0.818,0.431,0,{ic: 0.0767}], [0.562,0.431,0,{ic: 0.0767, krn: {'39': -0.102}}],

[0.511,0.431,0,{ic: 0.0631, krn: {'101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.511,0.431,0.194,{ic: 0.0631, krn: {'101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.46,0.431,0.194,{ic: 0.0885}],

[0.422,0.431,0,{ic: 0.108, krn: {'101': -0.0511, '97': -0.0511, '111': -0.0511, '100': -0.0511, '99': -0.0511, '103': -0.0511, '113': -0.0511}}],

[0.409,0.431,0,{ic: 0.0821}], [0.332,0.615,0,{ic: 0.0949}],

[0.537,0.431,0,{ic: 0.0767}], [0.46,0.431,0,{ic: 0.108}],

[0.664,0.431,0,{ic: 0.108, krn: {'108': 0.0511}}],

[0.464,0.431,0,{ic: 0.12}], [0.486,0.431,0.194,{ic: 0.0885}],

[0.409,0.431,0,{ic: 0.123}], [0.511,0.431,0,{ic: 0.0921, lig: {'45': 124}}],

[1.02,0.431,0,{ic: 0.0921}], [0.511,0.694,0,{ic: 0.122}],

[0.511,0.668,0,{ic: 0.116}], [0.511,0.668,0,{ic: 0.105}]

],

cmbx10: [

[0.692,0.686], [0.958,0.686], [0.894,0.686], [0.806,0.686],

[0.767,0.686], [0.9,0.686], [0.831,0.686], [0.894,0.686],

[0.831,0.686], [0.894,0.686], [0.831,0.686],

[0.671,0.694,0,{ic: 0.109, krn: {'39': 0.109, '63': 0.109, '33': 0.109, '41': 0.109, '93': 0.109}, lig: {'105': 14, '108': 15}}],

[0.639,0.694], [0.639,0.694], [0.958,0.694], [0.958,0.694],

[0.319,0.444], [0.351,0.444,0.194], [0.575,0.694], [0.575,0.694],

[0.575,0.632], [0.575,0.694], [0.575,0.596], [0.869,0.694],

[0.511,0,0.17], [0.597,0.694], [0.831,0.444], [0.894,0.444],

[0.575,0.542,0.0972], [1.04,0.686], [1.17,0.686], [0.894,0.735,0.0486],

[0.319,0.444,0,{krn: {'108': -0.319, '76': -0.378}}],

[0.35,0.694,0,{lig: {'96': 60}}], [0.603,0.694], [0.958,0.694,0.194],

[0.575,0.75,0.0556], [0.958,0.75,0.0556], [0.894,0.694],

[0.319,0.694,0,{krn: {'63': 0.128, '33': 0.128}, lig: {'39': 34}}],

[0.447,0.75,0.25], [0.447,0.75,0.25], [0.575,0.75], [0.894,0.633,0.133],

[0.319,0.156,0.194], [0.383,0.444,0,{lig: {'45': 123}}],

[0.319,0.156], [0.575,0.75,0.25],

[0.575,0.644], [0.575,0.644], [0.575,0.644], [0.575,0.644],

[0.575,0.644], [0.575,0.644], [0.575,0.644], [0.575,0.644],

[0.575,0.644], [0.575,0.644], [0.319,0.444], [0.319,0.444,0.194],

[0.35,0.5,0.194], [0.894,0.391,-0.109], [0.543,0.5,0.194],

[0.543,0.694,0,{lig: {'96': 62}}],

[0.894,0.694],

[0.869,0.686,0,{krn: {'116': -0.0319, '67': -0.0319, '79': -0.0319, '71': -0.0319, '85': -0.0319, '81': -0.0319, '84': -0.0958, '89': -0.0958, '86': -0.128, '87': -0.128}}],

[0.818,0.686], [0.831,0.686],

[0.882,0.686,0,{krn: {'88': -0.0319, '87': -0.0319, '65': -0.0319, '86': -0.0319, '89': -0.0319}}],

[0.756,0.686],

[0.724,0.686,0,{krn: {'111': -0.0958, '101': -0.0958, '117': -0.0958, '114': -0.0958, '97': -0.0958, '65': -0.128, '79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],

[0.904,0.686], [0.9,0.686], [0.436,0.686,0,{krn: {'73': 0.0319}}],

[0.594,0.686],

[0.901,0.686,0,{krn: {'79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],

[0.692,0.686,0,{krn: {'84': -0.0958, '89': -0.0958, '86': -0.128, '87': -0.128}}],

[1.09,0.686], [0.9,0.686],

[0.864,0.686,0,{krn: {'88': -0.0319, '87': -0.0319, '65': -0.0319, '86': -0.0319, '89': -0.0319}}],

[0.786,0.686,0,{krn: {'65': -0.0958, '111': -0.0319, '101': -0.0319, '97': -0.0319, '46': -0.0958, '44': -0.0958}}],

[0.864,0.686,0.194],

[0.862,0.686,0,{krn: {'116': -0.0319, '67': -0.0319, '79': -0.0319, '71': -0.0319, '85': -0.0319, '81': -0.0319, '84': -0.0958, '89': -0.0958, '86': -0.128, '87': -0.128}}],

[0.639,0.686],

[0.8,0.686,0,{krn: {'121': -0.0319, '101': -0.0958, '111': -0.0958, '114': -0.0958, '97': -0.0958, '65': -0.0958, '117': -0.0958}}],

[0.885,0.686],

[0.869,0.686,0,{ic: 0.016, krn: {'111': -0.0958, '101': -0.0958, '117': -0.0958, '114': -0.0958, '97': -0.0958, '65': -0.128, '79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],

[1.19,0.686,0,{ic: 0.016, krn: {'111': -0.0958, '101': -0.0958, '117': -0.0958, '114': -0.0958, '97': -0.0958, '65': -0.128, '79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],

[0.869,0.686,0,{krn: {'79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],

[0.869,0.686,0,{ic: 0.0287, krn: {'101': -0.0958, '111': -0.0958, '114': -0.0958, '97': -0.0958, '65': -0.0958, '117': -0.0958}}],

[0.703,0.686], [0.319,0.75,0.25], [0.603,0.694], [0.319,0.75,0.25],

[0.575,0.694], [0.319,0.694],

[0.319,0.694,0,{lig: {'96': 92}}],

[0.559,0.444,0,{krn: {'118': -0.0319, '106': 0.0639, '121': -0.0319, '119': -0.0319}}],

[0.639,0.694,0,{krn: {'101': 0.0319, '111': 0.0319, '120': -0.0319, '100': 0.0319, '99': 0.0319, '113': 0.0319, '118': -0.0319, '106': 0.0639, '121': -0.0319, '119': -0.0319}}],

[0.511,0.444,0,{krn: {'104': -0.0319, '107': -0.0319}}],

[0.639,0.694], [0.527,0.444],

[0.351,0.694,0,{ic: 0.109, krn: {'39': 0.109, '63': 0.109, '33': 0.109, '41': 0.109, '93': 0.109}, lig: {'105': 12, '102': 11, '108': 13}}],

[0.575,0.444,0.194,{ic: 0.016, krn: {'106': 0.0319}}],

[0.639,0.694,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],

[0.319,0.694], [0.351,0.694,0.194],

[0.607,0.694,0,{krn: {'97': -0.0639, '101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],

[0.319,0.694],

[0.958,0.444,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],

[0.639,0.444,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],

[0.575,0.444,0,{krn: {'101': 0.0319, '111': 0.0319, '120': -0.0319, '100': 0.0319, '99': 0.0319, '113': 0.0319, '118': -0.0319, '106': 0.0639, '121': -0.0319, '119': -0.0319}}],

[0.639,0.444,0.194,{krn: {'101': 0.0319, '111': 0.0319, '120': -0.0319, '100': 0.0319, '99': 0.0319, '113': 0.0319, '118': -0.0319, '106': 0.0639, '121': -0.0319, '119': -0.0319}}],

[0.607,0.444,0.194], [0.474,0.444], [0.454,0.444],

[0.447,0.635,0,{krn: {'121': -0.0319, '119': -0.0319}}],

[0.639,0.444,0,{krn: {'119': -0.0319}}],

[0.607,0.444,0,{ic: 0.016, krn: {'97': -0.0639, '101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],

[0.831,0.444,0,{ic: 0.016, krn: {'101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],

[0.607,0.444],

[0.607,0.444,0.194,{ic: 0.016, krn: {'111': -0.0319, '101': -0.0319, '97': -0.0319, '46': -0.0958, '44': -0.0958}}],

[0.511,0.444], [0.575,0.444,0,{ic: 0.0319, lig: {'45': 124}}],

[1.15,0.444,0,{ic: 0.0319}], [0.575,0.694], [0.575,0.694], [0.575,0.694]

]

};

/***************************************************************************/

/*

* Implement image-based fonts for fallback method

*/

jsMath.Img = {

// font sizes available

fonts: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249, 298, 358, 430],

// em widths for the various font size directories

w: {'50': 6.9, '60': 8.3, '70': 9.7, '85': 11.8, '100': 13.9,

'120': 16.7, '144': 20.0, '173': 24.0, '207': 28.8, '249': 34.6,

'298': 41.4, '358': 49.8, '430': 59.8},

best: 4, // index of best font size in the fonts list

update: {}, // fonts to update (see UpdateFonts below)

factor: 1, // factor by which to shrink images (for better printing)

loaded: 0, // image fonts are loaded

// add characters to be drawn using images

SetFont: function (change) {

for (var font in change) {

if (!this.update[font]) {this.update[font] = []}

this.update[font] = this.update[font].concat(change[font]);

}

},

/*

* Called by the exta-font definition files to add an image font

* into the mix

*/

AddFont: function (size,def) {

if (!jsMath.Img[size]) {jsMath.Img[size] = {}};

jsMath.Add(jsMath.Img[size],def);

},

/*

* Update font(s) to use image data rather than native fonts

* It looks in the jsMath.Img.update array to find the names

* of the fonts to udpate, and the arrays of character codes

* to set (or 'all' to change every character);

*/

UpdateFonts: function () {

var change = this.update; if (!this.loaded) return;

for (var font in change) {

for (var i = 0; i < change[font].length; i++) {

var c = change[font][i];

if (c == 'all') {for (c in jsMath.TeX[font]) {jsMath.TeX[font][c].img = {}}}

else {jsMath.TeX[font][c].img = {}}

}

}

this.update = {};

},

/*

* Find the font size that best fits our current font

* (this is the directory name for the img files used

* in some fallback modes).

*/

BestSize: function () {

var w = jsMath.em * this.factor;

var m = this.w[this.fonts[0]];

for (var i = 1; i < this.fonts.length; i++) {

if (w < (this.w[this.fonts[i]] + 2*m) / 3) {return i-1}

m = this.w[this.fonts[i]];

}

return i-1;

},

/*

* Get the scaling factor for the image fonts

*/

Scale: function () {

if (!this.loaded) return;

this.best = this.BestSize();

this.em = jsMath.Img.w[this.fonts[this.best]];

this.scale = (jsMath.em/this.em);

if (Math.abs(this.scale - 1) < .12) {this.scale = 1}

},

/*

* Get URL to directory for given font and size, based on the

* user's alpha/plain setting

*/

URL: function (name,size,C) {

var type = (jsMath.Controls.cookie.alpha) ? '/alpha/': '/plain/';

// if (C == null) {C = "def.js"} else {C = 'char'+C+'.png'}

if ( C == null ) {

return jsMath.root + 'fonts/' + name+type+'def.js';

}

C = 'char'+C+'.png';

if (size != "") {size += '/'}

return this.root+name+type+size+C;

},

/*

* Laod the data for an image font

*/

LoadFont: function (name) {

if (!this.loaded) this.Init();

jsMath.Setup.Script(this.URL(name,""));

},

/*

* Setup for print mode, and create the hex code table

*/

Init: function () {

if (jsMath.Controls.cookie.print || jsMath.Controls.cookie.stayhires) {

jsMath.Controls.cookie.print = jsMath.Controls.cookie.stayhires;

this.factor *= 3;

if (!jsMath.Controls.isLocalCookie || !jsMath.Global.isLocal) {jsMath.Controls.SetCookie(0)}

if (jsMath.Browser.alphaPrintBug) {jsMath.Controls.cookie.alpha = 0}

}

var codes = '0123456789ABCDEF';

this.HexCode = [];

for (var i = 0; i < 128; i++) {

var h = Math.floor(i/16); var l = i - 16*h;

this.HexCode[i] = codes.charAt(h)+codes.charAt(l);

}

this.loaded = 1;

}

};

/***************************************************************************/

/*

* jsMath.HTML handles creation of most of the HTML needed for

* presenting mathematics in HTML pages.

*/

jsMath.HTML = {

/*

* Produce a string version of a measurement in ems,

* showing only a limited number of digits, and

* using 0 when the value is near zero.

*/

Em: function (m) {

if (Math.abs(m) < .000001) {m = 0}

var s = String(m); s = s.replace(/(\.\d\d\d).+/,'$1');

return s+'em'

},

/*

* Create a horizontal space of width w

*/

Spacer: function (w) {

if (w == 0) {return ''};

return jsMath.Browser.msieSpaceFix+'';

},

/*

* Create a blank rectangle of the given size

* If the height is small, it is converted to pixels so that it

* will not disappear at small font sizes.

*/

Blank: function (w,h,d,isRule) {

var backspace = ; var style =

if (isRule) {

style += 'border-left:'+this.Em(w)+' solid;';

if (jsMath.Browser.widthAddsBorder) {w = 0};

}

if (w == 0) {

if (jsMath.Browser.blankWidthBug) {

if (jsMath.Browser.quirks) {

style += 'width:1px;';

backspace = ''

} else if (!isRule) {

style += 'width:1px;margin-right:-1px;';

}

}

} else {style += 'width:'+this.Em(w)+';'}

if (d == null) {d = 0}

if (h) {

var H = this.Em(h+d);

if (isRule && h*jsMath.em <= 1.5) {H = "1.5px"; h = 1.5/jsMath.em}

style += 'height:'+H+';';

}

if (jsMath.Browser.mozInlineBlockBug) {d = -h}

if (jsMath.Browser.msieBlockDepthBug && !isRule) {d -= jsMath.d}

if (d) {style += 'vertical-align:'+this.Em(-d)}

return backspace+'';

},

/*

* Create a rule line for fractions, etc.

*/

Rule: function (w,h) {

if (h == null) {h = jsMath.TeX.default_rule_thickness}

return this.Blank(w,h,0,1);

},

/*

* Create a strut for measuring position of baseline

*/

Strut: function (h) {return this.Blank(1,h,0,1)},

msieStrut: function (h) {

return ''

},

/*

* Add a tag to activate a specific CSS class

*/

Class: function (tclass,html) {

return ''+html+'';

},

/*

* Use a to place some HTML at a specific position.

* (This can be replaced by the ones below to overcome

* some browser-specific bugs.)

*/

Place: function (html,x,y) {

if (Math.abs(x) < .0001) {x = 0}

if (Math.abs(y) < .0001) {y = 0}

if (x || y) {

var span = '' + html + '';

}

return html;

},

/*

* For MSIE on Windows, backspacing must be done in a separate

* , otherwise the contents will be clipped. Netscape

* also doesn't combine vertical and horizontal spacing well.

* Here the x and y positioning are done in separate tags

*/

PlaceSeparateSkips: function (html,x,y,mw,Mw,w) {

if (Math.abs(x) < .0001) {x = 0}

if (Math.abs(y) < .0001) {y = 0}

if (y) {

var lw = 0; var rw = 0; var width = "";

if (mw != null) {

rw = Mw - w; lw = mw;

width = ' width:'+this.Em(Mw-mw)+';';

}

html =

this.Spacer(lw-rw) +

'' +

this.Spacer(-lw) +

html +

this.Spacer(rw) +

''

}

if (x) {html = this.Spacer(x) + html}

return html;

},

/*

* Place a SPAN with absolute coordinates

*/

PlaceAbsolute: function (html,x,y,mw,Mw,w) {

if (Math.abs(x) < .0001) {x = 0}

if (Math.abs(y) < .0001) {y = 0}

var leftSpace = ""; var rightSpace = ""; var width = "";

if (jsMath.Browser.msieRelativeClipBug && mw != null) {

leftSpace = this.Spacer(-mw); x += mw;

rightSpace = this.Spacer(Mw-w);

}

if (jsMath.Browser.operaAbsoluteWidthBug) {width = " width: "+this.Em(w+2)}

html =

'' +

leftSpace + html + rightSpace +

' ' + // space normalizes line height in script styles

'';

return html;

},

Absolute: function(html,w,h,d,y) {

if (y != "none") {

if (Math.abs(y) < .0001) {y = 0}

html = ''

+ html + ' ' // space normalizes line height in script styles

+ '';

}

if (d == "none") {d = 0}

html += this.Blank((jsMath.Browser.lineBreakBug ? 0 : w),h-d,d);

if (jsMath.Browser.msieAbsoluteBug) { // for MSIE (Mac)

html = '' + html + '';

}

html = '' + html + '';

if (jsMath.Browser.lineBreakBug)

{html = ''+html+''}

return html;

}

};

/***************************************************************************/

/*

* jsMath.Box handles TeX's math boxes and jsMath's equivalent of hboxes.

*/

jsMath.Box = function (format,text,w,h,d) {

if (d == null) {d = jsMath.d}

this.type = 'typeset';

this.w = w; this.h = h; this.d = d; this.bh = h; this.bd = d;

this.x = 0; this.y = 0; this.mw = 0; this.Mw = w;

this.html = text; this.format = format;

};

jsMath.Add(jsMath.Box,{

defaultH: 0, // default height for characters with none specified

/*

* An empty box

*/

Null: function () {return new jsMath.Box('null','',0,0,0)},

/*

* A box containing only text whose class and style haven't been added

* yet (so that we can combine ones with the same styles). It gets

* the text dimensions, if needed. (In general, this has been

* replaced by TeX() below, but is still used in fallback mode.)

*/

Text: function (text,tclass,style,size,a,d) {

var html = jsMath.Typeset.AddClass(tclass,text);

html = jsMath.Typeset.AddStyle(style,size,html);

var BB = jsMath.EmBoxFor(html); var TeX = jsMath.Typeset.TeX(style,size);

var bd = ((tclass == 'cmsy10' || tclass == 'cmex10')? BB.h-TeX.h: TeX.d*BB.h/TeX.hd);

var box = new jsMath.Box('text',text,BB.w,BB.h-bd,bd);

box.style = style; box.size = size; box.tclass = tclass;

if (d != null) {box.d = d*TeX.scale} else {box.d = 0}

if (a == null || a == 1) {box.h = .9*TeX.M_height}

else {box.h = 1.1*TeX.x_height + TeX.scale*a}

return box;

},

/*

* Produce a box containing a given TeX character from a given font.

* The box is a text box (like the ones above), so that characters from

* the same font can be combined.

*/

TeX: function (C,font,style,size) {

var c = jsMath.TeX[font][C];

if (c.d == null) {c.d = 0}; if (c.h == null) {c.h = 0}

if (c.img != null && c.c != '') this.TeXIMG(font,C,jsMath.Typeset.StyleSize(style,size));

var scale = jsMath.Typeset.TeX(style,size).scale;

var box = new jsMath.Box('text',c.c,c.w*scale,c.h*scale,c.d*scale);

box.style = style; box.size = size;

if (c.tclass) {

box.tclass = c.tclass;

if (c.img) {box.bh = c.img.bh; box.bd = c.img.bd}

else {box.bh = scale*jsMath.h; box.bd = scale*jsMath.d}

} else {

box.tclass = font;

box.bh = scale*jsMath.TeX[font].h;

box.bd = scale*jsMath.TeX[font].d;

if (jsMath.Browser.msieFontBug && box.html.match(/&#/)) {

// hack to avoid font changing back to the default

// font when a unicode reference is not followed

// by a letter or number

box.html += 'x';

}

}

return box;

},

/*

* In fallback modes, handle the fact that we don't have the

* sizes of the characters precomputed

*/

TeXfallback: function (C,font,style,size) {

var c = jsMath.TeX[font][C]; if (!c.tclass) {c.tclass = font}

if (c.img != null) {return this.TeXnonfallback(C,font,style,size)}

if (c.h != null && c.a == null) {c.a = c.h-1.1*jsMath.TeX.x_height}

var a = c.a; var d = c.d; // avoid Firefox warnings

var box = this.Text(c.c,c.tclass,style,size,a,d);

var scale = jsMath.Typeset.TeX(style,size).scale;

if (c.bh != null) {

box.bh = c.bh*scale;

box.bd = c.bd*scale;

} else {

var h = box.bd+box.bh;

var html = jsMath.Typeset.AddClass(box.tclass,box.html);

html = jsMath.Typeset.AddStyle(style,size,html);

box.bd = jsMath.EmBoxFor(html + jsMath.HTML.Strut(h)).h - h;

box.bh = h - box.bd;

if (scale == 1) {c.bh = box.bh; c.bd = box.bd}

}

if (jsMath.msieFontBug && box.html.match(/&#/))

{box.html += 'x'}

return box;

},

/*

* Set the character's string to the appropriate image file

*/

TeXIMG: function (font,C,size) {

var c = jsMath.TeX[font][C];

if (c.img.size != null && c.img.size == size &&

c.img.best != null && c.img.best == jsMath.Img.best) return;

var mustScale = (jsMath.Img.scale != 1);

var id = jsMath.Img.best + size - 4;

if (id < 0) {id = 0; mustScale = 1} else

if (id >= jsMath.Img.fonts.length) {id = jsMath.Img.fonts.length-1; mustScale = 1}

var imgFont = jsMath.Img[jsMath.Img.fonts[id]];

var img = imgFont[font][C];

var scale = 1/jsMath.Img.w[jsMath.Img.fonts[id]];

if (id != jsMath.Img.best + size - 4) {

if (c.w != null) {scale = c.w/img[0]} else {

scale *= jsMath.Img.fonts[size]/jsMath.Img.fonts[4]

* jsMath.Img.fonts[jsMath.Img.best]/jsMath.Img.fonts[id];

}

}

var w = img[0]*scale; var h = img[1]*scale; var d = -img[2]*scale; var v;

var wadjust = (c.w == null || Math.abs(c.w-w) < .01)? "" : " margin-right:"+jsMath.HTML.Em(c.w-w)+';';

var resize = ""; C = jsMath.Img.HexCode[C];

if (!mustScale && !jsMath.Controls.cookie.scaleImg) {

if (jsMath.Browser.mozImageSizeBug || 2*w < h ||

(jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha))

{resize = "height:"+(img[1]*jsMath.Browser.imgScale)+'px;'}

resize += " width:"+(img[0]*jsMath.Browser.imgScale)+'px;'

v = -img[2]+'px';

} else {

if (jsMath.Browser.mozImageSizeBug || 2*w < h ||

(jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha))

{resize = "height:"+jsMath.HTML.Em(h*jsMath.Browser.imgScale)+';'}

resize += " width:"+jsMath.HTML.Em(w*jsMath.Browser.imgScale)+';'

v = jsMath.HTML.Em(d);

}

var vadjust = (Math.abs(d) < .01 && !jsMath.Browser.valignBug)?

"": " vertical-align:"+v+';';

var URL = jsMath.Img.URL(font,jsMath.Img.fonts[id],C);

if (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha) {

c.c = '

+ 'style="'+jsMath.Browser.msieCenterBugFix

+ resize + vadjust + wadjust

+ ' filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' + "'"

+ URL + "', sizingMethod='scale'" + ');" />';

} else {

c.c = '';

}

c.tclass = "normal";

c.img.bh = h+d; c.img.bd = -d;

c.img.size = size; c.img.best = jsMath.Img.best;

},

/*

* A box containing a spacer of a specific width

*/

Space: function (w) {

return new jsMath.Box('html',jsMath.HTML.Spacer(w),w,0,0);

},

/*

* A box containing a horizontal rule

*/

Rule: function (w,h) {

if (h == null) {h = jsMath.TeX.default_rule_thickness}

var html = jsMath.HTML.Rule(w,h);

return new jsMath.Box('html',html,w,h,0);

},

/*

* Get a character from a TeX font, and make sure that it has

* its metrics specified.

*/

GetChar: function (code,font) {

var c = jsMath.TeX[font][code];

if (c.img != null) {this.TeXIMG(font,code,4)}

if (c.tclass == null) {c.tclass = font}

if (!c.computedW) {

c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w;

if (c.h == null) {c.h = jsMath.Box.defaultH}; if (c.d == null) {c.d = 0}

c.computedW = 1;

}

return c;

},

/*

* Locate the TeX delimiter character that matches a given height.

* Return the character, font, style and actual height used.

*/

DelimBestFit: function (H,c,font,style) {

if (c == 0 && font == 0) return null;

var C; var h; font = jsMath.TeX.fam[font];

var isSS = (style.charAt(1) == 'S');

var isS = (style.charAt(0) == 'S');

while (c != null) {

C = jsMath.TeX[font][c];

if (C.h == null) {C.h = jsMath.Box.defaultH}; if (C.d == null) {C.d = 0}

h = C.h+C.d;

if (C.delim) {return [c,font,'',H]}

if (isSS && .5*h >= H) {return [c,font,'SS',.5*h]}

if (isS && .7*h >= H) {return [c,font,'S',.7*h]}

if (h >= H || C.n == null) {return [c,font,'T',h]}

c = C.n;

}

return null;

},

/*

* Create the HTML needed for a stretchable delimiter of a given height,

* either centered or not. This version uses relative placement (i.e.,

* backspaces, not line-breaks). This works with more browsers, but

* if the font size changes, the backspacing may not be right, so the

* delimiters may become jagged.

*/

DelimExtendRelative: function (H,c,font,a,nocenter) {

var C = jsMath.TeX[font][c];

var top = this.GetChar(C.delim.top? C.delim.top: C.delim.rep,font);

var rep = this.GetChar(C.delim.rep,font);

var bot = this.GetChar(C.delim.bot? C.delim.bot: C.delim.rep,font);

var ext = jsMath.Typeset.AddClass(rep.tclass,rep.c);

var w = rep.w; var h = rep.h+rep.d

var y; var Y; var html; var dx; var i; var n;

if (C.delim.mid) {// braces

var mid = this.GetChar(C.delim.mid,font);

n = Math.ceil((H-(top.h+top.d)-(mid.h+mid.d)-(bot.h+bot.d))/(2*(rep.h+rep.d)));

H = 2*n*(rep.h+rep.d) + (top.h+top.d) + (mid.h+mid.d) + (bot.h+bot.d);

if (nocenter) {y = 0} else {y = H/2+a}; Y = y;

html = jsMath.HTML.Place(jsMath.Typeset.AddClass(top.tclass,top.c),0,y-top.h)

+ jsMath.HTML.Place(jsMath.Typeset.AddClass(bot.tclass,bot.c),-(top.w+bot.w)/2,y-(H-bot.d))

+ jsMath.HTML.Place(jsMath.Typeset.AddClass(mid.tclass,mid.c),-(bot.w+mid.w)/2,y-(H+mid.h-mid.d)/2);

dx = (w-mid.w)/2; if (Math.abs(dx) < .0001) {dx = 0}

if (dx) {html += jsMath.HTML.Spacer(dx)}

y -= top.h+top.d + rep.h;

for (i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}

y -= H/2 - rep.h/2;

for (i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}

} else {// everything else

n = Math.ceil((H - (top.h+top.d) - (bot.h+bot.d))/(rep.h+rep.d));

// make sure two-headed arrows have an extender

if (top.h+top.d < .9*(rep.h+rep.d)) {n = Math.max(1,n)}

H = n*(rep.h+rep.d) + (top.h+top.d) + (bot.h+bot.d);

if (nocenter) {y = 0} else {y = H/2+a}; Y = y;

html = jsMath.HTML.Place(jsMath.Typeset.AddClass(top.tclass,top.c),0,y-top.h)

dx = (w-top.w)/2; if (Math.abs(dx) < .0001) {dx = 0}

if (dx) {html += jsMath.HTML.Spacer(dx)}

y -= top.h+top.d + rep.h;

for (i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}

html += jsMath.HTML.Place(jsMath.Typeset.AddClass(bot.tclass,bot.c),-(w+bot.w)/2,Y-(H-bot.d));

}

if (nocenter) {h = top.h} else {h = H/2+a}

var box = new jsMath.Box('html',html,rep.w,h,H-h);

box.bh = jsMath.TeX[font].h; box.bd = jsMath.TeX[font].d;

return box;

},

/*

* Create the HTML needed for a stretchable delimiter of a given height,

* either centered or not. This version uses absolute placement (i.e.,

* line-breaks, not backspacing). This gives more reliable results,

* but doesn't work with all browsers.

*/

DelimExtendAbsolute: function (H,c,font,a,nocenter) {

var Font = jsMath.TeX[font];

var C = Font[c]; var html;

var top = this.GetChar(C.delim.top? C.delim.top: C.delim.rep,font);

var rep = this.GetChar(C.delim.rep,font);

var bot = this.GetChar(C.delim.bot? C.delim.bot: C.delim.rep,font);

var n; var h; var y; var ext; var i;

if (C.delim.mid) {// braces

var mid = this.GetChar(C.delim.mid,font);

n = Math.ceil((H-(top.h+top.d)-(mid.h+mid.d-.05)-(bot.h+bot.d-.05))/(2*(rep.h+rep.d-.05)));

H = 2*n*(rep.h+rep.d-.05) + (top.h+top.d) + (mid.h+mid.d-.05) + (bot.h+bot.d-.05);

html = jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(top.tclass,top.c),0,0);

h = rep.h+rep.d - .05; y = top.d-.05 + rep.h;

ext = jsMath.Typeset.AddClass(rep.tclass,rep.c)

for (i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}

html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(mid.tclass,mid.c),0,y+n*h-rep.h+mid.h);

y += n*h + mid.h+mid.d - .05;

for (i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}

html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(bot.tclass,bot.c),0,y+n*h-rep.h+bot.h);

} else {// all others

n = Math.ceil((H - (top.h+top.d) - (bot.h+bot.d-.05))/(rep.h+rep.d-.05));

H = n*(rep.h+rep.d-.05) + (top.h+top.d) + (bot.h+bot.d-.05);

html = jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(top.tclass,top.c),0,0);

h = rep.h+rep.d-.05; y = top.d-.05 + rep.h;

ext = jsMath.Typeset.AddClass(rep.tclass,rep.c);

for (i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}

html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(bot.tclass,bot.c),0,y+n*h-rep.h+bot.h);

}

var w = top.w;

if (nocenter) {h = top.h; y = 0} else {h = H/2 + a; y = h - top.h}

if (jsMath.Controls.cookie.font === "unicode") {

if (jsMath.Browser.msie8HeightBug) {y -= jsMath.hd}

else if (jsMath.Browser.msieBlockDepthBug) {y += jsMath.d}

}

html = jsMath.HTML.Absolute(html,w,Font.h,"none",-y);

var box = new jsMath.Box('html',html,rep.w,h,H-h);

box.bh = jsMath.TeX[font].h; box.bd = jsMath.TeX[font].d;

return box;

},

/*

* Get the HTML for a given delimiter of a given height.

* It will return either a single character, if one exists, or the

* more complex HTML needed for a stretchable delimiter.

*/

Delimiter: function (H,delim,style,nocenter) {

var size = 4; //### pass this?

var TeX = jsMath.Typeset.TeX(style,size);

if (!delim) {return this.Space(TeX.nulldelimiterspace)}

var CFSH = this.DelimBestFit(H,delim[2],delim[1],style);

if (CFSH == null || CFSH[3] < H)

{CFSH = this.DelimBestFit(H,delim[4],delim[3],style)}

if (CFSH == null) {return this.Space(TeX.nulldelimiterspace)}

if (CFSH[2] == '')

{return this.DelimExtend(H,CFSH[0],CFSH[1],TeX.axis_height,nocenter)}

var box = jsMath.Box.TeX(CFSH[0],CFSH[1],CFSH[2],size).Styled();

if (!nocenter) {box.y = -((box.h+box.d)/2 - box.d - TeX.axis_height)}

if (Math.abs(box.y) < .0001) {box.y = 0}

if (box.y) {box = jsMath.Box.SetList([box],CFSH[2],size)}

return box;

},

/*

* Get a character by its TeX charcode, and make sure its width

* is specified.

*/

GetCharCode: function (code) {

var font = jsMath.TeX.fam[code[0]];

var Font = jsMath.TeX[font];

var c = Font[code[1]];

if (c.img != null) {this.TeXIMG(font,code[1],4)}

if (c.w == null) {c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w}

if (c.font == null) {c.font = font}

return c;

},

/*

* Add the class to the html, and use the font if there isn't one

* specified already

*/

AddClass: function (tclass,html,font) {

if (tclass == null) {tclass = font}

return jsMath.Typeset.AddClass(tclass,html);

},

/*

* Create the HTML for an alignment (e.g., array or matrix)

* Since the widths are not really accurate (they are based on pixel

* widths not the sub-pixel widths of the actual characters), there

* is some drift involved. We lay out the table column by column

* to help reduce the problem.

*

* ### still need to allow users to specify row and column attributes,

* and do things like \span and \multispan ###

*/

LayoutRelative: function (size,table,align,cspacing,rspacing,vspace,useStrut,addWidth) {

if (align == null) {align = []}

if (cspacing == null) {cspacing = []}

if (rspacing == null) {rspacing = []}

if (useStrut == null) {useStrut = 1}

if (addWidth == null) {addWidth = 1}

// get row and column maximum dimensions

var scale = jsMath.sizes[size]/100;

var W = []; var H = []; var D = [];

var unset = -1000; var bh = unset; var bd = unset;

var i; var j; var row;

for (i = 0; i < table.length; i++) {

if (rspacing[i] == null) {rspacing[i] = 0}

row = table[i];

H[i] = useStrut*jsMath.h*scale; D[i] = useStrut*jsMath.d*scale;

for (j = 0; j < row.length; j++) {

row[j] = row[j].Remeasured();

if (row[j].h > H[i]) {H[i] = row[j].h}

if (row[j].d > D[i]) {D[i] = row[j].d}

if (j >= W.length) {W[j] = row[j].w}

else if (row[j].w > W[j]) {W[j] = row[j].w}

if (row[j].bh > bh) {bh = row[j].bh}

if (row[j].bd > bd) {bd = row[j].bd}

}

}

if (rspacing[table.length] == null) {rspacing[table.length] = 0}

if (bh == unset) {bh = 0}; if (bd == unset) {bd = 0}

// lay out the columns

var HD = useStrut*(jsMath.hd-.01)*scale;

var dy = (vspace || 1) * scale/6;

var html = ''; var pW = 0; var cW = 0;

var w; var h; var y;

var box; var mlist; var entry;

for (j = 0; j < W.length; j++) {

mlist = []; y = -H[0]-rspacing[0]; pW = 0;

for (i = 0; i < table.length; i++) {

entry = table[i][j];

if (entry && entry.format != 'null') {

if (align[j] == 'l') {w = 0} else

if (align[j] == 'r') {w = W[j] - entry.w} else

{w = (W[j] - entry.w)/2}

entry.x = w - pW; pW = entry.w + w; entry.y = y;

mlist[mlist.length] = entry;

}

if (i+1 < table.length) {y -= Math.max(HD,D[i]+H[i+1]) + dy + rspacing[i+1]}

}

if (cspacing[j] == null) cspacing[j] = scale;

if (mlist.length > 0) {

box = jsMath.Box.SetList(mlist,'T',size);

html += jsMath.HTML.Place(box.html,cW,0);

cW = W[j] - box.w + cspacing[j];

} else {cW += cspacing[j]}

}

// get the full width and height

w = -cspacing[W.length-1]; y = (H.length-1)*dy + rspacing[0];

for (i = 0; i < W.length; i++) {w += W[i] + cspacing[i]}

for (i = 0; i < H.length; i++) {y += Math.max(HD,H[i]+D[i]) + rspacing[i+1]}

h = y/2 + jsMath.TeX.axis_height; var d = y-h;

// adjust the final row width, and vcenter the table

// (add 1/6em at each side for the \,)

html += jsMath.HTML.Spacer(cW-cspacing[W.length-1] + addWidth*scale/6);

html = jsMath.HTML.Place(html,addWidth*scale/6,h);

box = new jsMath.Box('html',html,w+addWidth*scale/3,h,d);

box.bh = bh; box.bd = bd;

return box;

},

/*

* Create the HTML for an alignment (e.g., array or matrix)

* Use absolute position for elements in the array.

*

* ### still need to allow users to specify row and column attributes,

* and do things like \span and \multispan ###

*/

LayoutAbsolute: function (size,table,align,cspacing,rspacing,vspace,useStrut,addWidth) {

if (align == null) {align = []}

if (cspacing == null) {cspacing = []}

if (rspacing == null) {rspacing = []}

if (useStrut == null) {useStrut = 1}

if (addWidth == null) {addWidth = 1}

// get row and column maximum dimensions

var scale = jsMath.sizes[size]/100;

var HD = useStrut*(jsMath.hd-.01)*scale;

var dy = (vspace || 1) * scale/6;

var W = []; var H = []; var D = [];

var w = 0; var h; var x; var y;

var i; var j; var row;

for (i = 0; i < table.length; i++) {

if (rspacing[i] == null) {rspacing[i] = 0}

row = table[i];

H[i] = useStrut*jsMath.h*scale; D[i] = useStrut*jsMath.d*scale;

for (j = 0; j < row.length; j++) {

row[j] = row[j].Remeasured();

if (row[j].h > H[i]) {H[i] = row[j].h}

if (row[j].d > D[i]) {D[i] = row[j].d}

if (j >= W.length) {W[j] = row[j].w}

else if (row[j].w > W[j]) {W[j] = row[j].w}

}

}

if (rspacing[table.length] == null) {rspacing[table.length] = 0}

// get the height and depth of the centered table

y = (H.length-1)*dy + rspacing[0];

for (i = 0; i < H.length; i++) {y += Math.max(HD,H[i]+D[i]) + rspacing[i+1]}

h = y/2 + jsMath.TeX.axis_height; var d = y - h;

// lay out the columns

var html = ''; var entry; w = addWidth*scale/6;

for (j = 0; j < W.length; j++) {

y = H[0]-h + rspacing[0];

for (i = 0; i < table.length; i++) {

entry = table[i][j];

if (entry && entry.format != 'null') {

if (align[j] && align[j] == 'l') {x = 0} else

if (align[j] && align[j] == 'r') {x = W[j] - entry.w} else

{x = (W[j] - entry.w)/2}

html += jsMath.HTML.PlaceAbsolute(entry.html,w+x,

y-Math.max(0,entry.bh-jsMath.h*scale),

entry.mw,entry.Mw,entry.w);

}

if (i+1 < table.length) {y += Math.max(HD,D[i]+H[i+1]) + dy + rspacing[i+1]}

}

if (cspacing[j] == null) cspacing[j] = scale;

w += W[j] + cspacing[j];

}

// get the full width

w = -cspacing[W.length-1]+addWidth*scale/3;

for (i = 0; i < W.length; i++) {w += W[i] + cspacing[i]}

html = jsMath.HTML.Spacer(addWidth*scale/6)+html+jsMath.HTML.Spacer(addWidth*scale/6);

if (jsMath.Browser.spanHeightVaries) {y = h-jsMath.h} else {y = 0}

if (jsMath.Browser.msie8HeightBug) {y = d-jsMath.d}

html = jsMath.HTML.Absolute(html,w,h+d,d,y);

var box = new jsMath.Box('html',html,w+addWidth*scale/3,h,d);

return box;

},

/*

* Look for math within \hbox and other non-math text

*/

InternalMath: function (text,size) {

if (!jsMath.safeHBoxes) {text = text.replace(/@\(([^)]*)\)/g,'<$1>')}

if (!text.match(/\$|\\\(/))

{return this.Text(this.safeHTML(text),'normal','T',size).Styled()}

var i = 0; var k = 0; var c; var match = '';

var mlist = []; var parse, s;

while (i < text.length) {

c = text.charAt(i++);

if (c == '$') {

if (match == '$') {

parse = jsMath.Parse(text.slice(k,i-1),null,size);

if (parse.error) {

mlist[mlist.length] = this.Text(parse.error,'error','T',size,1,.2);

} else {

parse.Atomize();

mlist[mlist.length] = parse.mlist.Typeset('T',size).Styled();

}

match = ''; k = i;

} else {

s = this.safeHTML(text.slice(k,i-1));

mlist[mlist.length] = this.Text(s,'normal','T',size,1,.2);

match = '$'; k = i;

}

} else if (c == '\\') {

c = text.charAt(i++);

if (c == '(' && match == '') {

s = this.safeHTML(text.slice(k,i-2));

mlist[mlist.length] = this.Text(s,'normal','T',size,1,.2);

match = ')'; k = i;

} else if (c == ')' && match == ')') {

parse = jsMath.Parse(text.slice(k,i-2),null,size);

if (parse.error) {

mlist[mlist.length] = this.Text(parse.error,'error','T',size,1,.2);

} else {

parse.Atomize();

mlist[mlist.length] = parse.mlist.Typeset('T',size).Styled();

}

match = ''; k = i;

}

}

}

s = this.safeHTML(text.slice(k));

mlist[mlist.length] = this.Text(s,'normal','T',size,1,.2);

return this.SetList(mlist,'T',size);

},

/*

* Quote HTML characters if we are in safe mode

*/

safeHTML: function (s) {

if (jsMath.safeHBoxes) {

s = s.replace(/&/g,'&')

.replace(/

.replace(/>/g,'>');

}

return s;

},

/*

* Convert an abitrary box to a typeset box. I.e., make an

* HTML version of the contents of the box, at its desired (x,y)

* position.

*/

Set: function (box,style,size,addstyle) {

if (box && box.type) {

if (box.type == 'typeset') {return box}

if (box.type == 'mlist') {

box.mlist.Atomize(style,size);

return box.mlist.Typeset(style,size);

}

if (box.type == 'text') {

box = this.Text(box.text,box.tclass,style,size,box.ascend||null,box.descend||null);

if (addstyle != 0) {box.Styled()}

return box;

}

box = this.TeX(box.c,box.font,style,size);

if (addstyle != 0) {box.Styled()}

return box;

}

return jsMath.Box.Null();

},

/*

* Convert a list of boxes to a single typeset box. I.e., finalize

* the HTML for the list of boxes, properly spaced and positioned.

*/

SetList: function (boxes,style,size) {

var mlist = []; var box;

for (var i = 0; i < boxes.length; i++) {

box = boxes[i];

if (box.type == 'typeset') {box = jsMath.mItem.Typeset(box)}

mlist[mlist.length] = box;

}

var typeset = new jsMath.Typeset(mlist);

return typeset.Typeset(style,size);

}

});

jsMath.Package(jsMath.Box,{

/*

* Add the class and style to a text box (i.e., finalize the

* unpositioned HTML for the box).

*/

Styled: function () {

if (this.format == 'text') {

this.html = jsMath.Typeset.AddClass(this.tclass,this.html);

this.html = jsMath.Typeset.AddStyle(this.style,this.size,this.html);

delete this.tclass; delete this.style;

this.format = 'html';

}

return this;

},

/*

* Recompute the box width to make it more accurate.

*/

Remeasured: function () {

if (this.w > 0) {

var w = this.w; this.w = jsMath.EmBoxFor(this.html).w;

if (this.w > this.Mw) {this.Mw = this.w}

w = this.w/w; if (Math.abs(w-1) > .05) {this.h *= w; this.d *= w}

}

return this;

}

});

/***************************************************************************/

/*

* mItems are the building blocks of mLists (math lists) used to

* store the information about a mathematical expression. These are

* basically the items listed in the TeXbook in Appendix G (plus some

* minor extensions).

*/

jsMath.mItem = function (type,def) {

this.type = type;

jsMath.Add(this,def);

}

jsMath.Add(jsMath.mItem,{

/*

* A general atom (given a nucleus for the atom)

*/

Atom: function (type,nucleus) {

return new jsMath.mItem(type,{atom: 1, nuc: nucleus});

},

/*

* An atom whose nucleus is a piece of text, in a given

* class, with a given additional height and depth

*/

TextAtom: function (type,text,tclass,a,d) {

var atom = new jsMath.mItem(type,{

atom: 1,

nuc: {

type: 'text',

text: text,

tclass: tclass

}

});

if (a != null) {atom.nuc.ascend = a}

if (d != null) {atom.nuc.descend = d}

return atom;

},

/*

* An atom whose nucleus is a TeX character in a specific font

*/

TeXAtom: function (type,c,font) {

return new jsMath.mItem(type,{

atom: 1,

nuc: {

type: 'TeX',

c: c,

font: font

}

});

},

/*

* A generalized fraction atom, with given delimiters, rule

* thickness, and a numerator and denominator.

*/

Fraction: function (name,num,den,thickness,left,right) {

return new jsMath.mItem('fraction',{

from: name, num: num, den: den,

thickness: thickness, left: left, right: right

});

},

/*

* An atom that inserts some glue

*/

Space: function (w) {return new jsMath.mItem('space',{w: w})},

/*

* An atom that contains a typeset box (like an hbox or vbox)

*/

Typeset: function (box) {return new jsMath.mItem('ord',{atom:1, nuc: box})},

/*

* An atom that contains some finished HTML (acts like a typeset box)

*/

HTML: function (html) {return new jsMath.mItem('html',{html: html})}

});

/***************************************************************************/

/*

* mLists are lists of mItems, and encode the contents of

* mathematical expressions and sub-expressions. They act as

* the expression "stack" as the mathematics is parsed, and

* contain some state information, like the position of the

* most recent open paren and \over command, and the current font.

*/

jsMath.mList = function (list,font,size,style) {

if (list) {this.mlist = list} else {this.mlist = []}

if (style == null) {style = 'T'}; if (size == null) {size = 4}

this.data = {openI: null, overI: null, overF: null,

font: font, size: size, style: style};

this.init = {size: size, style: style};

}

jsMath.Package(jsMath.mList,{

/*

* Add an mItem to the list

*/

Add: function (box) {return (this.mlist[this.mlist.length] = box)},

/*

* Get the i-th mItem from the list

*/

Get: function (i) {return this.mlist[i]},

/*

* Get the length of the list

*/

Length: function() {return this.mlist.length},

/*

* Get the tail mItem of the list

*/

Last: function () {

if (this.mlist.length == 0) {return null}

return this.mlist[this.mlist.length-1]

},

/*

* Get a sublist of an mList

*/

Range: function (i,j) {

if (j == null) {j = this.mlist.length}

return new jsMath.mList(this.mlist.slice(i,j+1));

},

/*

* Remove a range of mItems from the list.

*/

Delete: function (i,j) {

if (j == null) {j = i}

if (this.mlist.splice) {this.mlist.splice(i,j-i+1)} else {

var mlist = [];

for (var k = 0; k < this.mlist.length; k++)

{if (k < i || k > j) {mlist[mlist.length] = this.mlist[k]}}

this.mlist = mlist;

}

},

/*

* Add an open brace and maintain the stack information

* about the previous open brace so we can recover it

* when this one os closed.

*/

Open: function (left) {

var box = this.Add(new jsMath.mItem('boundary',{data: this.data}));

var olddata = this.data;

this.data = {}; for (var i in olddata) {this.data[i] = olddata[i]}

delete this.data.overI; delete this.data.overF;

this.data.openI = this.mlist.length-1;

if (left != null) {box.left = left}

return box;

},

/*

* Attempt to close a brace. Recover the stack information

* about previous open braces and \over commands. If there was an

* \over (or \above, etc) in this set of braces, create a fraction

* atom from the two halves, otherwise create an inner or ord

* from the contents of the braces.

* Remove the braced material from the list and add the newly

* created atom (the fraction, inner or ord).

*/

Close: function (right) {

if (right != null) {right = new jsMath.mItem('boundary',{right: right})}

var atom; var open = this.data.openI;

var over = this.data.overI; var from = this.data.overF;

this.data = this.mlist[open].data;

if (over) {

atom = jsMath.mItem.Fraction(from.name,

{type: 'mlist', mlist: this.Range(open+1,over-1)},

{type: 'mlist', mlist: this.Range(over)},

from.thickness,from.left,from.right);

if (right) {

var mlist = new jsMath.mList([this.mlist[open],atom,right]);

atom = jsMath.mItem.Atom('inner',{type: 'mlist', mlist: mlist});

}

} else {

var openI = open+1; if (right) {this.Add(right); openI--}

atom = jsMath.mItem.Atom((right)?'inner':'ord',

{type: 'mlist', mlist: this.Range(openI)});

}

this.Delete(open,this.Length());

return this.Add(atom);

},

/*

* Create a generalized fraction from an mlist that

* contains an \over (or \above, etc).

*/

Over: function () {

var over = this.data.overI; var from = this.data.overF;

var atom = jsMath.mItem.Fraction(from.name,

{type: 'mlist', mlist: this.Range(open+1,over-1)},

{type: 'mlist', mlist: this.Range(over)},

from.thickness,from.left,from.right);

this.mlist = [atom];

},

/*

* Take a raw mList (that has been produced by parsing some TeX

* expression), and perform the modifications outlined in

* Appendix G of the TeXbook.

*/

Atomize: function (style,size) {

var mitem; var prev = '';

this.style = style; this.size = size;

for (var i = 0; i < this.mlist.length; i++) {

mitem = this.mlist[i]; mitem.delta = 0;

if (mitem.type == 'choice')

{this.mlist = this.Atomize.choice(this.style,mitem,i,this.mlist); i--}

else if (this.Atomize[mitem.type]) {

var f = this.Atomize[mitem.type]; // Opera needs separate name

f(this.style,this.size,mitem,prev,this,i);

}

prev = mitem;

}

if (mitem && mitem.type == 'bin') {mitem.type = 'ord'}

if (this.mlist.length >= 2 && mitem.type == 'boundary' &&

this.mlist[0].type == 'boundary') {this.AddDelimiters(style,size)}

},

/*

* For a list that has boundary delimiters as its first and last

* entries, we replace the boundary atoms by open and close

* atoms whose nuclii are the specified delimiters properly sized

* for the contents of the list. (Rule 19)

*/

AddDelimiters: function(style,size) {

var unset = -10000; var h = unset; var d = unset;

for (var i = 0; i < this.mlist.length; i++) {

var mitem = this.mlist[i];

if (mitem.atom || mitem.type == 'box') {

h = Math.max(h,mitem.nuc.h+mitem.nuc.y);

d = Math.max(d,mitem.nuc.d-mitem.nuc.y);

}

}

var TeX = jsMath.TeX; var a = jsMath.Typeset.TeX(style,size).axis_height;

var delta = Math.max(h-a,d+a);

var H = Math.max(Math.floor(TeX.integer*delta/500)*TeX.delimiterfactor,

TeX.integer*(2*delta-TeX.delimitershortfall))/TeX.integer;

var left = this.mlist[0]; var right = this.mlist[this.mlist.length-1];

left.nuc = jsMath.Box.Delimiter(H,left.left,style);

right.nuc = jsMath.Box.Delimiter(H,right.right,style);

left.type = 'open'; left.atom = 1; delete left.left;

right.type = 'close'; right.atom = 1; delete right.right;

},

/*

* Typeset a math list to produce final HTML for the list.

*/

Typeset: function (style,size) {

var typeset = new jsMath.Typeset(this.mlist);

return typeset.Typeset(style,size);

}

});

/*

* These routines implement the main rules given in Appendix G of the

* TeXbook

*/

jsMath.Add(jsMath.mList.prototype.Atomize,{

/*

* Handle \displaystyle, \textstyle, etc.

*/

style: function (style,size,mitem,prev,mlist) {

mlist.style = mitem.style;

},

/*

* Handle \tiny, \small, etc.

*/

size: function (style,size,mitem,prev,mlist) {

mlist.size = mitem.size;

},

/*

* Create empty boxes of the proper sizes for the various

* phantom-type commands

*/

phantom: function (style,size,mitem) {

var box = mitem.nuc = jsMath.Box.Set(mitem.phantom,style,size);

if (mitem.h) {box.Remeasured(); box.html = jsMath.HTML.Spacer(box.w)}

else {box.html = '', box.w = box.Mw = box.mw = 0;}

if (!mitem.v) {box.h = box.d = 0}

box.bd = box.bh = 0;

delete mitem.phantom;

mitem.type = 'box';

},

/*

* Create a box of zero height and depth containing the

* contents of the atom

*/

smash: function (style,size,mitem) {

var box = mitem.nuc = jsMath.Box.Set(mitem.smash,style,size).Remeasured();

box.h = box.d = 0;

delete mitem.smash;

mitem.type = 'box';

},

/*

* Move a box up or down vertically

*/

raise: function (style,size,mitem) {

mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size);

var y = mitem.raise;

mitem.nuc.html =

jsMath.HTML.Place(mitem.nuc.html,0,y,mitem.nuc.mw,mitem.nuc.Mw,mitem.nuc.w);

mitem.nuc.h += y; mitem.nuc.d -= y;

mitem.type = 'ord'; mitem.atom = 1;

},

/*

* Hide the size of a box so that it laps to the left or right, or

* up or down.

*/

lap: function (style,size,mitem) {

var box = jsMath.Box.Set(mitem.nuc,style,size).Remeasured();

var mlist = [box];

if (mitem.lap == 'llap') {box.x = -box.w} else

if (mitem.lap == 'rlap') {mlist[1] = jsMath.mItem.Space(-box.w)} else

if (mitem.lap == 'ulap') {box.y = box.d; box.h = box.d = 0} else

if (mitem.lap == 'dlap') {box.y = -box.h; box.h = box.d = 0}

mitem.nuc = jsMath.Box.SetList(mlist,style,size);

if (mitem.lap == 'ulap' || mitem.lap == 'dlap') {mitem.nuc.h = mitem.nuc.d = 0}

mitem.type = 'box'; delete mitem.atom;

},

/*

* Handle a Bin atom. (Rule 5)

*/

bin: function (style,size,mitem,prev) {

if (prev && prev.type) {

var type = prev.type;

if (type == 'bin' || type == 'op' || type == 'rel' ||

type == 'open' || type == 'punct' || type == '' ||

(type == 'boundary' && prev.left != '')) {mitem.type = 'ord'}

} else {mitem.type = 'ord'}

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle a Rel atom. (Rule 6)

*/

rel: function (style,size,mitem,prev) {

if (prev.type && prev.type == 'bin') {prev.type = 'ord'}

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle a Close atom. (Rule 6)

*/

close: function (style,size,mitem,prev) {

if (prev.type && prev.type == 'bin') {prev.type = 'ord'}

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle a Punct atom. (Rule 6)

*/

punct: function (style,size,mitem,prev) {

if (prev.type && prev.type == 'bin') {prev.type = 'ord'}

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle an Open atom. (Rule 7)

*/

open: function (style,size,mitem) {

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle an Inner atom. (Rule 7)

*/

inner: function (style,size,mitem) {

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle a Vcent atom. (Rule 8)

*/

vcenter: function (style,size,mitem) {

var box = jsMath.Box.Set(mitem.nuc,style,size);

var TeX = jsMath.Typeset.TeX(style,size);

box.y = TeX.axis_height - (box.h-box.d)/2;

mitem.nuc = box; mitem.type = 'ord';

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle an Over atom. (Rule 9)

*/

overline: function (style,size,mitem) {

var TeX = jsMath.Typeset.TeX(style,size);

var box = jsMath.Box.Set(mitem.nuc,jsMath.Typeset.PrimeStyle(style),size).Remeasured();

var t = TeX.default_rule_thickness;

var rule = jsMath.Box.Rule(box.w,t);

rule.x = -rule.w; rule.y = box.h + 3*t;

mitem.nuc = jsMath.Box.SetList([box,rule],style,size);

mitem.nuc.h += t;

mitem.type = 'ord';

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle an Under atom. (Rule 10)

*/

underline: function (style,size,mitem) {

var TeX = jsMath.Typeset.TeX(style,size);

var box = jsMath.Box.Set(mitem.nuc,jsMath.Typeset.PrimeStyle(style),size).Remeasured();

var t = TeX.default_rule_thickness;

var rule = jsMath.Box.Rule(box.w,t);

rule.x = -rule.w; rule.y = -box.d - 3*t - t;

mitem.nuc = jsMath.Box.SetList([box,rule],style,size);

mitem.nuc.d += t;

mitem.type = 'ord';

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle a Rad atom. (Rule 11 plus stuff for \root..\of)

*/

radical: function (style,size,mitem) {

var TeX = jsMath.Typeset.TeX(style,size);

var Cp = jsMath.Typeset.PrimeStyle(style);

var box = jsMath.Box.Set(mitem.nuc,Cp,size).Remeasured();

var t = TeX.default_rule_thickness;

var p = t; if (style == 'D' || style == "D'") {p = TeX.x_height}

var r = t + p/4;

var surd = jsMath.Box.Delimiter(box.h+box.d+r+t,[0,2,0x70,3,0x70],style,1);

// if (surd.h > 0) {t = surd.h} // thickness of rule is height of surd character

if (surd.d > box.h+box.d+r) {r = (r+surd.d-box.h-box.d)/2}

surd.y = box.h+r;

var rule = jsMath.Box.Rule(box.w,t);

rule.y = surd.y-t/2; rule.h += 3*t/2; box.x = -box.w;

var Cr = jsMath.Typeset.UpStyle(jsMath.Typeset.UpStyle(style));

var root = jsMath.Box.Set(mitem.root || null,Cr,size).Remeasured();

if (mitem.root) {

root.y = .55*(box.h+box.d+3*t+r)-box.d;

surd.x = Math.max(root.w-(11/18)*surd.w,0);

rule.x = (7/18)*surd.w;

root.x = -(root.w+rule.x);

}

mitem.nuc = jsMath.Box.SetList([surd,root,rule,box],style,size);

mitem.type = 'ord';

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle an Acc atom. (Rule 12)

*/

accent: function (style,size,mitem) {

var TeX = jsMath.Typeset.TeX(style,size);

var Cp = jsMath.Typeset.PrimeStyle(style);

var box = jsMath.Box.Set(mitem.nuc,Cp,size);

var u = box.w; var s; var Font; var ic = 0;

if (mitem.nuc.type == 'TeX') {

Font = jsMath.TeX[mitem.nuc.font];

if (Font[mitem.nuc.c].krn && Font.skewchar)

{s = Font[mitem.nuc.c].krn[Font.skewchar]}

ic = Font[mitem.nuc.c].ic; if (ic == null) {ic = 0}

}

if (s == null) {s = 0}

var c = mitem.accent[2];

var font = jsMath.TeX.fam[mitem.accent[1]]; Font = jsMath.TeX[font];

while (Font[c].n && Font[Font[c].n].w <= u) {c = Font[c].n}

var delta = Math.min(box.h,TeX.x_height);

if (mitem.nuc.type == 'TeX') {

var nitem = jsMath.mItem.Atom('ord',mitem.nuc);

nitem.sup = mitem.sup; nitem.sub = mitem.sub; nitem.delta = 0;

jsMath.mList.prototype.Atomize.SupSub(style,size,nitem);

delta += (nitem.nuc.h - box.h);

box = mitem.nuc = nitem.nuc;

delete mitem.sup; delete mitem.sub;

}

var acc = jsMath.Box.TeX(c,font,style,size);

acc.y = box.h - delta; acc.x = -box.w + s + (u-acc.w)/2;

if (jsMath.Browser.msieAccentBug)

{acc.html += jsMath.HTML.Spacer(.1); acc.w += .1; acc.Mw += .1}

if (Font[c].ic || ic) {acc.x += (ic - (Font[c].ic||0)) * TeX.scale}

mitem.nuc = jsMath.Box.SetList([box,acc],style,size);

if (mitem.nuc.w != box.w) {

var space = jsMath.mItem.Space(box.w-mitem.nuc.w);

mitem.nuc = jsMath.Box.SetList([mitem.nuc,space],style,size);

}

mitem.type = 'ord';

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle an Op atom. (Rules 13 and 13a)

*/

op: function (style,size,mitem) {

var TeX = jsMath.Typeset.TeX(style,size); var box;

mitem.delta = 0; var isD = (style.charAt(0) == 'D');

if (mitem.limits == null && isD) {mitem.limits = 1}

if (mitem.nuc.type == 'TeX') {

var C = jsMath.TeX[mitem.nuc.font][mitem.nuc.c];

if (isD && C.n) {mitem.nuc.c = C.n; C = jsMath.TeX[mitem.nuc.font][C.n]}

box = mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size);

if (C.ic) {

mitem.delta = C.ic * TeX.scale;

if (mitem.limits || !mitem.sub || jsMath.Browser.msieIntegralBug) {

box = mitem.nuc = jsMath.Box.SetList([box,jsMath.mItem.Space(mitem.delta)],style,size);

}

}

box.y = -((box.h+box.d)/2 - box.d - TeX.axis_height);

if (Math.abs(box.y) < .0001) {box.y = 0}

}

if (!box) {box = mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size).Remeasured()}

if (mitem.limits) {

var W = box.w; var x = box.w;

var mlist = [box]; var dh = 0; var dd = 0;

if (mitem.sup) {

var sup = jsMath.Box.Set(mitem.sup,jsMath.Typeset.UpStyle(style),size).Remeasured();

sup.x = ((box.w-sup.w)/2 + mitem.delta/2) - x; dh = TeX.big_op_spacing5;

W = Math.max(W,sup.w); x += sup.x + sup.w;

sup.y = box.h+sup.d + box.y +

Math.max(TeX.big_op_spacing1,TeX.big_op_spacing3-sup.d);

mlist[mlist.length] = sup; delete mitem.sup;

}

if (mitem.sub) {

var sub = jsMath.Box.Set(mitem.sub,jsMath.Typeset.DownStyle(style),size).Remeasured();

sub.x = ((box.w-sub.w)/2 - mitem.delta/2) - x; dd = TeX.big_op_spacing5;

W = Math.max(W,sub.w); x += sub.x + sub.w;

sub.y = -box.d-sub.h + box.y -

Math.max(TeX.big_op_spacing2,TeX.big_op_spacing4-sub.h);

mlist[mlist.length] = sub; delete mitem.sub;

}

if (W > box.w) {box.x = (W-box.w)/2; x += box.x}

if (x < W) {mlist[mlist.length] = jsMath.mItem.Space(W-x)}

mitem.nuc = jsMath.Box.SetList(mlist,style,size);

mitem.nuc.h += dh; mitem.nuc.d += dd;

} else {

if (jsMath.Browser.msieIntegralBug && mitem.sub && C && C.ic)

{mitem.nuc = jsMath.Box.SetList([box,jsMath.Box.Space(-C.ic*TeX.scale)],style,size)}

else if (box.y) {mitem.nuc = jsMath.Box.SetList([box],style,size)}

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

}

},

/*

* Handle an Ord atom. (Rule 14)

*/

ord: function (style,size,mitem,prev,mList,i) {

if (mitem.nuc.type == 'TeX' && !mitem.sup && !mitem.sub) {

var nitem = mList.mlist[i+1];

if (nitem && nitem.atom && nitem.type &&

(nitem.type == 'ord' || nitem.type == 'op' || nitem.type == 'bin' ||

nitem.type == 'rel' || nitem.type == 'open' ||

nitem.type == 'close' || nitem.type == 'punct')) {

if (nitem.nuc.type == 'TeX' && nitem.nuc.font == mitem.nuc.font) {

mitem.textsymbol = 1;

var krn = jsMath.TeX[mitem.nuc.font][mitem.nuc.c].krn;

krn *= jsMath.Typeset.TeX(style,size).scale;

if (krn && krn[nitem.nuc.c]) {

for (var k = mList.mlist.length-1; k > i; k--)

{mList.mlist[k+1] = mList.mlist[k]}

mList.mlist[i+1] = jsMath.mItem.Space(krn[nitem.nuc.c]);

}

}

}

}

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Handle a generalized fraction. (Rules 15 to 15e)

*/

fraction: function (style,size,mitem) {

var TeX = jsMath.Typeset.TeX(style,size); var t = 0;

if (mitem.thickness != null) {t = mitem.thickness}

else if (mitem.from.match(/over/)) {t = TeX.default_rule_thickness}

var isD = (style.charAt(0) == 'D');

var Cn = (style == 'D')? 'T': (style == "D'")? "T'": jsMath.Typeset.UpStyle(style);

var Cd = (isD)? "T'": jsMath.Typeset.DownStyle(style);

var num = jsMath.Box.Set(mitem.num,Cn,size).Remeasured();

var den = jsMath.Box.Set(mitem.den,Cd,size).Remeasured();

var u; var v; var w; var p; var r;

var H = (isD)? TeX.delim1 : TeX.delim2;

var mlist = [jsMath.Box.Delimiter(H,mitem.left,style)]

var right = jsMath.Box.Delimiter(H,mitem.right,style);

if (num.w < den.w) {

num.x = (den.w-num.w)/2;

den.x = -(num.w + num.x);

w = den.w; mlist[1] = num; mlist[2] = den;

} else {

den.x = (num.w-den.w)/2;

num.x = -(den.w + den.x);

w = num.w; mlist[1] = den; mlist[2] = num;

}

if (isD) {u = TeX.num1; v = TeX.denom1} else {

u = (t != 0)? TeX.num2: TeX.num3;

v = TeX.denom2;

}

if (t == 0) {// atop

p = (isD)? 7*TeX.default_rule_thickness: 3*TeX.default_rule_thickness;

r = (u - num.d) - (den.h - v);

if (r < p) {u += (p-r)/2; v += (p-r)/2}

} else {// over

p = (isD)? 3*t: t; var a = TeX.axis_height;

r = (u-num.d)-(a+t/2); if (r < p) {u += p-r}

r = (a-t/2)-(den.h-v); if (r < p) {v += p-r}

var rule = jsMath.Box.Rule(w,t); rule.x = -w; rule.y = a - t/2;

mlist[mlist.length] = rule;

}

num.y = u; den.y = -v;

mlist[mlist.length] = right;

mitem.nuc = jsMath.Box.SetList(mlist,style,size);

mitem.type = 'ord'; mitem.atom = 1;

delete mitem.num; delete mitem.den;

jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);

},

/*

* Add subscripts and superscripts. (Rules 17-18f)

*/

SupSub: function (style,size,mitem) {

var TeX = jsMath.Typeset.TeX(style,size);

var nuc = mitem.nuc;

var box = mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size,0);

if (box.format == 'null')

{box = mitem.nuc = jsMath.Box.Text('','normal',style,size)}

if (nuc.type == 'TeX') {

if (!mitem.textsymbol) {

var C = jsMath.TeX[nuc.font][nuc.c];

if (C.ic) {

mitem.delta = C.ic * TeX.scale;

if (!mitem.sub) {

box = mitem.nuc = jsMath.Box.SetList([box,jsMath.Box.Space(mitem.delta)],style,size);

mitem.delta = 0;

}

}

} else {mitem.delta = 0}

}

if (!mitem.sup && !mitem.sub) return;

mitem.nuc.Styled();

var Cd = jsMath.Typeset.DownStyle(style);

var Cu = jsMath.Typeset.UpStyle(style);

var q = jsMath.Typeset.TeX(Cu,size).sup_drop;

var r = jsMath.Typeset.TeX(Cd,size).sub_drop;

var u = 0; var v = 0; var p;

if (nuc.type && nuc.type != 'text' && nuc.type != 'TeX' && nuc.type != 'null')

{u = box.h - q; v = box.d + r}

if (mitem.sub) {

var sub = jsMath.Box.Set(mitem.sub,Cd,size);

sub = jsMath.Box.SetList([sub,jsMath.mItem.Space(TeX.scriptspace)],style,size);

}

if (!mitem.sup) {

sub.y = -Math.max(v,TeX.sub1,sub.h-(4/5)*jsMath.Typeset.TeX(Cd,size).x_height);

mitem.nuc = jsMath.Box.SetList([box,sub],style,size).Styled(); delete mitem.sub;

return;

}

var sup = jsMath.Box.Set(mitem.sup,Cu,size);

sup = jsMath.Box.SetList([sup,jsMath.mItem.Space(TeX.scriptspace)],style,size);

if (style == 'D') {p = TeX.sup1}

else if (style.charAt(style.length-1) == "'") {p = TeX.sup3}

else {p = TeX.sup2}

u = Math.max(u,p,sup.d+jsMath.Typeset.TeX(Cu,size).x_height/4);

if (!mitem.sub) {

sup.y = u;

mitem.nuc = jsMath.Box.SetList([box,sup],style,size); delete mitem.sup;

return;

}

v = Math.max(v,jsMath.Typeset.TeX(Cd,size).sub2);

var t = TeX.default_rule_thickness;

if ((u-sup.d) - (sub.h -v) < 4*t) {

v = 4*t + sub.h - (u-sup.d);

p = (4/5)*TeX.x_height - (u-sup.d);

if (p > 0) {u += p; v -= p}

}

sup.Remeasured(); sub.Remeasured();

sup.y = u; sub.y = -v; sup.x = mitem.delta;

if (sup.w+sup.x > sub.w)

{sup.x -= sub.w; mitem.nuc = jsMath.Box.SetList([box,sub,sup],style,size)} else

{sub.x -= (sup.w+sup.x); mitem.nuc = jsMath.Box.SetList([box,sup,sub],style,size)}

delete mitem.sup; delete mitem.sub;

}

});

/***************************************************************************/

/*

* The Typeset object handles most of the TeX-specific processing

*/

jsMath.Typeset = function (mlist) {

this.type = 'typeset';

this.mlist = mlist;

}

jsMath.Add(jsMath.Typeset,{

/*

* The "C-uparrow" style table (TeXbook, p. 441)

*/

upStyle: {

D: "S", T: "S", "D'": "S'", "T'": "S'",

S: "SS", SS: "SS", "S'": "SS'", "SS'": "SS'"

},

/*

* The "C-downarrow" style table (TeXbook, p. 441)

*/

downStyle: {

D: "S'", T: "S'", "D'": "S'", "T'": "S'",

S: "SS'", SS: "SS'", "S'": "SS'", "SS'": "SS'"

},

/*

* Get the various styles given the current style

* (see TeXbook, p. 441)

*/

UpStyle: function (style) {return this.upStyle[style]},

DownStyle: function (style) {return this.downStyle[style]},

PrimeStyle: function (style) {

if (style.charAt(style.length-1) == "'") {return style}

return style + "'"

},

/*

* A value scaled to the appropriate size for scripts

*/

StyleValue: function (style,v) {

if (style == "S" || style == "S'") {return .7*v}

if (style == "SS" || style == "SS'") {return .5*v}

return v;

},

/*

* Return the size associated with a given style and size

*/

StyleSize: function (style,size) {

if (style == "S" || style == "S'") {size = Math.max(0,size-2)}

else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}

return size;

},

/*

* Return the font parameter table for the given style

*/

TeX: function (style,size) {

if (style == "S" || style == "S'") {size = Math.max(0,size-2)}

else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}

return jsMath.TeXparams[size];

},

/*

* Add the CSS class for the given TeX style

*/

AddStyle: function (style,size,html) {

if (style == "S" || style == "S'") {size = Math.max(0,size-2)}

else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}

if (size != 4) {html = '' + html + ''}

return html;

},

/*

* Add the font class, if needed

*/

AddClass: function (tclass,html) {

if (tclass != '' && tclass != 'normal') {html = jsMath.HTML.Class(tclass,html)}

return html;

}

});

jsMath.Package(jsMath.Typeset,{

/*

* The spacing tables for inter-atom spacing

* (See rule 20, and Chapter 18, p 170)

*/

DTsep: {

ord: {op: 1, bin: 2, rel: 3, inner: 1},

op: {ord: 1, op: 1, rel: 3, inner: 1},

bin: {ord: 2, op: 2, open: 2, inner: 2},

rel: {ord: 3, op: 3, open: 3, inner: 3},

open: {},

close: {op: 1, bin:2, rel: 3, inner: 1},

punct: {ord: 1, op: 1, rel: 1, open: 1, close: 1, punct: 1, inner: 1},

inner: {ord: 1, op: 1, bin: 2, rel: 3, open: 1, punct: 1, inner: 1}

},

SSsep: {

ord: {op: 1},

op: {ord: 1, op: 1},

bin: {},

rel: {},

open: {},

close: {op: 1},

punct: {},

inner: {op: 1}

},

/*

* The sizes used in the tables above

*/

sepW: ['','thinmuskip','medmuskip','thickmuskip'],

/*

* Find the amount of separation to use between two adjacent

* atoms in the given style

*/

GetSeparation: function (l,r,style) {

if (l && l.atom && r.atom) {

var table = this.DTsep; if (style.charAt(0) == "S") {table = this.SSsep}

var row = table[l.type];

if (row && row[r.type] != null) {return jsMath.TeX[this.sepW[row[r.type]]]}

}

return 0;

},

/*

* Typeset an mlist (i.e., turn it into HTML).

* Here, text items of the same class and style are combined

* to reduce the number of tags used (though it is still

* huge). Spaces are combined, when possible.

* ### More needs to be done with that. ###

* The width of the final box is recomputed at the end, since

* the final width is not necessarily the sum of the widths of

* the individual parts (widths are in pixels, but the browsers

* puts pieces together using sub-pixel accuracy).

*/

Typeset: function (style,size) {

this.style = style; this.size = size; var unset = -10000

this.w = 0; this.mw = 0; this.Mw = 0;

this.h = unset; this.d = unset;

this.bh = this.h; this.bd = this.d;

this.tbuf = ; this.tx = 0; this.tclass = ;

this.cbuf = ; this.hbuf = ; this.hx = 0;

var mitem = null; var prev; this.x = 0; this.dx = 0;

for (var i = 0; i < this.mlist.length; i++) {

prev = mitem; mitem = this.mlist[i];

switch (mitem.type) {

case 'size':

this.FlushClassed();

this.size = mitem.size;

mitem = prev; // hide this from TeX

break;

case 'style':

this.FlushClassed();

if (this.style.charAt(this.style.length-1) == "'")

{this.style = mitem.style + "'"} else {this.style = mitem.style}

mitem = prev; // hide this from TeX

break;

case 'space':

if (typeof(mitem.w) == 'object') {

if (this.style.charAt(1) == 'S') {mitem.w = .5*mitem.w[0]/18}

else if (this.style.charAt(0) == 'S') {mitem.w = .7*mitem.w[0]/18}

else {mitem.w = mitem.w[0]/18}

}

this.dx += mitem.w-0; // mitem.w is sometimes a string?

mitem = prev; // hide this from TeX

break;

case 'html':

this.FlushClassed();

if (this.hbuf == '') {this.hx = this.x}

this.hbuf += mitem.html;

mitem = prev; // hide this from TeX

break;

default: // atom

if (!mitem.atom && mitem.type != 'box') break;

mitem.nuc.x += this.dx + this.GetSeparation(prev,mitem,this.style);

if (mitem.nuc.x || mitem.nuc.y) mitem.nuc.Styled();

this.dx = 0; this.x = this.x + this.w;

if (this.x + mitem.nuc.x + mitem.nuc.mw < this.mw)

{this.mw = this.x + mitem.nuc.x + mitem.nuc.mw}

if (this.w + mitem.nuc.x + mitem.nuc.Mw > this.Mw)

{this.Mw = this.w + mitem.nuc.x + mitem.nuc.Mw}

this.w += mitem.nuc.w + mitem.nuc.x;

if (mitem.nuc.format == 'text') {

if (this.tclass != mitem.nuc.tclass && this.tclass != '') this.FlushText();

if (this.tbuf == && this.cbuf == ) {this.tx = this.x}

this.tbuf += mitem.nuc.html; this.tclass = mitem.nuc.tclass;

} else {

this.FlushClassed();

if (mitem.nuc.x || mitem.nuc.y) this.Place(mitem.nuc);

if (this.hbuf == '') {this.hx = this.x}

this.hbuf += mitem.nuc.html;

}

this.h = Math.max(this.h,mitem.nuc.h+mitem.nuc.y); this.bh = Math.max(this.bh,mitem.nuc.bh);

this.d = Math.max(this.d,mitem.nuc.d-mitem.nuc.y); this.bd = Math.max(this.bd,mitem.nuc.bd);

break;

}

}

this.FlushClassed(); // make sure scaling is included

if (this.dx) {

this.hbuf += jsMath.HTML.Spacer(this.dx); this.w += this.dx;

if (this.w > this.Mw) {this.Mw = this.w}

if (this.w < this.mw) {this.mw = this.w}

}

if (this.hbuf == '') {return jsMath.Box.Null()}

if (this.h == unset) {this.h = 0}

if (this.d == unset) {this.d = 0}

var box = new jsMath.Box('html',this.hbuf,this.w,this.h,this.d);

box.bh = this.bh; box.bd = this.bd;

box.mw = this.mw; box.Mw = this.Mw;

return box;

},

/*

* Add the font to the buffered text and move it to the

* classed-text buffer.

*/

FlushText: function () {

if (this.tbuf == '') return;

this.cbuf += jsMath.Typeset.AddClass(this.tclass,this.tbuf);

this.tbuf = ; this.tclass = ;

},

/*

* Add the script or scriptscript style to the text and

* move it to the HTML buffer

*/

FlushClassed: function () {

this.FlushText();

if (this.cbuf == '') return;

if (this.hbuf == '') {this.hx = this.tx}

this.hbuf += jsMath.Typeset.AddStyle(this.style,this.size,this.cbuf);

this.cbuf = '';

},

/*

* Add a to position an item's HTML, and

* adjust the item's height and depth.

* (This may be replaced buy one of the following browser-specific

* versions by Browser.Init().)

*/

Place: function (item) {

var html = '' + item.html + '';

item.h += item.y; item.d -= item.y;

item.x = 0; item.y = 0;

},

/*

* For MSIE on Windows, backspacing must be done in a separate

* , otherwise the contents will be clipped. Netscape

* also doesn't combine vertical and horizontal spacing well.

* Here, the horizontal and vertical spacing are done separately.

*/

PlaceSeparateSkips: function (item) {

if (item.y) {

var rw = item.Mw - item.w; var lw = item.mw;

var W = item.Mw - item.mw;

item.html =

jsMath.HTML.Spacer(lw-rw) +

'' +

jsMath.HTML.Spacer(-lw) +

item.html +

jsMath.HTML.Spacer(rw) +

''

}

if (item.x) {item.html = jsMath.HTML.Spacer(item.x) + item.html}

item.h += item.y; item.d -= item.y;

item.x = 0; item.y = 0;

}

});

/***************************************************************************/

/*

* The Parse object handles the parsing of the TeX input string, and creates

* the mList to be typeset by the Typeset object above.

*/

jsMath.Parse = function (s,font,size,style) {

var parse = new jsMath.Parser(s,font,size,style);

parse.Parse();

return parse;

}

jsMath.Parser = function (s,font,size,style) {

this.string = s; this.i = 0;

this.mlist = new jsMath.mList(null,font,size,style);

}

jsMath.Package(jsMath.Parser,{

// special characters

cmd: '\\',

open: '{',

close: '}',

// patterns for letters and numbers

letter: /[a-z]/i,

number: /[0-9]/,

// pattern for macros to ^ and _ that should be read with arguments

scriptargs: /^((math|text)..|mathcal|[hm]box)$/,

// the \mathchar definitions (see Appendix B of the TeXbook).

mathchar: {

'!': [5,0,0x21],

'(': [4,0,0x28],

')': [5,0,0x29],

'*': [2,2,0x03], // \ast

'+': [2,0,0x2B],

',': [6,1,0x3B],

'-': [2,2,0x00],

'.': [0,1,0x3A],

'/': [0,1,0x3D],

':': [3,0,0x3A],

';': [6,0,0x3B],

'<': [3,1,0x3C],

'=': [3,0,0x3D],

'>': [3,1,0x3E],

'?': [5,0,0x3F],

'[': [4,0,0x5B],

']': [5,0,0x5D],

// '{': [4,2,0x66],

// '}': [5,2,0x67],

'|': [0,2,0x6A]

},

// handle special \catcode characters

special: {

'~': 'Tilde',

'^': 'HandleSuperscript',

'_': 'HandleSubscript',

' ': 'Space',

'\01': 'Space',

"\t": 'Space',

"\r": 'Space',

"\n": 'Space',

"'": 'Prime',

'%': 'HandleComment',

'&': 'HandleEntry',

'#': 'Hash'

},

// the \mathchardef table (see Appendix B of the TeXbook).

mathchardef: {

// brace parts

braceld: [0,3,0x7A],

bracerd: [0,3,0x7B],

bracelu: [0,3,0x7C],

braceru: [0,3,0x7D],

// Greek letters

alpha: [0,1,0x0B],

beta: [0,1,0x0C],

gamma: [0,1,0x0D],

delta: [0,1,0x0E],

epsilon: [0,1,0x0F],

zeta: [0,1,0x10],

eta: [0,1,0x11],

theta: [0,1,0x12],

iota: [0,1,0x13],

kappa: [0,1,0x14],

lambda: [0,1,0x15],

mu: [0,1,0x16],

nu: [0,1,0x17],

xi: [0,1,0x18],

pi: [0,1,0x19],

rho: [0,1,0x1A],

sigma: [0,1,0x1B],

tau: [0,1,0x1C],

upsilon: [0,1,0x1D],

phi: [0,1,0x1E],

chi: [0,1,0x1F],

psi: [0,1,0x20],

omega: [0,1,0x21],

varepsilon: [0,1,0x22],

vartheta: [0,1,0x23],

varpi: [0,1,0x24],

varrho: [0,1,0x25],

varsigma: [0,1,0x26],

varphi: [0,1,0x27],

Gamma: [7,0,0x00],

Delta: [7,0,0x01],

Theta: [7,0,0x02],

Lambda: [7,0,0x03],

Xi: [7,0,0x04],

Pi: [7,0,0x05],

Sigma: [7,0,0x06],

Upsilon: [7,0,0x07],

Phi: [7,0,0x08],

Psi: [7,0,0x09],

Omega: [7,0,0x0A],

// Ord symbols

aleph: [0,2,0x40],

imath: [0,1,0x7B],

jmath: [0,1,0x7C],

ell: [0,1,0x60],

wp: [0,1,0x7D],

Re: [0,2,0x3C],

Im: [0,2,0x3D],

partial: [0,1,0x40],

infty: [0,2,0x31],

prime: [0,2,0x30],

emptyset: [0,2,0x3B],

nabla: [0,2,0x72],

surd: [1,2,0x70],

top: [0,2,0x3E],

bot: [0,2,0x3F],

triangle: [0,2,0x34],

forall: [0,2,0x38],

exists: [0,2,0x39],

neg: [0,2,0x3A],

lnot: [0,2,0x3A],

flat: [0,1,0x5B],

natural: [0,1,0x5C],

sharp: [0,1,0x5D],

clubsuit: [0,2,0x7C],

diamondsuit: [0,2,0x7D],

heartsuit: [0,2,0x7E],

spadesuit: [0,2,0x7F],

// big ops

coprod: [1,3,0x60],

bigvee: [1,3,0x57],

bigwedge: [1,3,0x56],

biguplus: [1,3,0x55],

bigcap: [1,3,0x54],

bigcup: [1,3,0x53],

intop: [1,3,0x52],

prod: [1,3,0x51],

sum: [1,3,0x50],

bigotimes: [1,3,0x4E],

bigoplus: [1,3,0x4C],

bigodot: [1,3,0x4A],

ointop: [1,3,0x48],

bigsqcup: [1,3,0x46],

smallint: [1,2,0x73],

// binary operations

triangleleft: [2,1,0x2F],

triangleright: [2,1,0x2E],

bigtriangleup: [2,2,0x34],

bigtriangledown: [2,2,0x35],

wedge: [2,2,0x5E],

land: [2,2,0x5E],

vee: [2,2,0x5F],

lor: [2,2,0x5F],

cap: [2,2,0x5C],

cup: [2,2,0x5B],

ddagger: [2,2,0x7A],

dagger: [2,2,0x79],

sqcap: [2,2,0x75],

sqcup: [2,2,0x74],

uplus: [2,2,0x5D],

amalg: [2,2,0x71],

diamond: [2,2,0x05],

bullet: [2,2,0x0F],

wr: [2,2,0x6F],

div: [2,2,0x04],

odot: [2,2,0x0C],

oslash: [2,2,0x0B],

otimes: [2,2,0x0A],

ominus: [2,2,0x09],

oplus: [2,2,0x08],

mp: [2,2,0x07],

pm: [2,2,0x06],

circ: [2,2,0x0E],

bigcirc: [2,2,0x0D],

setminus: [2,2,0x6E], // for set difference A\setminus B

cdot: [2,2,0x01],

ast: [2,2,0x03],

times: [2,2,0x02],

star: [2,1,0x3F],

// Relations

propto: [3,2,0x2F],

sqsubseteq: [3,2,0x76],

sqsupseteq: [3,2,0x77],

parallel: [3,2,0x6B],

mid: [3,2,0x6A],

dashv: [3,2,0x61],

vdash: [3,2,0x60],

leq: [3,2,0x14],

le: [3,2,0x14],

geq: [3,2,0x15],

ge: [3,2,0x15],

lt: [3,1,0x3C], // extra since < and > are hard

gt: [3,1,0x3E], // to get in HTML

succ: [3,2,0x1F],

prec: [3,2,0x1E],

approx: [3,2,0x19],

succeq: [3,2,0x17],

preceq: [3,2,0x16],

supset: [3,2,0x1B],

subset: [3,2,0x1A],

supseteq: [3,2,0x13],

subseteq: [3,2,0x12],

'in': [3,2,0x32],

ni: [3,2,0x33],

owns: [3,2,0x33],

gg: [3,2,0x1D],

ll: [3,2,0x1C],

not: [3,2,0x36],

sim: [3,2,0x18],

simeq: [3,2,0x27],

perp: [3,2,0x3F],

equiv: [3,2,0x11],

asymp: [3,2,0x10],

smile: [3,1,0x5E],

frown: [3,1,0x5F],

// Arrows

Leftrightarrow: [3,2,0x2C],

Leftarrow: [3,2,0x28],

Rightarrow: [3,2,0x29],

leftrightarrow: [3,2,0x24],

leftarrow: [3,2,0x20],

gets: [3,2,0x20],

rightarrow: [3,2,0x21],

to: [3,2,0x21],

mapstochar: [3,2,0x37],

leftharpoonup: [3,1,0x28],

leftharpoondown: [3,1,0x29],

rightharpoonup: [3,1,0x2A],

rightharpoondown: [3,1,0x2B],

nearrow: [3,2,0x25],

searrow: [3,2,0x26],

nwarrow: [3,2,0x2D],

swarrow: [3,2,0x2E],

minuschar: [3,2,0x00], // for longmapsto

hbarchar: [0,0,0x16], // for \hbar

lhook: [3,1,0x2C],

rhook: [3,1,0x2D],

ldotp: [6,1,0x3A], // ldot as a punctuation mark

cdotp: [6,2,0x01], // cdot as a punctuation mark

colon: [6,0,0x3A], // colon as a punctuation mark

'#': [7,0,0x23],

'$': [7,0,0x24],

'%': [7,0,0x25],

'&': [7,0,0x26]

},

// The delimiter table (see Appendix B of the TeXbook)

delimiter: {

'(': [0,0,0x28,3,0x00],

')': [0,0,0x29,3,0x01],

'[': [0,0,0x5B,3,0x02],

']': [0,0,0x5D,3,0x03],

'<': [0,2,0x68,3,0x0A],

'>': [0,2,0x69,3,0x0B],

'\\lt': [0,2,0x68,3,0x0A], // extra since < and > are

'\\gt': [0,2,0x69,3,0x0B], // hard to get in HTML

'/': [0,0,0x2F,3,0x0E],

'|': [0,2,0x6A,3,0x0C],

'.': [0,0,0x00,0,0x00],

'\\': [0,2,0x6E,3,0x0F],

'\\lmoustache': [4,3,0x7A,3,0x40], // top from (, bottom from )

'\\rmoustache': [5,3,0x7B,3,0x41], // top from ), bottom from (

'\\lgroup': [4,6,0x28,3,0x3A], // extensible ( with sharper tips

'\\rgroup': [5,6,0x29,3,0x3B], // extensible ) with sharper tips

'\\arrowvert': [0,2,0x6A,3,0x3C], // arrow without arrowheads

'\\Arrowvert': [0,2,0x6B,3,0x3D], // double arrow without arrowheads

// '\\bracevert': [0,7,0x7C,3,0x3E], // the vertical bar that extends braces

'\\bracevert': [0,2,0x6A,3,0x3E], // we don't load tt, so use | instead

'\\Vert': [0,2,0x6B,3,0x0D],

'\\|': [0,2,0x6B,3,0x0D],

'\\vert': [0,2,0x6A,3,0x0C],

'\\uparrow': [3,2,0x22,3,0x78],

'\\downarrow': [3,2,0x23,3,0x79],

'\\updownarrow': [3,2,0x6C,3,0x3F],

'\\Uparrow': [3,2,0x2A,3,0x7E],

'\\Downarrow': [3,2,0x2B,3,0x7F],

'\\Updownarrow': [3,2,0x6D,3,0x77],

'\\backslash': [0,2,0x6E,3,0x0F], // for double coset G\backslash H

'\\rangle': [5,2,0x69,3,0x0B],

'\\langle': [4,2,0x68,3,0x0A],

'\\rbrace': [5,2,0x67,3,0x09],

'\\lbrace': [4,2,0x66,3,0x08],

'\\}': [5,2,0x67,3,0x09],

'\\{': [4,2,0x66,3,0x08],

'\\rceil': [5,2,0x65,3,0x07],

'\\lceil': [4,2,0x64,3,0x06],

'\\rfloor': [5,2,0x63,3,0x05],

'\\lfloor': [4,2,0x62,3,0x04],

'\\lbrack': [0,0,0x5B,3,0x02],

'\\rbrack': [0,0,0x5D,3,0x03]

},

/*

* The basic macros for plain TeX.

*

* When the control sequence on the left is called, the JavaScript

* funtion on the right is called, with the name of the control sequence

* as its first parameter (this way, the same function can be called by

* several different control sequences to do similar actions, and the

* function can still tell which TeX command was issued). If the right

* is an array, the first entry is the routine to call, and the

* remaining entries in the array are parameters to pass to the function

* as the second parameter (they are in an array reference).

*

* Note: TeX macros as defined by the user are discussed below.

*/

macros: {

displaystyle: ['HandleStyle','D'],

textstyle: ['HandleStyle','T'],

scriptstyle: ['HandleStyle','S'],

scriptscriptstyle: ['HandleStyle','SS'],

rm: ['HandleFont',0],

mit: ['HandleFont',1],

oldstyle: ['HandleFont',1],

cal: ['HandleFont',2],

it: ['HandleFont',4],

bf: ['HandleFont',6],

font: ['Extension','font'],

left: 'HandleLeft',

right: 'HandleRight',

arcsin: ['NamedOp',0],

arccos: ['NamedOp',0],

arctan: ['NamedOp',0],

arg: ['NamedOp',0],

cos: ['NamedOp',0],

cosh: ['NamedOp',0],

cot: ['NamedOp',0],

coth: ['NamedOp',0],

csc: ['NamedOp',0],

deg: ['NamedOp',0],

det: 'NamedOp',

dim: ['NamedOp',0],

exp: ['NamedOp',0],

gcd: 'NamedOp',

hom: ['NamedOp',0],

inf: 'NamedOp',

ker: ['NamedOp',0],

lg: ['NamedOp',0],

lim: 'NamedOp',

liminf: ['NamedOp',null,'liminf'],

limsup: ['NamedOp',null,'limsup'],

ln: ['NamedOp',0],

log: ['NamedOp',0],

max: 'NamedOp',

min: 'NamedOp',

Pr: 'NamedOp',

sec: ['NamedOp',0],

sin: ['NamedOp',0],

sinh: ['NamedOp',0],

sup: 'NamedOp',

tan: ['NamedOp',0],

tanh: ['NamedOp',0],

vcenter: ['HandleAtom','vcenter'],

overline: ['HandleAtom','overline'],

underline: ['HandleAtom','underline'],

over: 'HandleOver',

overwithdelims: 'HandleOver',

atop: 'HandleOver',

atopwithdelims: 'HandleOver',

above: 'HandleOver',

abovewithdelims: 'HandleOver',

brace: ['HandleOver','\\{','\\}'],

brack: ['HandleOver','[',']'],

choose: ['HandleOver','(',')'],

overbrace: ['Extension','leaders'],

underbrace: ['Extension','leaders'],

overrightarrow: ['Extension','leaders'],

underrightarrow: ['Extension','leaders'],

overleftarrow: ['Extension','leaders'],

underleftarrow: ['Extension','leaders'],

overleftrightarrow: ['Extension','leaders'],

underleftrightarrow: ['Extension','leaders'],

overset: ['Extension','underset-overset'],

underset: ['Extension','underset-overset'],

llap: 'HandleLap',

rlap: 'HandleLap',

ulap: 'HandleLap',

dlap: 'HandleLap',

raise: 'RaiseLower',

lower: 'RaiseLower',

moveleft: 'MoveLeftRight',

moveright: 'MoveLeftRight',

frac: 'Frac',

root: 'Root',

sqrt: 'Sqrt',

// TeX substitution macros

hbar: ['Macro','\\hbarchar\\kern-.5em h'],

ne: ['Macro','\\not='],

neq: ['Macro','\\not='],

notin: ['Macro','\\mathrel{\\rlap{\\kern2mu/}}\\in'],

cong: ['Macro','\\mathrel{\\lower2mu{\\mathrel{{\\rlap{=}\\raise6mu\\sim}}}}'],

bmod: ['Macro','\\mathbin{\\rm mod}'],

pmod: ['Macro','\\kern 18mu ({\\rm mod}\\,\\,#1)',1],

'int': ['Macro','\\intop\\nolimits'],

oint: ['Macro','\\ointop\\nolimits'],

doteq: ['Macro','\\buildrel\\textstyle.\\over='],

ldots: ['Macro','\\mathinner{\\ldotp\\ldotp\\ldotp}'],

cdots: ['Macro','\\mathinner{\\cdotp\\cdotp\\cdotp}'],

vdots: ['Macro','\\mathinner{\\rlap{\\raise8pt{.\\rule 0pt 6pt 0pt}}\\rlap{\\raise4pt{.}}.}'],

ddots: ['Macro','\\mathinner{\\kern1mu\\raise7pt{\\rule 0pt 7pt 0pt .}\\kern2mu\\raise4pt{.}\\kern2mu\\raise1pt{.}\\kern1mu}'],

joinrel: ['Macro','\\mathrel{\\kern-4mu}'],

relbar: ['Macro','\\mathrel{\\smash-}'], // \smash, because - has the same height as +

Relbar: ['Macro','\\mathrel='],

bowtie: ['Macro','\\mathrel\\triangleright\\joinrel\\mathrel\\triangleleft'],

models: ['Macro','\\mathrel|\\joinrel='],

mapsto: ['Macro','\\mathrel{\\mapstochar\\rightarrow}'],

rightleftharpoons: ['Macro','\\vcenter{\\mathrel{\\rlap{\\raise3mu{\\rightharpoonup}}}\\leftharpoondown}'],

hookrightarrow: ['Macro','\\lhook\\joinrel\\rightarrow'],

hookleftarrow: ['Macro','\\leftarrow\\joinrel\\rhook'],

Longrightarrow: ['Macro','\\Relbar\\joinrel\\Rightarrow'],

longrightarrow: ['Macro','\\relbar\\joinrel\\rightarrow'],

longleftarrow: ['Macro','\\leftarrow\\joinrel\\relbar'],

Longleftarrow: ['Macro','\\Leftarrow\\joinrel\\Relbar'],

longmapsto: ['Macro','\\mathrel{\\mapstochar\\minuschar\\joinrel\\rightarrow}'],

longleftrightarrow: ['Macro','\\leftarrow\\joinrel\\rightarrow'],

Longleftrightarrow: ['Macro','\\Leftarrow\\joinrel\\Rightarrow'],

iff: ['Macro','\\;\\Longleftrightarrow\\;'],

mathcal: ['Macro','{\\cal #1}',1],

mathrm: ['Macro','{\\rm #1}',1],

mathbf: ['Macro','{\\bf #1}',1],

mathbb: ['Macro','{\\bf #1}',1],

mathit: ['Macro','{\\it #1}',1],

textrm: ['Macro','\\mathord{\\hbox{#1}}',1],

textit: ['Macro','\\mathord{\\class{textit}{\\hbox{#1}}}',1],

textbf: ['Macro','\\mathord{\\class{textbf}{\\hbox{#1}}}',1],

pmb: ['Macro','\\rlap{#1}\\kern1px{#1}',1],

TeX: ['Macro','T\\kern-.1667em\\lower.5ex{E}\\kern-.125em X'],

limits: ['Limits',1],

nolimits: ['Limits',0],

',': ['Spacer',1/6],

':': ['Spacer',1/6], // for LaTeX

'>': ['Spacer',2/9],

';': ['Spacer',5/18],

'!': ['Spacer',-1/6],

enspace: ['Spacer',1/2],

quad: ['Spacer',1],

qquad: ['Spacer',2],

thinspace: ['Spacer',1/6],

negthinspace: ['Spacer',-1/6],

hskip: 'Hskip',

kern: 'Hskip',

rule: ['Rule','colored'],

space: ['Rule','blank'],

big: ['MakeBig','ord',0.85],

Big: ['MakeBig','ord',1.15],

bigg: ['MakeBig','ord',1.45],

Bigg: ['MakeBig','ord',1.75],

bigl: ['MakeBig','open',0.85],

Bigl: ['MakeBig','open',1.15],

biggl: ['MakeBig','open',1.45],

Biggl: ['MakeBig','open',1.75],

bigr: ['MakeBig','close',0.85],

Bigr: ['MakeBig','close',1.15],

biggr: ['MakeBig','close',1.45],

Biggr: ['MakeBig','close',1.75],

bigm: ['MakeBig','rel',0.85],

Bigm: ['MakeBig','rel',1.15],

biggm: ['MakeBig','rel',1.45],

Biggm: ['MakeBig','rel',1.75],

mathord: ['HandleAtom','ord'],

mathop: ['HandleAtom','op'],

mathopen: ['HandleAtom','open'],

mathclose: ['HandleAtom','close'],

mathbin: ['HandleAtom','bin'],

mathrel: ['HandleAtom','rel'],

mathpunct: ['HandleAtom','punct'],

mathinner: ['HandleAtom','inner'],

mathchoice: ['Extension','mathchoice'],

buildrel: 'BuildRel',

hbox: 'HBox',

text: 'HBox',

mbox: 'HBox',

fbox: ['Extension','fbox'],

strut: 'Strut',

mathstrut: ['Macro','\\vphantom{(}'],

phantom: ['Phantom',1,1],

vphantom: ['Phantom',1,0],

hphantom: ['Phantom',0,1],

smash: 'Smash',

acute: ['MathAccent', [7,0,0x13]],

grave: ['MathAccent', [7,0,0x12]],

ddot: ['MathAccent', [7,0,0x7F]],

tilde: ['MathAccent', [7,0,0x7E]],

bar: ['MathAccent', [7,0,0x16]],

breve: ['MathAccent', [7,0,0x15]],

check: ['MathAccent', [7,0,0x14]],

hat: ['MathAccent', [7,0,0x5E]],

vec: ['MathAccent', [0,1,0x7E]],

dot: ['MathAccent', [7,0,0x5F]],

widetilde: ['MathAccent', [0,3,0x65]],

widehat: ['MathAccent', [0,3,0x62]],

'_': ['Replace','ord','_','normal',-.4,.1],

' ': ['Replace','ord',' ','normal'],

// angle: ['Replace','ord','∠','normal'],

angle: ['Macro','\\kern2.5mu\\raise1.54pt{\\rlap{\\scriptstyle \\char{cmsy10}{54}}\\kern1pt\\rule{.45em}{-1.2pt}{1.54pt}\\kern2.5mu}'],

matrix: 'Matrix',

array: 'Matrix', // ### still need to do alignment options ###

pmatrix: ['Matrix','(',')','c'],

cases: ['Matrix','\\{','.',['l','l'],null,2],

eqalign: ['Matrix',null,null,['r','l'],[5/18],3,'D'],

displaylines: ['Matrix',null,null,['c'],null,3,'D'],

cr: 'HandleRow',

'\\': 'HandleRow',

newline: 'HandleRow',

noalign: 'HandleNoAlign',

eqalignno: ['Matrix',null,null,['r','l','r'],[5/8,3],3,'D'],

leqalignno: ['Matrix',null,null,['r','l','r'],[5/8,3],3,'D'],

// LaTeX

begin: 'Begin',

end: 'End',

tiny: ['HandleSize',0],

Tiny: ['HandleSize',1], // non-standard

scriptsize: ['HandleSize',2],

small: ['HandleSize',3],

normalsize: ['HandleSize',4],

large: ['HandleSize',5],

Large: ['HandleSize',6],

LARGE: ['HandleSize',7],

huge: ['HandleSize',8],

Huge: ['HandleSize',9],

dots: ['Macro','\\ldots'],

newcommand: ['Extension','newcommand'],

newenvironment: ['Extension','newcommand'],

def: ['Extension','newcommand'],

// Extensions to TeX

color: ['Extension','HTML'],

href: ['Extension','HTML'],

'class': ['Extension','HTML'],

style: ['Extension','HTML'],

cssId: ['Extension','HTML'],

unicode: ['Extension','HTML'],

bbox: ['Extension','bbox'],

require: 'Require',

// debugging and test routines

'char': 'Char'

},

/*

* LaTeX environments

*/

environments: {

array: 'Array',

matrix: ['Array',null,null,'c'],

pmatrix: ['Array','(',')','c'],

bmatrix: ['Array','[',']','c'],

Bmatrix: ['Array','\\{','\\}','c'],

vmatrix: ['Array','\\vert','\\vert','c'],

Vmatrix: ['Array','\\Vert','\\Vert','c'],

cases: ['Array','\\{','.','ll',null,2],

eqnarray: ['Array',null,null,'rcl',[5/18,5/18],3,'D'],

'eqnarray*': ['Array',null,null,'rcl',[5/18,5/18],3,'D'],

equation: 'Equation',

'equation*': 'Equation',

align: ['Extension','AMSmath'],

'align*': ['Extension','AMSmath'],

aligned: ['Extension','AMSmath'],

multline: ['Extension','AMSmath'],

'multline*': ['Extension','AMSmath'],

split: ['Extension','AMSmath'],

gather: ['Extension','AMSmath'],

'gather*': ['Extension','AMSmath'],

gathered: ['Extension','AMSmath']

},

/***************************************************************************/

/*

* Add special characters to list above. (This makes it possible

* to define them in a variable that the user can change.)

*/

AddSpecial: function (obj) {

for (var id in obj) {

jsMath.Parser.prototype.special[jsMath.Parser.prototype[id]] = obj[id];

}

},

/*

* Throw an error

*/

Error: function (s) {

this.i = this.string.length;

if (s.error) {this.error = s.error} else {

if (!this.error) {this.error = s}

}

},

/***************************************************************************/

/*

* Check if the next character is a space

*/

nextIsSpace: function () {

return this.string.charAt(this.i).match(/[ \n\r\t]/);

},

/*

* Trim spaces from a string

*/

trimSpaces: function (text) {

if (typeof(text) != 'string') {return text}

return text.replace(/^\s+|\s+$/g,'');

},

/*

* Parse a substring to get its mList, and return it.

* Check that no errors occured

*/

Process: function (arg) {

var data = this.mlist.data;

arg = jsMath.Parse(arg,data.font,data.size,data.style);

if (arg.error) {this.Error(arg); return null}

if (arg.mlist.Length() == 0) {return null}

if (arg.mlist.Length() == 1) {

var atom = arg.mlist.Last();

if (atom.atom && atom.type == 'ord' && atom.nuc &&

!atom.sub && !atom.sup && (atom.nuc.type == 'text' || atom.nuc.type == 'TeX'))

{return atom.nuc}

}

return {type: 'mlist', mlist: arg.mlist};

},

/*

* Get and return a control-sequence name from the TeX string

*/

GetCommand: function () {

var letter = /^([a-z]+|.) ?/i;

var cmd = letter.exec(this.string.slice(this.i));

if (cmd) {this.i += cmd[1].length; return cmd[1]}

this.i++; return " ";

},

/*

* Get and return a TeX argument (either a single character or control sequence,

* or the contents of the next set of braces).

*/

GetArgument: function (name,noneOK) {

while (this.nextIsSpace()) {this.i++}

if (this.i >= this.string.length) {if (!noneOK) this.Error("Missing argument for "+name); return null}

if (this.string.charAt(this.i) == this.close) {if (!noneOK) this.Error("Extra close brace"); return null}

if (this.string.charAt(this.i) == this.cmd) {this.i++; return this.cmd+this.GetCommand()}

if (this.string.charAt(this.i) != this.open) {return this.string.charAt(this.i++)}

var j = ++this.i; var pcount = 1; var c = '';

while (this.i < this.string.length) {

c = this.string.charAt(this.i++);

if (c == this.cmd) {this.i++}

else if (c == this.open) {pcount++}

else if (c == this.close) {

if (pcount == 0) {this.Error("Extra close brace"); return null}

if (--pcount == 0) {return this.string.slice(j,this.i-1)}

}

}

this.Error("Missing close brace");

return null;

},

/*

* Get an argument and process it into an mList

*/

ProcessArg: function (name) {

var arg = this.GetArgument(name); if (this.error) {return null}

return this.Process(arg);

},

/*

* Get and process an argument for a super- or subscript.

* (read extra args for \frac, \sqrt, \mathrm, etc.)

* This handles these macros as special cases, so is really

* rather a hack. A more general method for indicating

* how to handle macros in scripts needs to be developed.

*/

ProcessScriptArg: function (name) {

var arg = this.GetArgument(name); if (this.error) {return null}

if (arg.charAt(0) == this.cmd) {

var csname = arg.substr(1);

if (csname == "frac") {

arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}

arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}

} else if (csname == "sqrt") {

arg += '['+this.GetBrackets(csname)+']'; if (this.error) {return null}

arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}

} else if (csname.match(this.scriptargs)) {

arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}

}

}

return this.Process(arg);

},

/*

* Get the name of a delimiter (check it in the delimiter list).

*/

GetDelimiter: function (name) {

while (this.nextIsSpace()) {this.i++}

var c = this.string.charAt(this.i);

if (this.i < this.string.length) {

this.i++;

if (c == this.cmd) {c = '\\'+this.GetCommand(name); if (this.error) return null}

if (this.delimiter[c] != null) {return this.delimiter[c]}

}

this.Error("Missing or unrecognized delimiter for "+name);

return null;

},

/*

* Get a dimension (including its units).

* Convert the dimen to em's, except for mu's, which must be

* converted when typeset.

*/

GetDimen: function (name,nomu) {

var rest; var advance = 0;

if (this.nextIsSpace()) {this.i++}

if (this.string.charAt(this.i) == '{') {

rest = this.GetArgument(name);

} else {

rest = this.string.slice(this.i);

advance = 1;

}

return this.ParseDimen(rest,name,advance,nomu);

},

ParseDimen: function (dimen,name,advance,nomu) {

var match = dimen.match(/^\s*([-+]?(\.\d+|\d+(\.\d*)?))(pt|em|ex|mu|px)/);

if (!match) {this.Error("Missing dimension or its units for "+name); return null}

if (advance) {

this.i += match[0].length;

if (this.nextIsSpace()) {this.i++}

}

var d = match[1]-0;

if (match[4] == 'px') {d /= jsMath.em}

else if (match[4] == 'pt') {d /= 10}

else if (match[4] == 'ex') {d *= jsMath.TeX.x_height}

else if (match[4] == 'mu') {if (nomu) {d = d/18} else {d = [d,'mu']}}

return d;

},

/*

* Get the next non-space character

*/

GetNext: function () {

while (this.nextIsSpace()) {this.i++}

return this.string.charAt(this.i);

},

/*

* Get an optional LaTeX argument in brackets

*/

GetBrackets: function (name) {

var c = this.GetNext(); if (c != '[') return '';

var start = ++this.i; var pcount = 0;

while (this.i < this.string.length) {

c = this.string.charAt(this.i++);

if (c == '{') {pcount++}

else if (c == '}') {

if (pcount == 0)

{this.Error("Extra close brace while looking for ']'"); return null}

pcount --;

} else if (c == this.cmd) {

this.i++;

} else if (c == ']') {

if (pcount == 0) {return this.string.slice(start,this.i-1)}

}

}

this.Error("Couldn't find closing ']' for argument to "+this.cmd+name);

return null;

},

/*

* Get everything up to the given control sequence name (token)

*/

GetUpto: function (name,token) {

while (this.nextIsSpace()) {this.i++}

var start = this.i; var pcount = 0;

while (this.i < this.string.length) {

var c = this.string.charAt(this.i++);

if (c == '{') {pcount++}

else if (c == '}') {

if (pcount == 0)

{this.Error("Extra close brace while looking for "+this.cmd+token); return null}

pcount --;

} else if (c == this.cmd) {

// really need separate counter for begin/end

// and it should really be a stack (new pcount for each begin)

if (this.string.slice(this.i,this.i+5) == "begin") {pcount++; this.i+=4}

else if (this.string.slice(this.i,this.i+3) == "end") {

if (pcount > 0) {pcount--; this.i += 2}

}

if (pcount == 0) {

if (this.string.slice(this.i,this.i+token.length) == token) {

c = this.string.charAt(this.i+token.length);

if (c.match(/[^a-z]/i) || !token.match(/[a-z]/i)) {

var arg = this.string.slice(start,this.i-1);

this.i += token.length;

return arg;

}

}

}

this.i++;

}

}

this.Error("Couldn't find "+this.cmd+token+" for "+name);

return null;

},

/*

* Get a parameter delimited by a control sequence, and

* process it to get its mlist

*/

ProcessUpto: function (name,token) {

var arg = this.GetUpto(name,token); if (this.error) return null;

return this.Process(arg);

},

/*

* Get everything up to \end{env}

*/

GetEnd: function (env) {

var body = ; var name = ;

while (name != env) {

body += this.GetUpto('begin{'+env+'}','end'); if (this.error) return null;

name = this.GetArgument(this.cmd+'end'); if (this.error) return null;

}

return body;

},

/***************************************************************************/

/*

* Ignore spaces

*/

Space: function () {},

/*

* Collect together any primes and convert them to a superscript

*/

Prime: function (c) {

var base = this.mlist.Last();

if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))

{base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}

if (base.sup) {this.Error("Prime causes double exponent: use braces to clarify"); return}

var sup = '';

while (c == "'") {sup += this.cmd+'prime'; c = this.GetNext(); if (c == "'") {this.i++}}

base.sup = this.Process(sup);

base.sup.isPrime = 1;

},

/*

* Raise or lower its parameter by a given amount

* @@@ Note that this is different from TeX, which requires an \hbox @@@

* ### make this work with mu's ###

*/

RaiseLower: function (name) {

var h = this.GetDimen(this.cmd+name,1); if (this.error) return;

var box = this.ProcessScriptArg(this.cmd+name); if (this.error) return;

if (name == 'lower') {h = -h}

this.mlist.Add(new jsMath.mItem('raise',{nuc: box, raise: h}));

},

/*

* Shift an expression to the right or left

* @@@ Note that this is different from TeX, which requires a \vbox @@@

* ### make this work with mu's ###

*/

MoveLeftRight: function (name) {

var x = this.GetDimen(this.cmd+name,1); if (this.error) return;

var box = this.ProcessScriptArg(this.cmd+name); if (this.error) return;

if (name == 'moveleft') {x = -x}

this.mlist.Add(jsMath.mItem.Space(x));

this.mlist.Add(jsMath.mItem.Atom('ord',box));

this.mlist.Add(jsMath.mItem.Space(-x));

},

/*

* Load an extension if it has not already been loaded

*/

Require: function (name) {

var file = this.GetArgument(this.cmd+name); if (this.error) return;

file = jsMath.Extension.URL(file);

if (jsMath.Setup.loaded[file]) return;

this.Extension(null,[file]);

},

/*

* Load an extension file and restart processing the math

*/

Extension: function (name,data) {

jsMath.Translate.restart = 1;

if (name != null) {delete jsMath.Parser.prototype[data[1]||'macros'][name]}

jsMath.Extension.Require(data[0],jsMath.Translate.asynchronous);

throw "restart";

},

/*

* Implements \frac{num}{den}

*/

Frac: function (name) {

var num = this.ProcessArg(this.cmd+name); if (this.error) return;

var den = this.ProcessArg(this.cmd+name); if (this.error) return;

this.mlist.Add(jsMath.mItem.Fraction('over',num,den));

},

/*

* Implements \sqrt[n]{...}

*/

Sqrt: function (name) {

var n = this.GetBrackets(this.cmd+name); if (this.error) return;

var arg = this.ProcessArg(this.cmd+name); if (this.error) return;

var box = jsMath.mItem.Atom('radical',arg);

if (n != '') {box.root = this.Process(n); if (this.error) return}

this.mlist.Add(box);

},

/*

* Implements \root...\of{...}

*/

Root: function (name) {

var n = this.ProcessUpto(this.cmd+name,'of'); if (this.error) return;

var arg = this.ProcessArg(this.cmd+name); if (this.error) return;

var box = jsMath.mItem.Atom('radical',arg);

box.root = n; this.mlist.Add(box);

},

/*

* Implements \buildrel...\over{...}

*/

BuildRel: function (name) {

var top = this.ProcessUpto(this.cmd+name,'over'); if (this.error) return;

var bot = this.ProcessArg(this.cmd+name); if (this.error) return;

var op = jsMath.mItem.Atom('op',bot);

op.limits = 1; op.sup = top;

this.mlist.Add(op);

},

/*

* Create a delimiter of the type and size specified in the parameters

*/

MakeBig: function (name,data) {

var type = data[0]; var h = data[1] * jsMath.p_height;

var delim = this.GetDelimiter(this.cmd+name); if (this.error) return;

this.mlist.Add(jsMath.mItem.Atom(type,jsMath.Box.Delimiter(h,delim,'T')));

},

/*

* Insert the specified character in the given font.

* (Try to load the font if it is not already available.)

*/

Char: function (name) {

var font = this.GetArgument(this.cmd+name); if (this.error) return;

var n = this.GetArgument(this.cmd+name); if (this.error) return;

if (!jsMath.TeX[font]) {

jsMath.TeX[font] = [];

this.Extension(null,[jsMath.Font.URL(font)]);

} else {

this.mlist.Add(jsMath.mItem.Typeset(jsMath.Box.TeX(n-0,font,this.mlist.data.style,this.mlist.data.size)));

}

},

/*

* Create an array or matrix.

*/

Matrix: function (name,delim) {

var data = this.mlist.data;

var arg = this.GetArgument(this.cmd+name); if (this.error) return;

var parse = new jsMath.Parser(arg+this.cmd+'\\',null,data.size,delim[5] || 'T');

parse.matrix = name; parse.row = []; parse.table = []; parse.rspacing = [];

parse.Parse(); if (parse.error) {this.Error(parse); return}

parse.HandleRow(name,1); // be sure the last row is recorded

var box = jsMath.Box.Layout(data.size,parse.table,delim[2]||null,delim[3]||null,parse.rspacing,delim[4]||null);

// Add parentheses, if needed

if (delim[0] && delim[1]) {

var left = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[0]],'T');

var right = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[1]],'T');

box = jsMath.Box.SetList([left,box,right],data.style,data.size);

}

this.mlist.Add(jsMath.mItem.Atom((delim[0]? 'inner': 'ord'),box));

},

/*

* When we see an '&', try to add a matrix entry to the row data.

* (Use all the data in the current mList, and then clear it)

*/

HandleEntry: function (name) {

if (!this.matrix)

{this.Error(name+" can only appear in a matrix or array"); return}

if (this.mlist.data.openI != null) {

var open = this.mlist.Get(this.mlist.data.openI);

if (open.left) {this.Error("Missing "+this.cmd+"right")}

else {this.Error("Missing close brace")}

}

if (this.mlist.data.overI != null) {this.mlist.Over()}

var data = this.mlist.data;

this.mlist.Atomize(data.style,data.size);

var box = this.mlist.Typeset(data.style,data.size);

box.entry = data.entry; delete data.entry; if (!box.entry) {box.entry = {}};

this.row[this.row.length] = box;

this.mlist = new jsMath.mList(null,null,data.size,data.style);

},

/*

* When we see a \cr or \\, try to add a row to the table

*/

HandleRow: function (name,last) {

var dimen;

if (!this.matrix) {this.Error(this.cmd+name+" can only appear in a matrix or array"); return}

if (name == "\\") {

dimen = this.GetBrackets(this.cmd+name); if (this.error) return;

if (dimen) {dimen = this.ParseDimen(dimen,this.cmd+name,0,1)}

}

this.HandleEntry(name);

if (!last || this.row.length > 1 || this.row[0].format != 'null')

{this.table[this.table.length] = this.row}

if (dimen) {this.rspacing[this.table.length] = dimen}

this.row = [];

},

/*

* Look for \vskip or \vspace in \noalign parameters

*/

HandleNoAlign: function (name) {

var arg = this.GetArgument(this.cmd+name); if (this.error) return;

var skip = arg.replace(/^.*(vskip|vspace)([^a-z])/i,'$2');

if (skip.length == arg.length) return;

var d = this.ParseDimen(skip,this.cmd+RegExp.$1,0,1); if (this.error) return;

this.rspacing[this.table.length] = (this.rspacing[this.table.length] || 0) + d;

},

/*

* LaTeX array environment

*/

Array: function (name,delim) {

var columns = delim[2]; var cspacing = delim[3];

if (!columns) {

columns = this.GetArgument(this.cmd+'begin{'+name+'}');

if (this.error) return;

}

columns = columns.replace(/[^clr]/g,'');

columns = columns.split('');

var data = this.mlist.data; var style = delim[5] || 'T';

var arg = this.GetEnd(name); if (this.error) return;

var parse = new jsMath.Parser(arg+this.cmd+'\\',null,data.size,style);

parse.matrix = name; parse.row = []; parse.table = []; parse.rspacing = [];

parse.Parse(); if (parse.error) {this.Error(parse); return}

parse.HandleRow(name,1); // be sure the last row is recorded

var box = jsMath.Box.Layout(data.size,parse.table,columns,cspacing,parse.rspacing,delim[4],delim[6],delim[7]);

// Add parentheses, if needed

if (delim[0] && delim[1]) {

var left = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[0]],'T');

var right = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[1]],'T');

box = jsMath.Box.SetList([left,box,right],data.style,data.size);

}

this.mlist.Add(jsMath.mItem.Atom((delim[0]? 'inner': 'ord'),box));

},

/*

* LaTeX \begin{env}

*/

Begin: function (name) {

var env = this.GetArgument(this.cmd+name); if (this.error) return;

if (env.match(/[^a-z*]/i)) {this.Error('Invalid environment name "'+env+'"'); return}

if (!this.environments[env]) {this.Error('Unknown environment "'+env+'"'); return}

var cmd = this.environments[env];

if (typeof(cmd) == "string") {cmd = [cmd]}

this[cmd[0]](env,cmd.slice(1));

},

/*

* LaTeX \end{env}

*/

End: function (name) {

var env = this.GetArgument(this.cmd+name); if (this.error) return;

this.Error(this.cmd+name+'{'+env+'} without matching '+this.cmd+'begin');

},

/*

* LaTeX equation environment (just remove the environment)

*/

Equation: function (name) {

var arg = this.GetEnd(name); if (this.error) return;

this.string = arg+this.string.slice(this.i); this.i = 0;

},

/*

* Add a fixed amount of horizontal space

*/

Spacer: function (name,w) {

this.mlist.Add(jsMath.mItem.Space(w-0));

},

/*

* Add horizontal space given by the argument

*/

Hskip: function (name) {

var w = this.GetDimen(this.cmd+name); if (this.error) return;

this.mlist.Add(jsMath.mItem.Space(w));

},

/*

* Typeset the argument as plain text rather than math.

*/

HBox: function (name) {

var text = this.GetArgument(this.cmd+name); if (this.error) return;

var box = jsMath.Box.InternalMath(text,this.mlist.data.size);

this.mlist.Add(jsMath.mItem.Typeset(box));

},

/*

* Insert a rule of a particular width, height and depth

* This replaces \hrule and \vrule

* @@@ not a standard TeX command, and all three parameters must be given @@@

*/

Rule: function (name,style) {

var w = this.GetDimen(this.cmd+name,1); if (this.error) return;

var h = this.GetDimen(this.cmd+name,1); if (this.error) return;

var d = this.GetDimen(this.cmd+name,1); if (this.error) return;

h += d; var html;

if (h != 0) {h = Math.max(1.05/jsMath.em,h)}

if (h == 0 || w == 0 || style == "blank")

{html = jsMath.HTML.Blank(w,h)} else {html = jsMath.HTML.Rule(w,h)}

if (d) {

html = ''

+ html + '';

}

this.mlist.Add(jsMath.mItem.Typeset(new jsMath.Box('html',html,w,h-d,d)));

},

/*

* Inserts an empty box of a specific height and depth

*/

Strut: function () {

var size = this.mlist.data.size;

var box = jsMath.Box.Text('','normal','T',size).Styled();

box.bh = box.bd = 0; box.h = .8; box.d = .3; box.w = box.Mw = 0;

this.mlist.Add(jsMath.mItem.Typeset(box));

},

/*

* Handles \phantom, \vphantom and \hphantom

*/

Phantom: function (name,data) {

var arg = this.ProcessArg(this.cmd+name); if (this.error) return;

this.mlist.Add(new jsMath.mItem('phantom',{phantom: arg, v: data[0], h: data[1]}));

},

/*

* Implements \smash

*/

Smash: function (name,data) {

var arg = this.ProcessArg(this.cmd+name); if (this.error) return;

this.mlist.Add(new jsMath.mItem('smash',{smash: arg}));

},

/*

* Puts an accent on the following argument

*/

MathAccent: function (name,accent) {

var c = this.ProcessArg(this.cmd+name); if (this.error) return;

var atom = jsMath.mItem.Atom('accent',c); atom.accent = accent[0];

this.mlist.Add(atom);

},

/*

* Handles functions and operators like sin, cos, sum, etc.

*/

NamedOp: function (name,data) {

var a = (name.match(/[^acegm-su-z]/)) ? 1: 0;

var d = (name.match(/[gjpqy]/)) ? .2: 0;

if (data[1]) {name = data[1]}

var box = jsMath.mItem.TextAtom('op',name,jsMath.TeX.fam[0],a,d);

if (data[0] != null) {box.limits = data[0]}

this.mlist.Add(box);

},

/*

* Implements \limits

*/

Limits: function (name,data) {

var atom = this.mlist.Last();

if (!atom || atom.type != 'op')

{this.Error(this.cmd+name+" is allowed only on operators"); return}

atom.limits = data[0];

},

/*

* Implements macros like those created by \def. The named control

* sequence is replaced by the string given as the first data value.

* If there is a second data value, this specifies how many arguments

* the macro uses, and in this case, those arguments are substituted

* for #1, #2, etc. within the replacement string.

*

* See the jsMath.Macro() command below for more details.

* The "newcommand" extension implements \newcommand and \def

* and are loaded automatically if needed.

*/

Macro: function (name,data) {

var text = data[0];

if (data[1]) {

var args = [];

for (var i = 0; i < data[1]; i++)

{args[args.length] = this.GetArgument(this.cmd+name); if (this.error) return}

text = this.SubstituteArgs(args,text);

}

this.string = this.AddArgs(text,this.string.slice(this.i));

this.i = 0;

},

/*

* Replace macro paramters with their values

*/

SubstituteArgs: function (args,string) {

var text = ; var newstring = ; var c; var i = 0;

while (i < string.length) {

c = string.charAt(i++);

if (c == this.cmd) {text += c + string.charAt(i++)}

else if (c == '#') {

c = string.charAt(i++);

if (c == "#") {text += c} else {

if (!c.match(/[1-9]/) || c > args.length)

{this.Error("Illegal macro parameter reference"); return null}

newstring = this.AddArgs(this.AddArgs(newstring,text),args[c-1]);

text = '';

}

} else {text += c}

}

return this.AddArgs(newstring,text);

},

/*

* Make sure that macros are followed by a space if their names

* could accidentally be continued into the following text.

*/

AddArgs: function (s1,s2) {

if (s2.match(/^[a-z]/i) && s1.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)) {s1 += ' '}

return s1+s2;

},

/*

* Replace the control sequence with the given text

*/

Replace: function (name,data) {

this.mlist.Add(jsMath.mItem.TextAtom(data[0],data[1],data[2],data[3]));

},

/*

* Error for # (must use \#)

*/

Hash: function (name) {

this.Error("You can't use 'macro parameter character #' in math mode");

},

/*

* Insert space for ~

*/

Tilde: function (name) {

this.mlist.Add(jsMath.mItem.TextAtom('ord',' ','normal'));

},

/*

* Implements \llap, \rlap, etc.

*/

HandleLap: function (name) {

var box = this.ProcessArg(); if (this.error) return;

box = this.mlist.Add(new jsMath.mItem('lap',{nuc: box, lap: name}));

},

/*

* Adds the argument as a specific type of atom (for commands like

* \overline, etc.)

*/

HandleAtom: function (name,data) {

var arg = this.ProcessArg(this.cmd+name); if (this.error) return;

this.mlist.Add(jsMath.mItem.Atom(data[0],arg));

},

/*

* Process the character associated with a specific \mathcharcode

*/

HandleMathCode: function (name,code) {

this.HandleTeXchar(code[0],code[1],code[2]);

},

/*

* Add a specific character from a TeX font (use the current

* font if the type is 7 (variable) or the font is not specified)

* Load the font if it is not already loaded.

*/

HandleTeXchar: function (type,font,code) {

if (type == 7 && this.mlist.data.font != null) {font = this.mlist.data.font}

font = jsMath.TeX.fam[font];

if (!jsMath.TeX[font]) {

jsMath.TeX[font] = [];

this.Extension(null,[jsMath.Font.URL(font)]);

} else {

this.mlist.Add(jsMath.mItem.TeXAtom(jsMath.TeX.atom[type],code,font));

}

},

/*

* Add a TeX variable character or number

*/

HandleVariable: function (c) {this.HandleTeXchar(7,1,c.charCodeAt(0))},

HandleNumber: function (c) {this.HandleTeXchar(7,0,c.charCodeAt(0))},

/*

* For unmapped characters, just add them in as normal

* (non-TeX) characters

*/

HandleOther: function (c) {

this.mlist.Add(jsMath.mItem.TextAtom('ord',c,'normal'));

},

/*

* Ignore comments in TeX data

* ### Some browsers remove the newlines, so this might cause

* extra stuff to be ignored; look into this ###

*/

HandleComment: function () {

var c;

while (this.i < this.string.length) {

c = this.string.charAt(this.i++);

if (c == "\r" || c == "\n") return;

}

},

/*

* Add a style change (e.g., \displaystyle, etc)

*/

HandleStyle: function (name,style) {

this.mlist.data.style = style[0];

this.mlist.Add(new jsMath.mItem('style',{style: style[0]}));

},

/*

* Implements \small, \large, etc.

*/

HandleSize: function (name,size) {

this.mlist.data.size = size[0];

this.mlist.Add(new jsMath.mItem('size',{size: size[0]}));

},

/*

* Set the current font (e.g., \rm, etc)

*/

HandleFont: function (name,font) {

this.mlist.data.font = font[0];

},

/*

* Look for and process a control sequence

*/

HandleCS: function () {

var cmd = this.GetCommand(); if (this.error) return;

if (this.macros[cmd]) {

var macro = this.macros[cmd];

if (typeof(macro) == "string") {macro = [macro]}

this[macro[0]](cmd,macro.slice(1)); return;

}

if (this.mathchardef[cmd]) {

this.HandleMathCode(cmd,this.mathchardef[cmd]);

return;

}

if (this.delimiter[this.cmd+cmd]) {

this.HandleMathCode(cmd,this.delimiter[this.cmd+cmd].slice(0,3))

return;

}

this.Error("Unknown control sequence '"+this.cmd+cmd+"'");

},

/*

* Process open and close braces

*/

HandleOpen: function () {this.mlist.Open()},

HandleClose: function () {

if (this.mlist.data.openI == null) {this.Error("Extra close brace"); return}

var open = this.mlist.Get(this.mlist.data.openI);

if (!open || open.left == null) {this.mlist.Close()}

else {this.Error("Extra close brace or missing "+this.cmd+"right"); return}

},

/*

* Implements \left

*/

HandleLeft: function (name) {

var left = this.GetDelimiter(this.cmd+name); if (this.error) return;

this.mlist.Open(left);

},

/*

* Implements \right

*/

HandleRight: function (name) {

var right = this.GetDelimiter(this.cmd+name); if (this.error) return;

var open = this.mlist.Get(this.mlist.data.openI);

if (open && open.left != null) {this.mlist.Close(right)}

else {this.Error("Extra open brace or missing "+this.cmd+"left");}

},

/*

* Implements generalized fractions (\over, \above, etc.)

*/

HandleOver: function (name,data) {

if (this.mlist.data.overI != null)

{this.Error('Ambiguous use of '+this.cmd+name); return}

this.mlist.data.overI = this.mlist.Length();

this.mlist.data.overF = {name: name};

if (data.length > 0) {

this.mlist.data.overF.left = this.delimiter[data[0]];

this.mlist.data.overF.right = this.delimiter[data[1]];

} else if (name.match(/withdelims$/)) {

this.mlist.data.overF.left = this.GetDelimiter(this.cmd+name); if (this.error) return;

this.mlist.data.overF.right = this.GetDelimiter(this.cmd+name); if (this.error) return;

} else {

this.mlist.data.overF.left = null;

this.mlist.data.overF.right = null;

}

if (name.match(/^above/)) {

this.mlist.data.overF.thickness = this.GetDimen(this.cmd+name,1);

if (this.error) return;

} else {

this.mlist.data.overF.thickness = null;

}

},

/*

* Add a superscript to the preceeding atom

*/

HandleSuperscript: function () {

var base = this.mlist.Last();

if (this.mlist.data.overI == this.mlist.Length()) {base = null}

if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))

{base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}

if (base.sup) {

if (base.sup.isPrime) {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}

else {this.Error("Double exponent: use braces to clarify"); return}

}

base.sup = this.ProcessScriptArg('superscript'); if (this.error) return;

},

/*

* Add a subscript to the preceeding atom

*/

HandleSubscript: function () {

var base = this.mlist.Last();

if (this.mlist.data.overI == this.mlist.Length()) {base = null}

if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))

{base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}

if (base.sub) {this.Error("Double subscripts: use braces to clarify"); return}

base.sub = this.ProcessScriptArg('subscript'); if (this.error) return;

},

/*

* Parse a TeX math string, handling macros, etc.

*/

Parse: function () {

var c;

while (this.i < this.string.length) {

c = this.string.charAt(this.i++);

if (this.mathchar[c]) {this.HandleMathCode(c,this.mathchar[c])}

else if (this.special[c]) {this[this.special[c]](c)}

else if (this.letter.test(c)) {this.HandleVariable(c)}

else if (this.number.test(c)) {this.HandleNumber(c)}

else {this.HandleOther(c)}

}

if (this.mlist.data.openI != null) {

var open = this.mlist.Get(this.mlist.data.openI);

if (open.left) {this.Error("Missing "+this.cmd+"right")}

else {this.Error("Missing close brace")}

}

if (this.mlist.data.overI != null) {this.mlist.Over()}

},

/*

* Perform the processing of Appendix G

*/

Atomize: function () {

var data = this.mlist.init;

if (!this.error) this.mlist.Atomize(data.style,data.size)

},

/*

* Produce the final HTML.

*

* We have to wrap the HTML it appropriate tags to hide its

* actual dimensions when these don't match the TeX dimensions of the

* results. We also include an image to force the results to take up

* the right amount of space. The results may need to be vertically

* adjusted to make the baseline appear in the correct place.

*/

Typeset: function () {

var data = this.mlist.init;

var box = this.typeset = this.mlist.Typeset(data.style,data.size);

if (this.error) {return ''+this.error+''}

if (box.format == 'null') {return ''};

box.Styled().Remeasured(); var isSmall = 0; var isBig = 0;

if (box.bh > box.h && box.bh > jsMath.h+.001) {isSmall = 1}

if (box.bd > box.d && box.bd > jsMath.d+.001) {isSmall = 1}

if (box.h > jsMath.h || box.d > jsMath.d) {isBig = 1}

var html = box.html;

if (isSmall) {// hide the extra size

if (jsMath.Browser.allowAbsolute) {

var y = (box.bh > jsMath.h+.001 ? jsMath.h - box.bh : 0);

html = jsMath.HTML.Absolute(html,box.w,jsMath.h,0,y);

} else if (jsMath.Browser.valignBug) {

// remove line height

html = ''

+ html + '';

} else if (!jsMath.Browser.operaLineHeightBug) {

// remove line height and try to hide the depth

var dy = jsMath.HTML.Em(Math.max(0,box.bd-jsMath.hd)/3);

html = '' + html + '';

}

isBig = 1;

}

if (isBig) {

// add height and depth to the line

// (force a little extra to separate lines if needed)

html += jsMath.HTML.Blank(0,box.h+.05,box.d+.05);

}

return ''+html+'';

}

});

/*

* Make these characters special (and call the given routines)

*/

jsMath.Parser.prototype.AddSpecial({

cmd: 'HandleCS',

open: 'HandleOpen',

close: 'HandleClose'

});

/*

* The web-page author can call jsMath.Macro to create additional

* TeX macros for use within his or her mathematics. See the

* author's documentation for more details.

*/

jsMath.Add(jsMath,{

Macro: function (name) {

var macro = jsMath.Parser.prototype.macros;

macro[name] = ['Macro'];

for (var i = 1; i < arguments.length; i++)

{macro[name][macro[name].length] = arguments[i]}

}

});

/*

* Use these commands to create macros that load

* JavaScript files and reprocess the mathematics when

* the file is loaded. This lets you to have macros or

* LaTeX environments that autoload their own definitions

* only when they are needed, saving initial download time

* on pages where they are not used. See the author's

* documentation for more details.

*

*/

jsMath.Extension = {

safeRequire: 1, // disables access to files outside of jsMath/extensions

Macro: function (name,file) {

var macro = jsMath.Parser.prototype.macros;

if (file == null) {file = name}

macro[name] = ['Extension',file];

},

LaTeX: function (env,file) {

var latex = jsMath.Parser.prototype.environments;

latex[env] = ['Extension',file,'environments'];

},

Font: function (name,font) {

if (font == null) {font = name + "10"}

var macro = jsMath.Parser.prototype.macros;

macro[name] = ['Extension',jsMath.Font.URL(font)];

},

MathChar: function (font,defs) {

var fam = jsMath.TeX.famName[font];

if (fam == null) {

fam = jsMath.TeX.fam.length;

jsMath.TeX.fam[fam] = font;

jsMath.TeX.famName[font] = fam;

}

var mathchardef = jsMath.Parser.prototype.mathchardef;

for (var c in defs) {mathchardef[c] = [defs[c][0],fam,defs[c][1]]}

},

Require: function (file,show) {

if (this.safeRequire && (file.match(/\.\.\/|[^-a-z0-9.\/:_+=%~]/i) ||

(file.match(/:/) && file.substr(0,jsMath.root.length) != jsMath.root))) {

jsMath.Setup.loaded[file] = 1;

return;

}

jsMath.Setup.Script(this.URL(file),show);

},

URL: function (file) {

file = file.replace(/^\s+|\s+$/g,'');

if (!file.match(/^([a-z]+:|\/|fonts|extensions\/)/i)) {file = 'extensions/'+file}

if (!file.match(/\.js$/)) {file += '.js'}

return file;

}

}

/***************************************************************************/

/*

* These routines look through the web page for math elements to process.

* There are two main entry points you can call:

*

*

* or

*

*

* The first will process the page asynchronously (so the user can start

* reading the top of the file while jsMath is still processing the bottom)

* while the second does not update until all the mathematics is typeset.

*/

jsMath.Add(jsMath,{

/*

* Call this at the bottom of your HTML page to have the

* mathematics typeset asynchronously. This lets the user

* start reading the mathematics while the rest of the page

* is being processed.

*/

Process: function (obj) {

jsMath.Setup.Body();

jsMath.Script.Push(jsMath.Translate,'Asynchronous',obj);

},

/*

* Call this at the bottom of your HTML page to have the

* mathematics typeset before the page is displayed.

* This can take a long time, so the user could cancel the

* page before it is complete; use it with caution, and only

* when there is a relatively small amount of math on the page.

*/

ProcessBeforeShowing: function (obj) {

jsMath.Setup.Body();

var method = (jsMath.Controls.cookie.asynch ? "Asynchronous": "Synchronous");

jsMath.Script.Push(jsMath.Translate,method,obj);

},

/*

* Process the contents of a single element. It must be of

* class "math".

*/

ProcessElement: function (obj) {

jsMath.Setup.Body();

jsMath.Script.Push(jsMath.Translate,'ProcessOne',obj);

}

});

jsMath.Translate = {

element: [], // the list of math elements on the page

cancel: 0, // set to 1 to cancel asynchronous processing

/*

* Parse a TeX string in Text or Display mode and return

* the HTML for it (taking it from the cache, if available)

*/

Parse: function (style,s,noCache) {

var cache = jsMath.Global.cache[style];

if (!cache[jsMath.em]) {cache[jsMath.em] = {}}

var HTML = cache[jsMath.em][s];

if (!HTML || noCache) {

var parse = jsMath.Parse(s,null,null,style);

parse.Atomize(); HTML = parse.Typeset();

if (!noCache) {cache[jsMath.em][s] = HTML}

}

return HTML;

},

TextMode: function (s,noCache) {this.Parse('T',s,noCache)},

DisplayMode: function (s,noCache) {this.Parse('D',s,noCache)},

/*

* Return the text of a given DOM element

*/

GetElementText: function (element) {

if (element.childNodes.length == 1 && element.childNodes[0].nodeName === "#comment") {

var result = element.childNodes[0].nodeValue.match(/^\[CDATA\[(.*)\]\]$/);

if (result != null) {return result[1]};

}

var text = this.recursiveElementText(element);

element.alt = text;

if (text.search('&') >= 0) {

text = text.replace(/</g,'<');

text = text.replace(/>/g,'>');

text = text.replace(/"/g,'"');

text = text.replace(/&/g,'&');

}

return text;

},

recursiveElementText: function (element) {

if (element.nodeValue != null) {

if (element.nodeName !== "#comment") {return element.nodeValue}

return element.nodeValue.replace(/^\[CDATA\[((.|\n)*)\]\]$/,"$1");

}

if (element.childNodes.length === 0) {return " "}

var text = '';

for (var i = 0; i < element.childNodes.length; i++)

{text += this.recursiveElementText(element.childNodes[i])}

return text;

},

/*

* Move hidden to the location of the math element to be

* processed and reinitialize sizes for that location.

*/

ResetHidden: function (element) {

element.innerHTML =

''

+ jsMath.Browser.operaHiddenFix; // needed by Opera in tables

element.className = '';

jsMath.hidden = element.firstChild;

if (!jsMath.BBoxFor("x").w) {jsMath.hidden = jsMath.hiddenTop}

jsMath.ReInit();

},

/*

* Typeset the contents of an element in \textstyle or \displaystyle

*/

ConvertMath: function (style,element,noCache) {

var text = this.GetElementText(element);

this.ResetHidden(element);

if (text.match(/^\s*\\nocache([^a-zA-Z])/))

{noCache = true; text = text.replace(/\s*\\nocache/,'')}

text = this.Parse(style,text,noCache);

element.className = 'typeset';

element.innerHTML = text;

},

/*

* Process a math element

*/

ProcessElement: function (element) {

this.restart = 0;

if (!element.className.match(/(^| )math( |$)/)) return; // don't reprocess elements

var noCache = (element.className.toLowerCase().match(/(^| )nocache( |$)/) != null);

try {

var style = (element.tagName.toLowerCase() == 'div' ? 'D' : 'T');

this.ConvertMath(style,element,noCache);

element.onclick = jsMath.Click.CheckClick;

element.ondblclick = jsMath.Click.CheckDblClick;

} catch (err) {

if (element.alt) {

var tex = element.alt;

tex = tex.replace(/&/g,'&')

.replace(/

.replace(/>/g,'>');

element.innerHTML = tex;

element.className = 'math';

if (noCache) {element.className += ' nocache'}

}

jsMath.hidden = jsMath.hiddenTop;

}

},

/*

* Asynchronously process all the math elements starting with

* the k-th one. Do them in blocks of 8 (more efficient than one

* at a time, but still allows screen updates periodically).

*/

ProcessElements: function (k) {

jsMath.Script.blocking = 1;

for (var i = 0; i < jsMath.Browser.processAtOnce; i++, k++) {

if (k >= this.element.length || this.cancel) {

this.ProcessComplete();

if (this.cancel) {

jsMath.Message.Set("Process Math: Canceled");

jsMath.Message.Clear()

}

jsMath.Script.blocking = 0;

jsMath.Script.Process();

return;

} else {

var savedQueue = jsMath.Script.SaveQueue();

this.ProcessElement(this.element[k]);

if (this.restart) {

jsMath.Script.Push(this,'ProcessElements',k);

jsMath.Script.RestoreQueue(savedQueue);

jsMath.Script.blocking = 0;

setTimeout('jsMath.Script.Process()',jsMath.Browser.delay);

return;

}

}

}

jsMath.Script.RestoreQueue(savedQueue);

var p = Math.floor(100 * k / this.element.length);

jsMath.Message.Set('Processing Math: '+p+'%');

setTimeout('jsMath.Translate.ProcessElements('+k+')',jsMath.Browser.delay);

},

/*

* Start the asynchronous processing of mathematics

*/

Asynchronous: function (obj) {

if (!jsMath.initialized) {jsMath.Init()}

this.element = this.GetMathElements(obj);

jsMath.Script.blocking = 1;

this.cancel = 0; this.asynchronous = 1;

jsMath.Message.Set('Processing Math: 0%',1);

setTimeout('jsMath.Translate.ProcessElements(0)',jsMath.Browser.delay);

},

/*

* Do synchronous processing of mathematics

*/

Synchronous: function (obj,i) {

if (i == null) {

if (!jsMath.initialized) {jsMath.Init()}

this.element = this.GetMathElements(obj);

i = 0;

}

this.asynchronous = 0;

while (i < this.element.length) {

this.ProcessElement(this.element[i]);

if (this.restart) {

jsMath.Synchronize('jsMath.Translate.Synchronous(null,'+i+')');

jsMath.Script.Process();

return;

}

i++;

}

this.ProcessComplete(1);

},

/*

* Synchronously process the contents of a single element

*/

ProcessOne: function (obj) {

if (!jsMath.initialized) {jsMath.Init()}

this.element = [obj];

this.Synchronous(null,0);

},

/*

* Look up all the math elements on the page and

* put them in a list sorted from top to bottom of the page

*/

GetMathElements: function (obj) {

var element = []; var k;

if (!obj) {obj = jsMath.document}

if (typeof(obj) == 'string') {obj = jsMath.document.getElementById(obj)}

if (!obj.getElementsByTagName) return null;

var math = obj.getElementsByTagName('div');

for (k = 0; k < math.length; k++) {

if (math[k].className && math[k].className.match(/(^| )math( |$)/)) {

if (jsMath.Browser.renameOK && obj.getElementsByName)

{math[k].setAttribute('name','_jsMath_')}

else {element[element.length] = math[k]}

}

}

math = obj.getElementsByTagName('span');

for (k = 0; k < math.length; k++) {

if (math[k].className && math[k].className.match(/(^| )math( |$)/)) {

if (jsMath.Browser.renameOK && obj.getElementsByName)

{math[k].setAttribute('name','_jsMath_')}

else {element[element.length] = math[k]}

}

}

// this gets the SPAN and DIV elements interleaved in order

if (jsMath.Browser.renameOK && obj.getElementsByName) {

element = obj.getElementsByName('_jsMath_');

} else if (jsMath.hidden.sourceIndex) {

element.sort(function (a,b) {return a.sourceIndex - b.sourceIndex});

}

return element;

},

/*

* Remove the window message about processing math

* and clean up any marked or

tags

*/

ProcessComplete: function (noMessage) {

if (jsMath.Browser.renameOK) {

var element = jsMath.document.getElementsByName('_jsMath_');

for (var i = element.length-1; i >= 0; i--) {

element[i].removeAttribute('name');

}

}

jsMath.hidden = jsMath.hiddenTop;

this.element = []; this.restart = null;

if (!noMessage) {

jsMath.Message.Set('Processing Math: Done');

jsMath.Message.Clear();

}

jsMath.Message.UnBlank();

if (jsMath.Browser.safariImgBug &&

(jsMath.Controls.cookie.font == 'symbol' ||

jsMath.Controls.cookie.font == 'image')) {

//

// For Safari, the images don't always finish

// updating, so nudge the window to cause a

// redraw. (Hack!)

//

if (this.timeout) {clearTimeout(this.timeout)}

this.timeout = setTimeout("jsMath.window.resizeBy(-1,0); "

+ "jsMath.window.resizeBy(1,0); "

+ "jsMath.Translate.timeout = null",2000);

}

},

/*

* Cancel procesing elements

*/

Cancel: function () {

jsMath.Translate.cancel = 1;

if (jsMath.Script.cancelTimer) {jsMath.Script.cancelLoad()}

}

};

jsMath.Add(jsMath,{

//

// Synchronize these with the loading of the tex2math plugin.

//

ConvertTeX: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertTeX',element)},

ConvertTeX2: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertTeX2',element)},

ConvertLaTeX: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertLaTeX',element)},

ConvertCustom: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertCustom',element)},

CustomSearch: function (om,cm,od,cd) {jsMath.Script.Push(null,function () {jsMath.tex2math.CustomSearch(om,cm,od,cd)})},

tex2math: {

ConvertTeX: function () {},

ConvertTeX2: function () {},

ConvertLaTeX: function () {},

ConvertCustom: function () {},

CustomSearch: function () {}

}

});

jsMath.Synchronize = jsMath.Script.Synchronize;

/***************************************************************************/

/*

* Initialize things

*/

try {

if (window.parent != window && window.jsMathAutoload) {

window.parent.jsMath = jsMath;

jsMath.document = window.parent.document;

jsMath.window = window.parent;

}

} catch (err) {}

jsMath.Global.Register();

jsMath.Loaded();

jsMath.Controls.GetCookie();

jsMath.Setup.Source();

jsMath.Global.Init();

jsMath.Script.Init();

jsMath.Setup.Fonts();

if (jsMath.document.body) {jsMath.Setup.Body()}

jsMath.Setup.User("onload");

}}