1 /*****************************************************************************
3 * jsMath: Mathematics on the Web
5 * This jsMath package makes it possible to display mathematics in HTML pages
6 * that are viewable by a wide range of browsers on both the Mac and the IBM PC,
7 * including browsers that don't process MathML. See
9 * http://www.math.union.edu/locate/jsMath
11 * for the latest version, and for documentation on how to use jsMath.
13 * Copyright 2004-2010 by Davide P. Cervone
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
19 * http://www.apache.org/licenses/LICENSE-2.0
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
27 *****************************************************************************/
30 * Prevent running everything again if this file is loaded twice
32 if (!window.jsMath || !window.jsMath.loaded) {
34 var jsMath_old = window.jsMath; // save user customizations
40 * function ShowObject (obj,spaces) {
41 * var s = ''; if (!spaces) {spaces = ""}
42 * for (var i in obj) {
43 * if (obj[i] != null) {
44 * if (typeof(obj[i]) == "object") {
45 * s += spaces + i + ": {\n"
46 * + ShowObject(obj[i],spaces + ' ')
48 * } else if (typeof(obj[i]) != "function") {
49 * s += spaces + i + ': ' + obj[i] + "\n";
57 /***************************************************************************/
59 // Check for DOM support
61 if (!document.getElementById || !document.childNodes || !document.createElement) {
62 alert('The mathematics on this page requires W3C DOM support in its JavaScript. '
63 + 'Unfortunately, your browser doesn\'t seem to have this.');
66 /***************************************************************************/
70 version: "3.6e", // change this if you edit the file, but don't edit this file
72 document: document, // the document loading jsMath
73 window: window, // the window of the of loading document
75 platform: (navigator.platform.match(/Mac/) ? "mac" :
76 navigator.platform.match(/Win/) ? "pc" : "unix"),
78 // Font sizes for \tiny, \small, etc. (must match styles below)
79 sizes: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249],
82 // The styles needed for the TeX fonts and other jsMath elements
85 '.math': { // unprocessed mathematics
86 'font-family': 'serif',
87 'font-style': 'normal',
88 'font-weight': 'normal'
91 '.typeset': { // final typeset mathematics
92 'font-family': 'serif',
93 'font-style': 'normal',
94 'font-weight': 'normal',
95 'line-height': 'normal',
97 'white-space': 'normal'
100 '.typeset .normal': { // \hbox contents style
101 'font-family': 'serif',
102 'font-style': 'normal',
103 'font-weight': 'normal'
106 'div.typeset': { // display mathematics
107 'text-align': 'center',
111 'span.typeset': { // in-line mathematics
115 '.typeset span': { // prevent outside CSS from setting these
116 'text-align': 'left',
122 'a .typeset img, .typeset a img': { // links in image mode
124 'border-bottom': '1px solid blue;'
128 '.typeset .size0': {'font-size': '50%'}, // tiny (\scriptscriptsize)
129 '.typeset .size1': {'font-size': '60%'}, // (50% of \large for consistency)
130 '.typeset .size2': {'font-size': '70%'}, // scriptsize
131 '.typeset .size3': {'font-size': '85%'}, // small (70% of \large for consistency)
132 '.typeset .size4': {'font-size': '100%'}, // normalsize
133 '.typeset .size5': {'font-size': '120%'}, // large
134 '.typeset .size6': {'font-size': '144%'}, // Large
135 '.typeset .size7': {'font-size': '173%'}, // LARGE
136 '.typeset .size8': {'font-size': '207%'}, // huge
137 '.typeset .size9': {'font-size': '249%'}, // Huge
140 '.typeset .cmr10': {'font-family': 'jsMath-cmr10, serif'},
141 '.typeset .cmbx10': {'font-family': 'jsMath-cmbx10, jsMath-cmr10'},
142 '.typeset .cmti10': {'font-family': 'jsMath-cmti10, jsMath-cmr10'},
143 '.typeset .cmmi10': {'font-family': 'jsMath-cmmi10'},
144 '.typeset .cmsy10': {'font-family': 'jsMath-cmsy10'},
145 '.typeset .cmex10': {'font-family': 'jsMath-cmex10'},
147 '.typeset .textit': {'font-family': 'serif', 'font-style': 'italic'},
148 '.typeset .textbf': {'font-family': 'serif', 'font-weight': 'bold'},
150 '.typeset .link': {'text-decoration': 'none'}, // links in mathematics
152 '.typeset .error': { // in-line error messages
154 'font-style': 'italic',
155 'background-color': '#FFFFCC',
157 border: '1px solid #CC0000'
160 '.typeset .blank': { // internal use
161 display: 'inline-block',
167 '.typeset .spacer': { // internal use
168 display: 'inline-block'
171 '#jsMath_hiddenSpan': { // used for measuring BBoxes
172 visibility: 'hidden',
173 position: 'absolute',
176 'line-height': 'normal',
180 '#jsMath_message': { // percentage complete message
184 'background-color': '#E6E6E6',
185 border: 'solid 1px #959595',
190 'font-size': 'small',
194 '#jsMath_panel': { // control panel
198 padding: '.8em 1.6em',
199 'background-color': '#DDDDDD',
200 border: 'outset 2px',
205 'font-style': 'normal'
207 '#jsMath_panel .disabled': {color: '#888888'}, // disabled items in the panel
208 '#jsMath_panel .infoLink': {'font-size': '85%'}, // links to web pages
210 // avoid CSS polution from outside the panel
212 'font-size': 'inherit',
213 'font-style': 'inherit',
214 'font-family': 'inherit',
215 'line-height': 'normal'
217 '#jsMath_panel div': {'background-color': 'inherit', color: 'inherit'},
218 '#jsMath_panel span': {'background-color': 'inherit', color: 'inherit'},
219 '#jsMath_panel td': {
220 border: '0px', padding: '0px', margin: '0px',
221 'background-color': 'inherit', color: 'inherit'
223 '#jsMath_panel tr': {
224 border: '0px', padding: '0px', margin: '0px',
225 'background-color': 'inherit', color: 'inherit'
227 '#jsMath_panel table': {
228 border: '0px', padding: '0px', margin: '0px',
229 'background-color': 'inherit', color: 'inherit',
230 height: 'auto', width: 'auto'
233 '#jsMath_button': { // the jsMath floating button (to open control panel)
237 'background-color': 'white',
238 border: 'solid 1px #959595',
240 padding: '0px 3px 1px 3px',
243 'text-decoration': 'none',
244 'font-size': 'x-small',
248 '#jsMath_button *': {
249 padding: '0px', border: '0px', margin: '0px', 'line-height': 'normal',
250 'font-size': 'inherit', 'font-style': 'inherit', 'font-family': 'inherit'
253 '#jsMath_global': {'font-style': 'italic'}, // 'global' in jsMath button
255 '#jsMath_noFont .message': { // missing font message window
256 'text-align': 'center',
257 padding: '.8em 1.6em',
258 border: '3px solid #DD0000',
259 'background-color': '#FFF8F8',
261 'font-size': 'small',
264 '#jsMath_noFont .link': {
265 padding: '0px 5px 2px 5px',
266 border: '2px outset',
267 'background-color': '#E8E8E8',
274 '#jsMath_PrintWarning .message': { // warning on print pages
275 'text-align': 'center',
276 padding: '.8em 1.6em',
277 border: '3px solid #DD0000',
278 'background-color': '#FFF8F8',
280 'font-size': 'x-small',
285 '#jsMath_button': {display: 'none'},
286 '#jsMath_Warning': {display: 'none'}
290 '#jsMath_PrintWarning': {display:'none'}
296 /***************************************************************************/
299 * Get a jsMath DOM element
301 Element: function (name) {return jsMath.document.getElementById('jsMath_'+name)},
304 * Get the width and height (in pixels) of an HTML string
306 BBoxFor: function (s) {
307 this.hidden.innerHTML =
308 '<nobr><span class="typeset"><span class="scale">'+s+'</span></span></nobr>';
309 var math = (jsMath.Browser.msieBBoxBug ? this.hidden.firstChild.firstChild : this.hidden);
310 var bbox = {w: math.offsetWidth, h: this.hidden.offsetHeight};
311 this.hidden.innerHTML = '';
316 * Get the width and height (in ems) of an HTML string.
317 * Check the cache first to see if we've already measured it.
319 EmBoxFor: function (s) {
320 var cache = jsMath.Global.cache.R;
321 if (!cache[this.em]) {cache[this.em] = {}}
322 if (!cache[this.em][s]) {
323 var bbox = this.BBoxFor(s);
324 cache[this.em][s] = {w: bbox.w/this.em, h: bbox.h/this.em};
326 return cache[this.em][s];
330 * Initialize jsMath. This determines the em size, and a variety
331 * of other parameters used throughout jsMath.
334 if (jsMath.Setup.inited != 1) {
335 if (!jsMath.Setup.inited) {jsMath.Setup.Body()}
336 if (jsMath.Setup.inited != 1) {
337 if (jsMath.Setup.inited == -100) return;
338 alert("It looks like jsMath failed to set up properly (error code "
339 + jsMath.Setup.inited + "). "
340 + "I will try to keep going, but it could get ugly.");
341 jsMath.Setup.inited = 1;
344 this.em = this.CurrentEm();
345 var cache = jsMath.Global.cache.B;
346 if (!cache[this.em]) {
348 cache[this.em].bb = this.BBoxFor('x'); var hh = cache[this.em].bb.h;
349 cache[this.em].d = this.BBoxFor('x'+jsMath.HTML.Strut(hh/this.em)).h - hh;
351 jsMath.Browser.italicCorrection = cache[this.em].ic;
352 var bb = cache[this.em].bb; var h = bb.h; var d = cache[this.em].d
353 this.h = (h-d)/this.em; this.d = d/this.em;
354 this.hd = this.h + this.d;
356 this.Setup.TeXfonts();
358 var x_height = this.EmBoxFor('<span class="cmr10">M</span>').w/2;
359 this.TeX.M_height = x_height*(26/14);
360 this.TeX.h = this.h; this.TeX.d = this.d; this.TeX.hd = this.hd;
363 if (!this.initialized) {
365 this.Img.UpdateFonts();
368 // factor for \big and its brethren
369 this.p_height = (this.TeX.cmex10[0].h + this.TeX.cmex10[0].d) / .85;
371 this.initialized = 1;
375 * Get the x size and if it has changed, reinitialize the sizes
377 ReInit: function () {
378 if (this.em != this.CurrentEm()) {this.Init()}
382 * Find the em size in effect at the current text location
384 CurrentEm: function () {
385 var em = this.BBoxFor('<span style="'+jsMath.Browser.block+';width:27em;height:1em"></span>').w/27;
386 if (em > 0) {return em}
387 // handle older browsers
388 return this.BBoxFor('<img src="'+jsMath.blank+'" style="width:13em;height:1em" />').w/13;
392 * Mark jsMath as loaded and copy any user-provided overrides
394 Loaded: function () {
396 var override = ['Process', 'ProcessBeforeShowing','ProcessElement',
397 'ConvertTeX','ConvertTeX2','ConvertLaTeX','ConvertCustom',
398 'CustomSearch', 'Synchronize', 'Macro', 'document'];
399 for (var i = 0; i < override.length; i++) {
400 if (jsMath_old[override[i]]) {delete jsMath_old[override[i]]}
403 if (jsMath_old) {this.Insert(jsMath,jsMath_old)}
409 * Manage JavaScript objects:
411 * Add: add/replace items in an object
412 * Insert: add items to an object
413 * Package: add items to an object prototype
415 Add: function (dst,src) {for (var id in src) {dst[id] = src[id]}},
416 Insert: function (dst,src) {
417 for (var id in src) {
418 if (dst[id] && typeof(src[id]) == 'object'
419 && (typeof(dst[id]) == 'object'
420 || typeof(dst[id]) == 'function')) {
421 this.Insert(dst[id],src[id]);
427 Package: function (obj,def) {this.Insert(obj.prototype,def)}
432 /***************************************************************************/
435 * Implements items associated with the global cache.
437 * This object will be replaced by a global version when
438 * (and if) jsMath-global.html is loaded.
441 isLocal: 1, // a local copy if jsMath-global.html hasn't been loaded
442 cache: {T: {}, D: {}, R: {}, B: {}},
445 * Clear the global (or local) cache
447 ClearCache: function () {jsMath.Global.cache = {T: {}, D: {}, R: {}, B: {}}},
450 * Initiate global mode
452 GoGlobal: function (cookie) {
453 var url = String(jsMath.window.location);
454 var c = (jsMath.isCHMmode ? '#' : '?');
455 if (cookie) {url = url.replace(/\?.*/,'') + '?' + cookie}
456 jsMath.Controls.Reload(jsMath.root + "jsMath-global.html" + c +escape(url));
460 * Check if we need to go to global mode
463 if (jsMath.Controls.cookie.global == "always" && !jsMath.noGoGlobal) {
464 if (navigator.accentColorName) return; // OmniWeb crashes on GoGlobal
465 if (!jsMath.window) {jsMath.window = window}
466 jsMath.Controls.loaded = 1;
467 jsMath.Controls.defaults.hiddenGlobal = null;
468 this.GoGlobal(jsMath.Controls.SetCookie(2));
473 * Try to register with a global.html window that contains us
475 Register: function () {
476 var parent = jsMath.window.parent;
477 if (!jsMath.isCHMmode)
478 {jsMath.isCHMmode = (jsMath.window.location.protocol == 'mk:')}
480 if (!jsMath.isCHMmode) this.Domain();
481 if (parent.jsMath && parent.jsMath.isGlobal)
482 {parent.jsMath.Register(jsMath.window)}
483 } catch (err) {jsMath.noGoGlobal = 1}
487 * If we're not the parent window, try to set the domain to
488 * match the parent's domain (so we can use the Global data
489 * if the surrounding frame is a Global frame).
491 Domain: function () {
492 // MSIE/Mac can't do domain changes, so don't bother trying
493 if (navigator.appName == 'Microsoft Internet Explorer' &&
494 jsMath.platform == 'mac' && navigator.userProfile != null) return;
495 // MSIE/PC can do domain change, but gets mixed up if we don't
496 // find a domain that works, and then can't look in window.location
497 // any longer. So don't try, since we can't afford to leave it confused.
498 if (jsMath.document.all && !jsMath.window.opera) return;
500 if (window == parent) return;
501 var oldDomain = jsMath.document.domain;
504 try {if (parent.document.title != null) return} catch (err) {}
505 if (!document.domain.match(/\..*\./)) break;
506 jsMath.document.domain = jsMath.document.domain.replace(/^[^.]*\./,'');
509 jsMath.document.domain = oldDomain;
516 /***************************************************************************/
520 * Implement loading of remote scripts using XMLHttpRequest, if
521 * possible, otherwise use a hidden IFRAME and fake it. That
522 * method runs asynchronously, which causes lots of headaches.
523 * Solve these using Push command, which queues actions
524 * until files have loaded.
529 request: null, // the XMLHttpRequest object
532 * Create the XMLHttpRequest object, if we can.
533 * Otherwise, use the iframe-based fallback method.
536 if (!(jsMath.Controls.cookie.asynch && jsMath.Controls.cookie.progress)) {
537 if (window.XMLHttpRequest) {
538 try {this.request = new XMLHttpRequest} catch (err) {}
539 // MSIE and FireFox3 can't use xmlRequest on local files,
540 // but we don't have jsMath.browser yet to tell, so use this check
541 if (this.request && jsMath.root.match(/^file:\/\//)) {
543 this.request.open("GET",jsMath.root+"jsMath.js",false);
544 this.request.send(null);
547 // Firefox3 has window.postMessage for inter-window communication.
548 // It can be used to handle the new file:// security model,
549 // so set up the listener.
550 if (window.postMessage && window.addEventListener) {
552 jsMath.window.addEventListener("message",jsMath.Post.Listener,false);
557 if (!this.request && window.ActiveXObject && !this.mustPost) {
558 var xml = ["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0",
559 "MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
560 for (var i = 0; i < xml.length && !this.request; i++) {
561 try {this.request = new ActiveXObject(xml[i])} catch (err) {}
566 // Use the delayed-script fallback for MSIE/Mac and old versions
567 // of several browsers (Opera 7.5, OmniWeb 4.5).
569 if (!this.request || jsMath.Setup.domainChanged)
570 {this.Load = this.delayedLoad; this.needsBody = 1}
574 * Load a script and evaluate it in the window's context
576 Load: function (url,show) {
578 jsMath.Message.Set("Loading "+url);
579 jsMath.Script.Delay(1);
580 jsMath.Script.Push(this,'xmlRequest',url);
581 jsMath.Script.Push(jsMath.Message,'Clear');
583 jsMath.Script.Push(this,'xmlRequest',url);
588 * Load a URL and run the contents of the file
590 xmlRequest: function (url) {
592 // this.debug('xmlRequest: '+url);
594 this.request.open("GET",url,false);
595 this.request.send(null);
598 if (jsMath.Translate.restart && jsMath.Translate.asynchronous) {return ""}
599 throw Error("jsMath can't load the file '"+url+"'\n"
600 + "Message: "+err.message);
602 if (this.request.status != null && (this.request.status >= 400 || this.request.status < 0)) {
603 // Do we need to deal with redirected links?
605 if (jsMath.Translate.restart && jsMath.Translate.asynchronous) {return ""}
606 throw Error("jsMath can't load the file '"+url+"'\n"
607 + "Error status: "+this.request.status);
609 if (!url.match(/\.js$/)) {return(this.request.responseText)}
610 var tmpQueue = this.queue; this.queue = [];
611 // this.debug('xml Eval ['+tmpQueue.length+']');
612 jsMath.window.eval(this.request.responseText);
613 // this.debug('xml Done ['+this.queue.length+' + '+tmpQueue.length+']');
614 this.blocking = 0; this.queue = this.queue.concat(tmpQueue);
619 /********************************************************************
621 * Implement asynchronous loading and execution of scripts
622 * (via hidden IFRAME) interleved with other JavaScript commands
623 * that must be synchronized with the file loading. (Basically, this
624 * is for MSIE/Mac and Opera 7.5, which don't have XMLHttpRequest.)
627 cancelTimeout: 30*1000, // delay for canceling load (30 sec)
629 blocking: 0, // true when an asynchronous action is being performed
630 cancelTimer: null, // timer to cancel load if it takes too long
631 needsBody: 0, // true if loading files requires BODY to be present
633 queue: [], // the stack of pending actions
636 * Provide mechanism for synchronizing with the asynchronous jsMath
637 * file-loading mechanism. 'code' can be a string or a function.
639 Synchronize: function (code,data) {
640 if (typeof(code) != 'string') {jsMath.Script.Push(null,code,data)}
641 else {jsMath.Script.Push(jsMath.window,'eval',code)}
645 * Queue a function to be processed.
646 * If nothing is being loaded, do the pending commands.
648 Push: function (object,method,data) {
649 // this.debug('Pushing: '+method+' at '+this.queue.length); // debug
650 this.queue[this.queue.length] = [object,method,data];
651 if (!(this.blocking || (this.needsBody && !jsMath.document.body))) this.Process();
655 * Do any pending functions (stopping if a file load is started)
657 Process: function () {
658 while (this.queue.length && !this.blocking) {
659 var call = this.queue[0]; this.queue = this.queue.slice(1);
660 var savedQueue = this.SaveQueue();
661 var object = call[0]; var method = call[1]; var data = call[2];
662 // this.debug('Calling: '+method+' ['+savedQueue.length+']'); // debug
663 if (object) {object[method](data)} else if (method) {method(data)}
664 // this.debug('Done: '+method+' ['+this.queue.length+' + '+savedQueue.length+'] ('+this.blocking+')'); // debug
665 this.RestoreQueue(savedQueue);
670 * Allows pushes to occur at the FRONT of the queue
671 * (so a command acts as a single unit, including anything
672 * that it pushes on to the command stack)
674 SaveQueue: function () {
675 var queue = this.queue;
679 RestoreQueue: function (queue) {
680 this.queue = this.queue.concat(queue);
684 * Handle loading of scripts that run asynchronously
686 delayedLoad: function (url) {
687 // this.debug('Loading: '+url);
688 this.Push(this,'startLoad',url);
690 startLoad: function (url) {
691 var iframe = jsMath.document.createElement('iframe');
692 iframe.style.visibility = 'hidden';
693 iframe.style.position = 'absolute';
694 iframe.style.width = '0px';
695 iframe.style.height = '0px';
696 if (jsMath.document.body.firstChild) {
697 jsMath.document.body.insertBefore(iframe,jsMath.document.body.firstChild);
699 jsMath.document.body.appendChild(iframe);
701 this.blocking = 1; this.url = url;
702 if (url.substr(0,jsMath.root.length) == jsMath.root)
703 {url = url.substr(jsMath.root.length)}
704 jsMath.Message.Set("Loading "+url);
705 this.cancelTimer = setTimeout('jsMath.Script.cancelLoad()',this.cancelTimeout);
706 if (this.mustPost) {iframe.src = jsMath.Post.startLoad(url,iframe)}
707 else if (url.match(/\.js$/)) {iframe.src = jsMath.root+"jsMath-loader.html"}
708 else {iframe.src = this.url}
710 endLoad: function (action) {
711 if (this.cancelTimer) {clearTimeout(this.cancelTimer); this.cancelTimer = null}
712 jsMath.Post.endLoad();
713 jsMath.Message.Clear();
714 if (action != 'cancel') {this.blocking = 0; this.Process()}
718 // this.debug('Starting: ['+this.queue.length+'] '+this.url);
719 this.tmpQueue = this.queue; this.queue = [];
722 // this.debug('Ending: ['+this.queue.length+' + '+this.tmpQueue.length+'] '+this.url);
723 this.queue = this.queue.concat(this.tmpQueue); delete this.tmpQueue;
727 * If the loading takes too long, cancel it and end the load.
729 cancelLoad: function (message,delay) {
730 if (this.cancelTimer) {clearTimeout(this.cancelTimer); this.cancelTimer = null}
731 if (message == null) {message = "Can't load file"}
732 if (delay == null) {delay = 2000}
733 jsMath.Message.Set(message);
734 setTimeout('jsMath.Script.endLoad("cancel")',delay);
738 * Perform a delay (to let the browser catch up)
740 Delay: function (time) {
742 setTimeout('jsMath.Script.endDelay()',time);
744 endDelay: function () {
745 // this.debug('endDelay');
751 * Load an image and wait for it
752 * (so MSIE won't load extra copies of it)
755 WaitForImage: function (file) {
756 this.blocking = 1; this.imageCount++;
757 if (this.img == null) {this.img = []}
758 var img = new Image(); this.img[this.img.length] = img;
759 img.onload = function () {if (--jsMath.Script.imageCount == 0) jsMath.Script.endDelay()}
760 img.onerror = img.onload; img.onabort = img.onload;
765 * The code uncompressor
767 Uncompress: function (data) {
768 for (var k = 0; k < data.length; k++) {
769 var d = data[k]; var n = d.length;
770 for (var i = 0; i < n; i++) {if (typeof(d[i]) == 'number') {d[i] = d[d[i]]}}
771 data[k] = d.join('');
773 window.eval(data.join(''));
777 * for debugging the event queue
780 * ,debug: function (message) {
781 * if (jsMath.document.body && jsMath.window.debug) {jsMath.window.debug(message)}
782 * else {alert(message)}
788 /***************************************************************************/
791 * Handle window.postMessage() events in Firefox3
795 window: null, // iframe we are listening to
797 Listener: function (event) {
798 if (event.source != jsMath.Post.window) return;
799 var domain = event.origin.replace(/^file:\/\//,'');
800 var ddomain = document.domain.replace(/^file:\/\//,'');
801 if (domain == null || domain == "" || domain == "null") {domain = "localhost"}
802 if (ddomain == null || ddomain == "" || ddomain == "null") {ddomain = "localhost"}
803 if (domain != ddomain || !event.data.substr(0,6).match(/jsM(CP|LD|AL):/)) return;
804 var type = event.data.substr(6,3).replace(/ /g,'');
805 var message = event.data.substr(10);
806 if (jsMath.Post.Commands[type]) (jsMath.Post.Commands[type])(message);
811 * Commands that can be performed by the listener
814 SCR: function (message) {jsMath.window.eval(message)},
815 ERR: function (message) {jsMath.Script.cancelLoad(message,3000)},
816 BGN: function (message) {jsMath.Script.Start()},
817 END: function (message) {if (message) jsMath.Script.End(); jsMath.Script.endLoad()}
820 startLoad: function (url,iframe) {
821 this.window = iframe.contentWindow;
822 if (!url.match(/\.js$/)) {return jsMath.root+url}
823 return jsMath.root+"jsMath-loader-post.html?"+url;
825 endLoad: function () {this.window = null}
828 /***************************************************************************/
831 * Message and screen blanking facility
836 blank: null, // the div to blank out the screen
837 message: null, // the div for the messages
838 text: null, // the text node for messages
839 clear: null, // timer for clearing message
842 * Create the elements needed for the message box
845 if (!jsMath.document.body || !jsMath.Controls.cookie.progress) return;
846 this.message = jsMath.Element('message');
848 if (jsMath.Setup.stylesReady) {
849 this.message = jsMath.Setup.DIV('message',{visibility:'hidden'},jsMath.fixedDiv);
851 this.message = jsMath.Setup.DIV('message',{
852 visibility:'hidden', position:'absolute', bottom:'1px', left:'2px',
853 backgroundColor:'#E6E6E6', border:'solid 1px #959595',
854 margin:'0px', padding:'1px 8px', zIndex:102,
855 color:'black', fontSize:'small', width:'auto'
859 this.text = jsMath.document.createTextNode('');
860 this.message.appendChild(this.text);
861 this.message.onmousedown = jsMath.Translate.Cancel;
865 * Set the contents of the message box, or use the window status line
867 Set: function (text,canCancel) {
868 if (this.clear) {clearTimeout(this.clear); this.clear = null}
869 if (jsMath.Controls.cookie.progress) {
870 if (!this.text) {this.Init(); if (!this.text) return}
871 if (jsMath.Browser.textNodeBug) {this.message.innerHTML = text}
872 else {this.text.nodeValue = text}
873 this.message.style.visibility = 'visible';
875 this.message.style.cursor = 'pointer';
876 if (!this.message.style.cursor) {this.message.style.cursor = 'hand'}
877 this.message.title = ' Cancel Processing of Math ';
879 this.message.style.cursor = '';
880 this.message.title = '';
883 if (text.substr(0,8) != "Loading ") {jsMath.window.status = text}
888 * Clear the message box or status line
891 if (this.clear) {clearTimeout(this.clear)}
892 this.clear = setTimeout("jsMath.Message.doClear()",1000);
894 doClear: function () {
897 jsMath.window.status = '';
898 if (this.text) {this.text.nodeValue = ''}
899 if (this.message) {this.message.style.visibility = 'hidden'}
905 * Put up a DIV that covers the window so that the
906 * "flicker" of processing the mathematics will not be visible
909 if (this.blank || !jsMath.document.body) return;
910 this.blank = jsMath.Setup.DIV("blank",{
911 position:(jsMath.Browser.msiePositionFixedBug? 'absolute': 'fixed'),
912 top:'0px', left:'0px', bottom:'0px', right:'0px',
913 zIndex:101, backgroundColor:'white'
915 if (jsMath.Browser.msieBlankBug) {
916 this.blank.innerHTML = ' ';
917 this.blank.style.width = "110%";
918 this.blank.style.height = "110%";
922 UnBlank: function () {
923 if (this.blank) {jsMath.document.body.removeChild(this.blank)}
929 /***************************************************************************/
932 * Miscellaneous setup and initialization
936 loaded: [], // array of files already loaded
939 * Insert a DIV at the top of the page with given ID,
940 * attributes, and style settings
942 DIV: function (id,styles,parent) {
943 if (parent == null) {parent = jsMath.document.body}
944 var div = jsMath.document.createElement('div');
945 div.id = 'jsMath_'+id;
946 for (var i in styles) {div.style[i]= styles[i]}
947 if (!parent.hasChildNodes) {parent.appendChild(div)}
948 else {parent.insertBefore(div,parent.firstChild)}
953 * Source a jsMath JavaScript file (only load any given file once)
955 Script: function (file,show) {
956 if (this.loaded[file]) {return} else {this.loaded[file] = 1}
957 if (!file.match('^([a-zA-Z]+:/?)?/')) {file = jsMath.root + file}
958 jsMath.Script.Load(file,show);
962 * Use a hidden <DIV> for measuring the BBoxes of things
964 Hidden: function () {
965 jsMath.hidden = this.DIV("Hidden",{
966 visibility: 'hidden', position:"absolute",
967 top:0, left:0, border:0, padding:0, margin:0
969 jsMath.hiddenTop = jsMath.hidden;
974 * Find the root URL for the jsMath files (so we can load
975 * the other .js and .gif files)
977 Source: function () {
978 if (jsMath.Autoload && jsMath.Autoload.root) {
979 jsMath.root = jsMath.Autoload.root;
982 var script = jsMath.document.getElementsByTagName('script');
984 for (var i = 0; i < script.length; i++) {
985 var src = script[i].src;
986 if (src && src.match('(^|/|\\\\)jsMath.js$')) {
987 jsMath.root = src.replace(/jsMath.js$/,'');
993 if (jsMath.root.charAt(0) == '\\') {jsMath.root = jsMath.root.replace(/\\/g,'/')}
994 if (jsMath.root.charAt(0) == '/') {
995 if (jsMath.root.charAt(1) != '/')
996 {jsMath.root = '//' + jsMath.document.location.host + jsMath.root}
997 jsMath.root = jsMath.document.location.protocol + jsMath.root;
998 } else if (!jsMath.root.match(/^[a-z]+:/i)) {
999 var src = new String(jsMath.document.location);
1000 var pattern = new RegExp('/[^/]*/\\.\\./')
1001 jsMath.root = src.replace(new RegExp('[^/]*$'),'') + jsMath.root;
1002 while (jsMath.root.match(pattern))
1003 {jsMath.root = jsMath.root.replace(pattern,'/')}
1005 jsMath.Img.root = jsMath.root + "fonts/";
1006 jsMath.blank = jsMath.root + "blank.gif";
1011 * Find the most restricted common domain for the main
1012 * page and jsMath. Report an error if jsMath is outside
1013 * the domain of the calling page.
1015 Domain: function () {
1016 try {jsMath.document.domain} catch (err) {return}
1017 var jsDomain = ''; var pageDomain = jsMath.document.domain;
1018 if (jsMath.root.match('://([^/]*)/')) {jsDomain = RegExp.$1}
1019 jsDomain = jsDomain.replace(/:\d+$/,'');
1020 if (jsDomain == "" || jsDomain == pageDomain) return;
1022 // MSIE on the Mac can't change jsMath.document.domain and 'try' won't
1023 // catch the error (Grrr!), so exit for them.
1025 if (navigator.appName == 'Microsoft Internet Explorer' &&
1026 jsMath.platform == 'mac' && navigator.onLine &&
1027 navigator.userProfile && jsMath.document.all) return;
1028 jsDomain = jsDomain.split(/\./); pageDomain = pageDomain.split(/\./);
1029 if (jsDomain.length < 2 || pageDomain.length < 2 ||
1030 jsDomain[jsDomain.length-1] != pageDomain[pageDomain.length-1] ||
1031 jsDomain[jsDomain.length-2] != pageDomain[pageDomain.length-2]) {
1032 this.DomainWarning();
1035 var domain = jsDomain[jsDomain.length-2] + '.' + jsDomain[jsDomain.length-1];
1036 for (var i = 3; i <= jsDomain.length && i <= pageDomain.length; i++) {
1037 if (jsDomain[jsDomain.length-i] != pageDomain[pageDomain.length-i]) break;
1038 domain = jsDomain[jsDomain.length-i] + '.' + domain;
1040 jsMath.document.domain = domain;
1041 this.domainChanged = 1;
1044 DomainWarning: function () {
1045 alert("In order for jsMath to be able to load the additional "
1046 + "components that it may need, the jsMath.js file must be "
1047 + "loaded from a server in the same domain as the page that "
1048 + "contains it. Because that is not the case for this page, "
1049 + "the mathematics displayed here may not appear correctly.");
1053 * Initialize a font's encoding array
1055 EncodeFont: function (name) {
1056 var font = jsMath.TeX[name];
1057 if (font[0].c != null) return;
1058 for (var k = 0; k < 128; k++) {
1059 var data = font[k]; font[k] = data[3];
1060 if (font[k] == null) {font[k] = {}};
1061 font[k].w = data[0]; font[k].h = data[1];
1062 if (data[2] != null) {font[k].d = data[2]}
1063 font[k].c = jsMath.TeX.encoding[k];
1068 * Initialize the encodings for all fonts
1070 Fonts: function () {
1071 for (var i = 0; i < jsMath.TeX.fam.length; i++) {
1072 var name = jsMath.TeX.fam[i];
1073 if (name) {this.EncodeFont(name)}
1078 * Look up the default height and depth for a TeX font
1079 * and set the skewchar
1081 TeXfont: function (name) {
1082 var font = jsMath.TeX[name]; if (font == null) return;
1083 font.hd = jsMath.EmBoxFor('<span class="'+name+'">'+font[65].c+'</span>').h;
1084 font.d = jsMath.EmBoxFor('<span class="'+name+'">'+font[65].c+jsMath.HTML.Strut(font.hd)+'</span>').h - font.hd;
1085 font.h = font.hd - font.d;
1086 if (name == 'cmmi10') {font.skewchar = 0177}
1087 else if (name == 'cmsy10') {font.skewchar = 060}
1091 * Init all the TeX fonts
1093 TeXfonts: function () {
1094 for (var i = 0; i < jsMath.TeX.fam.length; i++)
1095 {if (jsMath.TeX.fam[i]) {this.TeXfont(jsMath.TeX.fam[i])}}
1099 * Compute font parameters for various sizes
1101 Sizes: function () {
1102 jsMath.TeXparams = []; var i; var j;
1103 for (j=0; j < jsMath.sizes.length; j++) {jsMath.TeXparams[j] = {}}
1104 for (i in jsMath.TeX) {
1105 if (typeof(jsMath.TeX[i]) != 'object') {
1106 for (j=0; j < jsMath.sizes.length; j++) {
1107 jsMath.TeXparams[j][i] = jsMath.sizes[j]*jsMath.TeX[i]/100;
1114 * Send the style definitions to the browser (these may be adjusted
1115 * by the browser-specific code)
1117 Styles: function (styles) {
1119 styles = jsMath.styles;
1120 styles['.typeset .scale'] = {'font-size': jsMath.Controls.cookie.scale+'%'};
1121 this.stylesReady = 1;
1123 jsMath.Script.Push(this,'AddStyleSheet',styles);
1124 if (jsMath.Browser.styleChangeDelay) {jsMath.Script.Push(jsMath.Script,'Delay',1)}
1128 * Make a style string from a hash of style definitions, which are
1129 * either strings themselves or hashes of style settings.
1131 StyleString: function (styles) {
1132 var styleString = {}, id;
1133 for (id in styles) {
1134 if (typeof styles[id] === 'string') {
1135 styleString[id] = styles[id];
1136 } else if (id.substr(0,1) === '@') {
1137 styleString[id] = this.StyleString(styles[id]);
1138 } else if (styles[id] != null) {
1140 for (var name in styles[id]) {
1141 if (styles[id][name] != null)
1142 {style[style.length] = name + ': ' + styles[id][name]}
1144 styleString[id] = style.join('; ');
1148 for (id in styleString) {string += id + " {"+styleString[id]+"}\n"}
1152 AddStyleSheet: function (styles) {
1153 var head = jsMath.document.getElementsByTagName('head')[0];
1155 var string = this.StyleString(styles);
1156 if (jsMath.document.createStyleSheet) {// check for MSIE
1157 head.insertAdjacentHTML('beforeEnd',
1158 '<span style="display:none">x</span>' // MSIE needs this for some reason
1159 + '<style type="text/css">'+string+'</style>');
1161 var style = jsMath.document.createElement('style'); style.type = "text/css";
1162 style.appendChild(jsMath.document.createTextNode(string));
1163 head.appendChild(style);
1165 } else if (!jsMath.noHEAD) {
1167 alert("Document is missing its <HEAD> section. Style sheet can't be created without it.");
1172 * Do the initialization that requires the <body> to be in place.
1175 if (this.inited) return;
1179 jsMath.Setup.Hidden(); this.inited = -2;
1180 jsMath.Browser.Init(); this.inited = -3;
1182 // blank screen if necessary
1183 if (jsMath.Controls.cookie.blank) {jsMath.Message.Blank()}; this.inited = -4;
1185 jsMath.Setup.Styles(); this.inited = -5;
1186 jsMath.Controls.Init(); this.inited = -6;
1188 // do user-specific initialization
1189 jsMath.Script.Push(jsMath.Setup,'User','pre-font'); this.inited = -7;
1191 // make sure browser-specific loads are done before this
1192 jsMath.Script.Push(jsMath.Font,'Check');
1193 if (jsMath.Font.register.length)
1194 {jsMath.Script.Push(jsMath.Font,'LoadRegistered')}
1200 * Web page author can override the entries to the UserEvent hash
1201 * functions that will be run at various times during jsMath's setup
1204 User: function (when) {
1205 if (jsMath.Setup.UserEvent[when]) {(jsMath.Setup.UserEvent[when])()}
1209 "pre-font": null, // after browser is set up but before fonts are tested
1210 "onload": null // after jsMath.js is loaded and finished running
1218 * Update specific parameters for a limited number of font entries
1220 TeXfonts: function (change) {
1221 for (var font in change) {
1222 for (var code in change[font]) {
1223 for (var id in change[font][code]) {
1224 jsMath.TeX[font][code][id] = change[font][code][id];
1231 * Update the character code for every character in a list
1234 TeXfontCodes: function (change) {
1235 for (var font in change) {
1236 for (var i = 0; i < change[font].length; i++) {
1237 jsMath.TeX[font][i].c = change[font][i];
1244 /***************************************************************************/
1247 * Implement browser-specific checks
1252 allowAbsolute: 1, // tells if browser can nest absolutely positioned
1253 // SPANs inside relative SPANs
1254 allowAbsoluteDelim: 0, // OK to use absolute placement for building delims?
1255 separateSkips: 0, // MSIE doesn't do negative left margins, and
1256 // Netscape doesn't combine skips well
1258 valignBug: 0, // Konqueror doesn't nest vertical-align
1259 operaHiddenFix: '', // for Opera to fix bug with math in tables
1260 msieCenterBugFix: '', // for MSIE centering bug with image fonts
1261 msieInlineBlockFix: '', // for MSIE alignment bug in non-quirks mode
1262 msieSpaceFix: '', // for MSIE to avoid dropping empty spans
1263 imgScale: 1, // MSI scales images for 120dpi screens, so compensate
1265 renameOK: 1, // tells if brower will find a tag whose name
1266 // has been set via setAttributes
1267 styleChangeDelay: 0, // true if style changes need a delay in order
1268 // for them to be available
1270 delay: 1, // delay for asynchronous math processing
1271 processAtOnce: 16, // number of math elements to process before screen update
1273 version: 0, // browser version number (when needed)
1276 * Determine if the "top" of a <SPAN> is always at the same height
1277 * or varies with the height of the rest of the line (MSIE).
1279 TestSpanHeight: function () {
1280 jsMath.hidden.innerHTML = '<span><span style="'+this.block+';height:2em;width:1px"></span>x</span>';
1281 var span = jsMath.hidden.firstChild;
1282 var img = span.firstChild;
1283 this.spanHeightVaries = (span.offsetHeight >= img.offsetHeight && span.offsetHeight > 0);
1284 this.spanHeightTooBig = (span.offsetHeight > img.offsetHeight);
1285 jsMath.hidden.innerHTML = '';
1289 * Determine if an inline-block with 0 width is OK or not
1290 * and decide whether to use spans or images for spacing
1292 TestInlineBlock: function () {
1293 this.block = "display:-moz-inline-box";
1294 this.hasInlineBlock = jsMath.BBoxFor('<span style="'+this.block+';width:10px;height:5px"></span>').w > 0;
1295 if (this.hasInlineBlock) {
1296 jsMath.styles['.typeset .blank'].display = '-moz-inline-box';
1297 delete jsMath.styles['.typeset .spacer'].display;
1299 this.block = "display:inline-block";
1300 this.hasInlineBlock = jsMath.BBoxFor('<span style="'+this.block+';width:10px;height:5px"></span>').w > 0;
1301 if (!this.hasInlineBlock) return;
1303 this.block += ';overflow:hidden';
1304 var h = jsMath.BBoxFor('x').h;
1305 this.mozInlineBlockBug = jsMath.BBoxFor(
1306 '<span style="'+this.block+';height:'+h+'px;width:1px"></span>x'+
1307 '<span style="'+this.block+';height:'+h+'px;width:1px;vertical-align:-'+h+'px"></span>').h > 2*h;
1308 this.widthAddsBorder = jsMath.BBoxFor('<span style="'+this.block+
1309 ';overflow:hidden;height:1px;width:10px;border-left:10px solid"></span>').w > 10;
1310 var h1 = jsMath.BBoxFor('<span style="'+this.block+';height:'+h+'px;width:1px"></span>x').h,
1311 h2 = jsMath.BBoxFor('<span style="'+this.block+';height:'+h+'px;width:1px;border-left:1px solid"></span>x').h,
1312 h3 = jsMath.BBoxFor('<span style="'+this.block+';height:2em"></span>').h;
1313 this.msieBlockDepthBug = (h1 == h);
1314 this.msieRuleDepthBug = (h2 == h);
1315 this.blankWidthBug = (h3 == 0);
1319 * Determine if the NAME attribute of a tag can be changed
1320 * using the setAttribute function, and then be properly
1321 * returned by getElementByName.
1323 TestRenameOK: function () {
1324 jsMath.hidden.innerHTML = '<span></span>';
1325 var test = jsMath.hidden.firstChild;
1326 test.setAttribute('name','jsMath_test');
1327 this.renameOK = (jsMath.document.getElementsByName('jsMath_test').length > 0);
1328 jsMath.hidden.innerHTML = '';
1332 * See if style changes occur immediately, or if we need to delay
1333 * in order to let them take effect.
1335 TestStyleChange: function () {
1336 jsMath.hidden.innerHTML = '<span ID="jsMath_test">x</span>';
1337 var span = jsMath.hidden.firstChild;
1338 var w = span.offsetWidth;
1339 jsMath.Setup.AddStyleSheet({'#jsMath_test': 'font-size:200%'});
1340 this.styleChangeDelay = (span.offsetWidth == w);
1341 jsMath.hidden.innerHTML = '';
1345 * Perform a version check on a standard version string
1347 VersionAtLeast: function (v) {
1348 var bv = new String(this.version).split('.');
1349 v = new String(v).split('.'); if (v[1] == null) {v[1] = '0'}
1350 return bv[0] > v[0] || (bv[0] == v[0] && bv[1] >= v[1]);
1354 * Test for browser characteristics, and adjust things
1355 * to overcome specific browser bugs
1358 jsMath.browser = 'unknown';
1359 this.TestInlineBlock();
1360 this.TestSpanHeight();
1361 this.TestRenameOK();
1362 this.TestStyleChange();
1372 // Change some routines depending on the browser
1374 if (this.allowAbsoluteDelim) {
1375 jsMath.Box.DelimExtend = jsMath.Box.DelimExtendAbsolute;
1376 jsMath.Box.Layout = jsMath.Box.LayoutAbsolute;
1378 jsMath.Box.DelimExtend = jsMath.Box.DelimExtendRelative;
1379 jsMath.Box.Layout = jsMath.Box.LayoutRelative;
1382 if (this.separateSkips) {
1383 jsMath.HTML.Place = jsMath.HTML.PlaceSeparateSkips;
1384 jsMath.Typeset.prototype.Place = jsMath.Typeset.prototype.PlaceSeparateSkips;
1389 // Handle bug-filled Internet Explorer
1392 if (jsMath.BBoxFor("<!--[if IE]>IE<![endif]-->").w) {
1393 jsMath.browser = 'MSIE';
1394 if (jsMath.platform == 'pc') {
1395 this.IE7 = (window.XMLHttpRequest != null);
1396 this.IE8 = (jsMath.BBoxFor("<!--[if gte IE 8]>IE8<![endif]-->").w > 0);
1397 this.isReallyIE8 = (jsMath.document.documentMode != null);
1398 this.quirks = (jsMath.document.compatMode == "BackCompat");
1399 this.msieMode = (jsMath.document.documentMode || (this.quirks ? 5 : 7));
1400 this.msieStandard6 = !this.quirks && !this.IE7;
1401 this.allowAbsoluteDelim = 1; this.separateSkips = 1;
1402 this.buttonCheck = 1; this.msieBlankBug = 1;
1403 this.msieAccentBug = 1; this.msieRelativeClipBug = 1;
1404 this.msieDivWidthBug = 1; this.msiePositionFixedBug = 1;
1405 this.msieIntegralBug = 1; this.waitForImages = 1;
1406 this.msieAlphaBug = !this.IE7; this.alphaPrintBug = !this.IE7;
1407 this.msieCenterBugFix = 'position:relative; ';
1408 this.msieInlineBlockFix = ' display:inline-block;';
1409 this.msie8HeightBug = this.msieBBoxBug = (this.msieMode == 8);
1410 this.blankWidthBug = (this.msieMode != 8);
1411 this.msieSpaceFix = (this.isReallyIE8 ?
1412 '<span style="display:inline-block; margin-right:-1px; width:1px"></span>' :
1413 '<span style="margin-right:-1px; width:1px"></span>');
1414 jsMath.Macro('joinrel','\\mathrel{\\kern-5mu}'),
1415 jsMath.Parser.prototype.mathchardef.mapstocharOrig = jsMath.Parser.prototype.mathchardef.mapstochar;
1416 delete jsMath.Parser.prototype.mathchardef.mapstochar;
1417 jsMath.Macro('mapstochar','\\rlap{\\mapstocharOrig\\,}\\kern1mu'),
1418 jsMath.styles['.typeset .arial'] = {'font-family': "'Arial unicode MS'"};
1419 if (!this.IE7 || this.quirks) {
1420 // MSIE doesn't implement fixed positioning, so use absolute
1421 jsMath.styles['#jsMath_message'].position = 'absolute';
1422 delete jsMath.styles['#jsMath_message'].width;
1423 jsMath.styles['#jsMath_panel'].position = 'absolute';
1424 delete jsMath.styles['#jsMath_panel'].width;
1425 jsMath.styles['#jsMath_button'].width = '1px';
1426 jsMath.styles['#jsMath_button'].position = 'absolute'
1427 delete jsMath.styles['#jsMath_button'].width;
1428 jsMath.fixedDiv = jsMath.Setup.DIV("fixedDiv",{position:'absolute', zIndex: 101});
1429 jsMath.window.attachEvent("onscroll",jsMath.Controls.MoveButton);
1430 jsMath.window.attachEvent("onresize",jsMath.Controls.MoveButton);
1431 jsMath.Controls.MoveButton();
1433 // Make MSIE put borders around the whole button
1434 jsMath.styles['#jsMath_noFont .link'].display = "inline-block";
1435 // MSIE needs this NOT to be inline-block
1436 delete jsMath.styles['.typeset .spacer'].display;
1437 // MSIE can't insert DIV's into text nodes, so tex2math must use SPAN's to fake DIV's
1438 jsMath.styles['.tex2math_div'] = {}; jsMath.Add(jsMath.styles['.tex2math_div'],jsMath.styles['div.typeset']);
1439 jsMath.styles['.tex2math_div'].width = '100%';
1440 jsMath.styles['.tex2math_div'].display = 'inline-block';
1441 // Reduce occurrance of zoom bug in IE7
1442 jsMath.styles['.typeset']['letter-spacing'] = '0';
1443 // MSIE will rescale images if the DPIs differ
1444 if (screen.deviceXDPI && screen.logicalXDPI
1445 && screen.deviceXDPI != screen.logicalXDPI) {
1446 this.imgScale *= screen.logicalXDPI/screen.deviceXDPI;
1447 jsMath.Controls.cookie.alpha = 0;
1449 // IE8 doesn't puts ALL boxes at the bottom rather than on the baseline
1450 if (this.msieRuleDepthBug) {jsMath.HTML.Strut = jsMath.HTML.msieStrut}
1451 } else if (jsMath.platform == 'mac') {
1452 this.msieAbsoluteBug = 1; this.msieButtonBug = 1;
1453 this.msieDivWidthBug = 1; this.msieBlankBug = 1;
1455 jsMath.Setup.Script('jsMath-msie-mac.js');
1456 jsMath.Parser.prototype.macros.angle = ['Replace','ord','<font face="Symbol">‹</font>','normal'];
1457 jsMath.styles['#jsMath_panel'].width = '42em';
1458 jsMath.Controls.cookie.printwarn = 0; // MSIE/Mac doesn't handle '@media screen'
1460 this.processAtOnce = Math.max(Math.floor((this.processAtOnce+1)/2),1);
1461 jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}');
1462 jsMath.Macro('angle','\\raise1.84pt{\\kern2.5mu\\rlap{\\scriptstyle/}\\kern.5pt\\rule{.4em}{-1.5pt}{1.84pt}\\kern2.5mu}');
1467 // Handle Netscape/Mozilla (any flavor)
1469 Mozilla: function () {
1470 if (jsMath.hidden.ATTRIBUTE_NODE && jsMath.window.directories) {
1471 jsMath.browser = 'Mozilla';
1472 if (jsMath.platform == 'pc') {this.alphaPrintBug = 1}
1473 this.allowAbsoluteDelim = 1;
1474 jsMath.styles['#jsMath_button'].cursor = jsMath.styles['#jsMath_noFont .link'].cursor = 'pointer',
1475 jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}');
1476 jsMath.Macro('angle','\\raise1.34pt{\\kern2.5mu\\rlap{\\scriptstyle/}\\rule{.4em}{-1pt}{1.34pt}\\kern2.5mu}');
1477 if (navigator.vendor == 'Firefox') {
1478 this.version = navigator.vendorSub;
1479 } else if (navigator.userAgent.match(' Firefox/([0-9.]+)([a-z ]|$)')) {
1480 this.version = RegExp.$1;
1482 if (this.VersionAtLeast("3.0")) {this.mozImageSizeBug = this.lineBreakBug = 1}
1489 OmniWeb: function () {
1490 if (navigator.accentColorName) {
1491 jsMath.browser = 'OmniWeb';
1492 this.allowAbsolute = this.hasInlineBlock;
1493 this.allowAbsoluteDelim = this.allowAbsolute;
1494 this.valignBug = !this.allowAbsolute;
1495 this.buttonCheck = 1; this.textNodeBug = 1;
1496 jsMath.noChangeGlobal = 1; // OmniWeb craches on GoGlobal
1497 if (!this.hasInlineBlock) {jsMath.Setup.Script('jsMath-old-browsers.js')}
1504 Opera: function () {
1505 if (this.spanHeightTooBig) {
1506 jsMath.browser = 'Opera';
1507 var isOld = navigator.userAgent.match("Opera 7");
1508 this.allowAbsolute = 0;
1510 this.operaHiddenFix = '[Processing]';
1511 if (isOld) {jsMath.Setup.Script('jsMath-old-browsers.js')}
1512 var version = navigator.appVersion.match(/^(\d+\.\d+)/);
1513 if (version) {this.version = version[1]} else {this.vesion = 0}
1514 this.operaAbsoluteWidthBug = this.operaLineHeightBug = (version[1] >= 9.5 && version[1] < 9.6);
1521 Safari: function () {
1522 if (navigator.appVersion.match(/Safari\//)) {
1523 jsMath.browser = 'Safari';
1524 if (navigator.vendor.match(/Google/)) {jsMath.browser = 'Chrome'}
1525 var version = navigator.userAgent.match("Safari/([0-9]+)");
1526 version = (version)? version[1] : 400; this.version = version;
1527 jsMath.TeX.axis_height += .05;
1528 this.allowAbsoluteDelim = version >= 125;
1529 this.safariIFRAMEbug = version >= 312 && version < 412;
1530 this.safariButtonBug = version < 412;
1531 this.safariImgBug = 1; this.textNodeBug = 1;
1532 this.lineBreakBug = version >= 526;
1533 this.buttonCheck = version < 500;
1534 this.styleChangeDelay = 1;
1535 jsMath.Macro('not','\\mathrel{\\rlap{\\kern3.25mu/}}');
1542 Konqueror: function () {
1543 if (navigator.product && navigator.product.match("Konqueror")) {
1544 jsMath.browser = 'Konqueror';
1545 this.allowAbsolute = 0;
1546 this.allowAbsoluteDelim = 0;
1547 if (navigator.userAgent.match(/Konqueror\/(\d+)\.(\d+)/)) {
1548 if (RegExp.$1 < 3 || (RegExp.$1 == 3 && RegExp.$2 < 3)) {
1549 this.separateSkips = 1;
1551 jsMath.Setup.Script('jsMath-old-browsers.js');
1554 // Apparently, Konqueror wants the names without the hyphen
1555 jsMath.Add(jsMath.styles,{
1556 '.typeset .cmr10': 'font-family: jsMath-cmr10, jsMath cmr10, serif',
1557 '.typeset .cmbx10': 'font-family: jsMath-cmbx10, jsMath cmbx10, jsMath-cmr10, jsMath cmr10',
1558 '.typeset .cmti10': 'font-family: jsMath-cmti10, jsMath cmti10, jsMath-cmr10, jsMath cmr10',
1559 '.typeset .cmmi10': 'font-family: jsMath-cmmi10, jsMath cmmi10',
1560 '.typeset .cmsy10': 'font-family: jsMath-cmsy10, jsMath cmsy10',
1561 '.typeset .cmex10': 'font-family: jsMath-cmex10, jsMath cmex10'
1563 jsMath.Font.testFont = "jsMath-cmex10, jsMath cmex10";
1569 /***************************************************************************/
1572 * Implement font check and messages
1576 testFont: "jsMath-cmex10",
1577 fallback: "symbol", // the default fallback method
1578 register: [], // list of fonts registered before jsMath.Init()
1580 // the HTML for the missing font message
1582 '<b>No jsMath TeX fonts found</b> -- using image fonts instead.<br/>\n'
1583 + 'These may be slow and might not print well.<br/>\n'
1584 + 'Use the jsMath control panel to get additional information.',
1587 'Extra TeX fonts not found: <b><span id="jsMath_ExtraFonts"></span></b><br/>'
1588 + 'Using image fonts instead. This may be slow and might not print well.<br/>\n'
1589 + 'Use the jsMath control panel to get additional information.',
1592 'To print higher-resolution math symbols, click the<br/>\n'
1593 + '<b>Hi-Res Fonts for Printing</b> button on the jsMath control panel.<br/>\n',
1596 'If the math symbols print as black boxes, turn off <b>image alpha channels</b><br/>\n'
1597 + 'using the <B>Options</B> pane of the jsMath control panel.<br/>\n',
1600 * Look to see if a font is found.
1601 * Check the character in a given position, and see if it is
1602 * wider than the usual one in that position.
1604 Test1: function (name,n,factor,prefix) {
1605 if (n == null) {n = 0x7C}; if (factor == null) {factor = 2}; if (prefix == null) {prefix = ''}
1606 var wh1 = jsMath.BBoxFor('<span style="font-family: '+prefix+name+', serif">'+jsMath.TeX[name][n].c+'</span>');
1607 var wh2 = jsMath.BBoxFor('<span style="font-family: serif">'+jsMath.TeX[name][n].c+'</span>');
1608 //alert([wh1.w,wh2.w,wh1.h,factor*wh2.w]);
1609 return (wh1.w > factor*wh2.w && wh1.h != 0);
1612 Test2: function (name,n,factor,prefix) {
1613 if (n == null) {n = 0x7C}; if (factor == null) {factor = 2}; if (prefix == null) {prefix = ''}
1614 var wh1 = jsMath.BBoxFor('<span style="font-family: '+prefix+name+', serif">'+jsMath.TeX[name][n].c+'</span>');
1615 var wh2 = jsMath.BBoxFor('<span style="font-family: serif">'+jsMath.TeX[name][n].c+'</span>');
1616 //alert([wh2.w,wh1.w,wh1.h,factor*wh1.w]);
1617 return (wh2.w > factor*wh1.w && wh1.h != 0);
1621 * Check for the new jsMath versions of the fonts (blacker with
1622 * different encoding) and if not found, look for old-style fonts.
1623 * If they are found, load the BaKoMa encoding information.
1625 CheckTeX: function () {
1626 var wh = jsMath.BBoxFor('<span style="font-family: '+jsMath.Font.testFont+', serif">'+jsMath.TeX.cmex10[1].c+'</span>');
1627 jsMath.nofonts = ((wh.w*3 > wh.h || wh.h == 0) && !this.Test1('cmr10',null,null,'jsMath-'));
1628 if (!jsMath.nofonts) return;
1630 * if (jsMath.browser != 'Mozilla' ||
1631 * (jsMath.platform == "mac" &&
1632 * (!jsMath.Browser.VersionAtLeast(1.5) || jsMath.Browser.VersionAtLeast(3.0))) ||
1633 * (jsMath.platform != "mac" && !jsMath.Browser.VersionAtLeast(3.0))) {
1634 * wh = jsMath.BBoxFor('<span style="font-family: CMEX10, serif">'+jsMath.TeX.cmex10[1].c+'</span>');
1635 * jsMath.nofonts = ((wh.w*3 > wh.h || wh.h == 0) && !this.Test1('cmr10'));
1636 * if (!jsMath.nofonts) {jsMath.Setup.Script("jsMath-BaKoMa-fonts.js")}
1642 * Check for the availability of TeX fonts. We do this by looking at
1643 * the width and height of a character in the cmex10 font. The cmex10
1644 * font has depth considerably greater than most characters' widths (the
1645 * whole font has the depth of the character with greatest depth). This
1646 * is not the case for most fonts, so if we can access cmex10, the
1647 * height of a character should be much bigger than the width.
1648 * Otherwise, if we don't have cmex10, we'll get a character in another
1649 * font with normal height and width. In this case, we insert a message
1650 * pointing the user to the jsMath site, and load one of the fallback
1654 Check: function () {
1655 var cookie = jsMath.Controls.cookie;
1657 if (jsMath.nofonts) {
1658 if (cookie.autofont || cookie.font == 'tex') {
1659 cookie.font = this.fallback;
1661 jsMath.nofontMessage = 1;
1662 cookie.warn = 0; jsMath.Controls.SetCookie(0);
1663 if (jsMath.window.NoFontMessage) {jsMath.window.NoFontMessage()}
1664 else {this.Message(this.message)}
1668 if (cookie.autofont) {cookie.font = 'tex'}
1669 if (cookie.font == 'tex') return;
1671 if (jsMath.noImgFonts) {cookie.font = 'unicode'}
1672 if (cookie.font == 'unicode') {
1673 jsMath.Setup.Script('jsMath-fallback-'+jsMath.platform+'.js');
1674 jsMath.Box.TeXnonfallback = jsMath.Box.TeX;
1675 jsMath.Box.TeX = jsMath.Box.TeXfallback;
1678 if (!cookie.print && cookie.printwarn) {
1680 (jsMath.Browser.alphaPrintBug && jsMath.Controls.cookie.alpha) ?
1681 this.print_message + this.alpha_message : this.print_message);
1683 if (jsMath.Browser.waitForImages) {
1684 jsMath.Script.Push(jsMath.Script,"WaitForImage",jsMath.blank);
1686 if (cookie.font == 'symbol') {
1687 jsMath.Setup.Script('jsMath-fallback-symbols.js');
1688 jsMath.Box.TeXnonfallback = jsMath.Box.TeX;
1689 jsMath.Box.TeX = jsMath.Box.TeXfallback;
1692 jsMath.Img.SetFont({
1693 cmr10: ['all'], cmmi10: ['all'], cmsy10: ['all'],
1694 cmex10: ['all'], cmbx10: ['all'], cmti10: ['all']
1696 jsMath.Img.LoadFont('cm-fonts');
1700 * The message for when no TeX fonts. You can eliminate this message
1703 * <script>jsMath = {Font: {Message: function () {}}}</script>
1705 * in your HTML file, before loading jsMath.js, if you want. But this
1706 * means the user may not know that he or she can get a better version
1709 Message: function (message) {
1710 if (jsMath.Element("Warning")) return;
1711 var div = jsMath.Setup.DIV("Warning",{});
1713 '<center><table><tr><td>'
1714 + '<div id="jsMath_noFont"><div class="message">' + message
1715 + '<div style="text-align:left"><span style="float:left; margin: 8px 0px 0px 20px">'
1716 + '<span onclick="jsMath.Controls.Panel()" title=" Open the jsMath Control Panel " class="link">jsMath Control Panel</span>'
1717 + '</span><span style="margin: 8px 20px 0px 0px; float:right">'
1718 + '<span onclick="jsMath.Font.HideMessage()" title=" Remove this font warning message " class="link">Hide this Message</span>'
1719 + '</span></div><div style="height:6px"></div><br clear="all"/></div></div>'
1720 + '<div style="width:22em; height:1px"></div>'
1721 + '</td></tr></table></center><hr/>';
1724 HideMessage: function () {
1725 var message = jsMath.Element("Warning");
1726 if (message) {message.style.display = "none"}
1729 PrintMessage: function (message) {
1730 if (jsMath.Element("PrintWarning")) return;
1731 var div = jsMath.Setup.DIV("PrintWarning",{});
1733 '<center><table><tr><td>'
1734 + '<div class="message">' + message + '</div>'
1735 + '<div style="width:22em; height:1px"></div>'
1736 + '</td></tr></table></center><hr/>';
1740 * Register an extra font so jsMath knows about it
1742 Register: function (data,force) {
1743 if (typeof(data) == 'string') {data = {name: data}}
1744 if (!jsMath.Setup.inited && !force) {
1745 this.register[this.register.length] = data;
1748 var fontname = data.name; var name = fontname.replace(/10$/,'');
1749 var fontfam = jsMath.TeX.fam.length;
1750 if (data.prefix == null) {data.prefix = ""}
1751 if (!data.style) {data.style = "font-family: "+data.prefix+fontname+", serif"}
1752 if (!data.styles) {data.styles = {}}
1753 if (!data.macros) {data.macros = {}}
1755 * Register font family
1757 jsMath.TeX.fam[fontfam] = fontname;
1758 jsMath.TeX.famName[fontname] = fontfam;
1759 data.macros[name] = ['HandleFont',fontfam];
1760 jsMath.Add(jsMath.Parser.prototype.macros,data.macros);
1764 data.styles['.typeset .'+fontname] = data.style;
1765 jsMath.Setup.Styles(data.styles);
1766 if (jsMath.initialized) {jsMath.Script.Push(jsMath.Setup,'TeXfont',fontname)}
1768 * Check for font and give message if missing
1770 var cookie = jsMath.Controls.cookie;
1771 var hasTeXfont = !jsMath.nofonts &&
1772 data.test(fontname,data.testChar,data.testFactor,data.prefix);
1773 if (hasTeXfont && cookie.font == 'tex') {
1774 if (data.tex) {data.tex(fontname,fontfam,data)}
1777 if (!hasTeXfont && cookie.warn && cookie.font == 'tex' && !jsMath.nofonts) {
1778 if (!cookie.fonts.match("/"+fontname+"/")) {
1779 cookie.fonts += fontname + "/"; jsMath.Controls.SetCookie(0);
1780 if (!jsMath.Element("Warning")) this.Message(this.extra_message);
1781 var extra = jsMath.Element("ExtraFonts");
1783 if (extra.innerHTML != "") {extra.innerHTML += ','}
1784 extra.innerHTML += " " + data.prefix+fontname;
1788 if (cookie.font == 'unicode' || jsMath.noImgFonts) {
1789 if (data.fallback) {data.fallback(fontname,fontfam,data)}
1794 if (cookie.font == 'symbol' && data.symbol != null) {
1795 font[fontname] = data.symbol(fontname,fontfam,data);
1797 font[fontname] = ['all'];
1799 jsMath.Img.SetFont(font);
1800 jsMath.Img.LoadFont(fontname);
1801 if (jsMath.initialized) {
1802 jsMath.Script.Push(jsMath.Img,'Scale');
1803 jsMath.Script.Push(jsMath.Img,'UpdateFonts');
1807 * If fonts are registered before jsMath.Init() is called, jsMath.em
1808 * will not be available, so they need to be delayed.
1810 LoadRegistered: function () {
1812 while (i < this.register.length) {this.Register(this.register[i++],1)}
1819 Load: function (name) {jsMath.Setup.Script(this.URL(name))},
1820 URL: function (name) {return jsMath.Img.root+name+'/def.js'}
1824 /***************************************************************************/
1827 * Implements the jsMath control panel.
1828 * Much of the code is in jsMath-controls.html, which is
1829 * loaded into a hidden IFRAME on demand
1833 // Data stored in the jsMath cookie
1836 font: 'tex', autofont: 1, scaleImg: 0, alpha: 1,
1837 warn: 1, fonts: '/', printwarn: 1, stayhires: 0,
1838 button: 1, progress: 1, asynch: 0, blank: 0,
1839 print: 0, keep: '0D', global: 'auto', hiddenGlobal: 1
1842 cookiePath: '/', // can also set cookieDomain
1843 noCookiePattern: /^(file|mk):$/, // pattern for handling cookies locally
1847 * Create the HTML needed for control panel
1850 this.panel = jsMath.Setup.DIV("panel",{display:'none'},jsMath.fixedDiv);
1851 if (!jsMath.Browser.msieButtonBug) {this.Button()}
1852 else {setTimeout("jsMath.Controls.Button()",500)}
1856 * Load the control panel
1858 Panel: function () {
1859 jsMath.Translate.Cancel();
1860 if (this.loaded) {this.Main()}
1861 else {jsMath.Script.delayedLoad(jsMath.root+"jsMath-controls.html")}
1865 * Create the control panel button
1867 Button: function () {
1868 var button = jsMath.Setup.DIV("button",{},jsMath.fixedDiv);
1869 button.title = ' Open jsMath Control Panel ';
1871 '<span onclick="jsMath.Controls.Panel()">jsMath</span>';
1872 if (!jsMath.Global.isLocal && !jsMath.noShowGlobal) {
1874 '<span id="jsMath_global" title=" Open jsMath Global Panel " '
1875 + 'onclick="jsMath.Global.Show(1)">Global </span>';
1877 if (button.offsetWidth < 30) {button.style.width = "auto"}
1878 if (!this.cookie.button) {button.style.display = "none"}
1882 * Since MSIE doesn't handle position:float, we need to have the
1883 * window repositioned every time the window scrolls. We do that
1884 * putting the floating elements into a window-sized DIV, but
1885 * absolutely positioned, and then move the DIV.
1887 MoveButton: function () {
1888 var body = (jsMath.Browser.quirks ? document.body : document.documentElement);
1889 jsMath.fixedDiv.style.left = body.scrollLeft + 'px';
1890 jsMath.fixedDiv.style.top = body.scrollTop + body.clientHeight + 'px';
1891 jsMath.fixedDiv.style.width = body.clientWidth + 'px';
1892 // jsMath.fixedDiv.style.top = body.scrollTop + 'px';
1893 // jsMath.fixedDiv.style.height = body.clientHeight + 'px';
1897 * Get the cookie data from the browser
1898 * (for file: references, use url '?' syntax)
1900 GetCookie: function () {
1901 // save the current cookie settings as the defaults
1902 if (this.defaults == null) {this.defaults = {}}
1903 jsMath.Add(this.defaults,this.cookie); this.userSet = {};
1904 // get the browser's cookie data
1905 var cookies = jsMath.document.cookie;
1906 if (jsMath.window.location.protocol.match(this.noCookiePattern)) {
1907 cookies = this.localGetCookie();
1908 this.isLocalCookie = 1;
1910 if (cookies.match(/jsMath=([^;]+)/)) {
1911 var data = unescape(RegExp.$1).split(/,/);
1912 for (var i = 0; i < data.length; i++) {
1913 var x = data[i].match(/(.*):(.*)/);
1914 if (x[2].match(/^\d+$/)) {x[2] = 1*x[2]} // convert from string
1915 this.cookie[x[1]] = x[2];
1916 this.userSet[x[1]] = 1;
1920 localGetCookie: function () {
1921 return jsMath.window.location.search.substr(1);
1925 * Save the cookie data in the browser
1926 * (for file: urls, append data like CGI reference)
1928 SetCookie: function (warn) {
1930 for (var id in this.cookie) {
1931 if (this.defaults[id] == null || this.cookie[id] != this.defaults[id])
1932 {cookie[cookie.length] = id + ':' + this.cookie[id]}
1934 cookie = cookie.join(',');
1935 if (this.isLocalCookie) {
1936 if (warn == 2) {return 'jsMath='+escape(cookie)}
1937 this.localSetCookie(cookie,warn);
1939 cookie = escape(cookie);
1940 if (cookie == '') {warn = 0}
1941 if (this.cookiePath) {cookie += '; path='+this.cookiePath}
1942 if (this.cookieDomain) {cookie += '; domain='+this.cookieDomain}
1943 if (this.cookie.keep != '0D') {
1947 M: 1000*60*60*24*30,
1948 Y: 1000*60*60*24*365
1951 exp.setTime(exp.getTime() +
1952 this.cookie.keep.substr(0,1) * ms[this.cookie.keep.substr(1,1)]);
1953 cookie += '; expires=' + exp.toGMTString();
1956 jsMath.document.cookie = 'jsMath='+cookie;
1957 var cookies = jsMath.document.cookie;
1958 if (warn && !cookies.match(/jsMath=/))
1959 {alert("Cookies must be enabled in order to save jsMath options")}
1964 localSetCookie: function (cookie,warn) {
1966 var href = String(jsMath.window.location).replace(/\?.*/,"");
1967 if (cookie != '') {href += '?jsMath=' + escape(cookie)}
1968 if (href != jsMath.window.location.href) {this.Reload(href)}
1972 * Reload the page (with the given URL)
1974 Reload: function (url) {
1975 if (!this.loaded) return;
1976 this.loaded = 0; jsMath.Setup.inited = -100;
1977 jsMath.Global.ClearCache();
1978 if (url) {jsMath.window.location.replace(url)}
1979 else {jsMath.window.location.reload()}
1984 /***************************************************************************/
1987 * Implements the actions for clicking and double-clicking
1993 * Handle clicking on math to get control panel
1995 CheckClick: function (event) {
1996 if (!event) {event = jsMath.window.event}
1997 if (event.altKey) jsMath.Controls.Panel();
2001 * Handle double-click for seeing TeX code
2004 CheckDblClick: function (event) {
2005 if (!event) {event = jsMath.window.event}
2006 if (!jsMath.Click.DblClick) {
2007 jsMath.Extension.Require('double-click',1);
2008 // Firefox clears the event, so copy it
2009 var tmpEvent = event; event = {};
2010 for (var id in tmpEvent) {event[id] = tmpEvent[id]}
2012 jsMath.Script.Push(jsMath.Click,'DblClick',[event,this.alt]);
2017 /***************************************************************************/
2020 * The TeX font information
2025 // The TeX font parameters
2048 default_rule_thickness: .06,
2049 big_op_spacing1: .111111,
2050 big_op_spacing2: .166666,
2051 big_op_spacing3: .2,
2052 big_op_spacing4: .6,
2053 big_op_spacing5: .1,
2055 integer: 6553.6, // conversion of em's to TeX internal integer
2057 nulldelimiterspace: .12,
2058 delimiterfactor: 901,
2059 delimitershortfall: .5,
2060 scale: 1, // scaling factor for font dimensions
2062 // The TeX math atom types (see Appendix G of the TeXbook)
2063 atom: ['ord', 'op', 'bin', 'rel', 'open', 'close', 'punct', 'ord'],
2065 // The TeX font families
2066 fam: ['cmr10','cmmi10','cmsy10','cmex10','cmti10','','cmbx10',''],
2067 famName: {cmr10:0, cmmi10:1, cmsy10:2, cmex10:3, cmti10:4, cmbx10:6},
2069 // Encoding used by jsMath fonts
2071 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç',
2072 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï',
2074 '°', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '·',
2075 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'µ', '¶', 'ß',
2077 'ï', '!', '"', '#', '$', '%', '&', ''',
2078 '(', ')', '*', '+', ',', '-', '.', '/',
2080 '0', '1', '2', '3', '4', '5', '6', '7',
2081 '8', '9', ':', ';', '<', '=', '>', '?',
2083 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
2084 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
2086 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
2087 'X', 'Y', 'Z', '[', '\', ']', '^', '_',
2089 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
2090 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
2092 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
2093 'x', 'y', 'z', '{', '|', '}', '~', 'ÿ'
2097 * The following are the TeX font mappings and metrics. The metric
2098 * information comes directly from the TeX .tfm files. Browser-specific
2099 * adjustments are made to these tables in the Browser.Init() routine
2102 [0.625,0.683], [0.833,0.683], [0.778,0.683], [0.694,0.683],
2103 [0.667,0.683], [0.75,0.683], [0.722,0.683], [0.778,0.683],
2104 [0.722,0.683], [0.778,0.683], [0.722,0.683],
2105 [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}}],
2106 [0.556,0.694], [0.556,0.694], [0.833,0.694], [0.833,0.694],
2108 [0.278,0.431], [0.306,0.431,0.194], [0.5,0.694], [0.5,0.694],
2109 [0.5,0.628], [0.5,0.694], [0.5,0.568], [0.75,0.694],
2110 [0.444,0,0.17], [0.5,0.694], [0.722,0.431], [0.778,0.431],
2111 [0.5,0.528,0.0972], [0.903,0.683], [1.01,0.683], [0.778,0.732,0.0486],
2113 [0.278,0.431,0,{krn: {'108': -0.278, '76': -0.319}}],
2114 [0.278,0.694,0,{lig: {'96': 60}}],
2115 [0.5,0.694], [0.833,0.694,0.194], [0.5,0.75,0.0556],
2116 [0.833,0.75,0.0556], [0.778,0.694],
2117 [0.278,0.694,0,{krn: {'63': 0.111, '33': 0.111}, lig: {'39': 34}}],
2118 [0.389,0.75,0.25], [0.389,0.75,0.25], [0.5,0.75],
2119 [0.778,0.583,0.0833], [0.278,0.106,0.194],
2120 [0.333,0.431,0,{lig: {'45': 123}}],
2121 [0.278,0.106], [0.5,0.75,0.25],
2123 [0.5,0.644], [0.5,0.644], [0.5,0.644], [0.5,0.644],
2124 [0.5,0.644], [0.5,0.644], [0.5,0.644], [0.5,0.644],
2125 [0.5,0.644], [0.5,0.644], [0.278,0.431], [0.278,0.431,0.194],
2126 [0.278,0.5,0.194], [0.778,0.367,-0.133], [0.472,0.5,0.194],
2127 [0.472,0.694,0,{lig: {'96': 62}}],
2130 [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}}],
2131 [0.708,0.683], [0.722,0.683],
2132 [0.764,0.683,0,{krn: {'88': -0.0278, '87': -0.0278, '65': -0.0278, '86': -0.0278, '89': -0.0278}}],
2134 [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}}],
2135 [0.785,0.683], [0.75,0.683], [0.361,0.683,0,{krn: {'73': 0.0278}}],
2137 [0.778,0.683,0,{krn: {'79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],
2138 [0.625,0.683,0,{krn: {'84': -0.0833, '89': -0.0833, '86': -0.111, '87': -0.111}}],
2139 [0.917,0.683], [0.75,0.683],
2140 [0.778,0.683,0,{krn: {'88': -0.0278, '87': -0.0278, '65': -0.0278, '86': -0.0278, '89': -0.0278}}],
2142 [0.681,0.683,0,{krn: {'65': -0.0833, '111': -0.0278, '101': -0.0278, '97': -0.0278, '46': -0.0833, '44': -0.0833}}],
2143 [0.778,0.683,0.194],
2144 [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}}],
2146 [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}}],
2148 [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}}],
2149 [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}}],
2150 [0.75,0.683,0,{krn: {'79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],
2151 [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}}],
2152 [0.611,0.683], [0.278,0.75,0.25], [0.5,0.694],
2153 [0.278,0.75,0.25], [0.5,0.694], [0.278,0.668],
2155 [0.278,0.694,0,{lig: {'96': 92}}],
2156 [0.5,0.431,0,{krn: {'118': -0.0278, '106': 0.0556, '121': -0.0278, '119': -0.0278}}],
2157 [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}}],
2158 [0.444,0.431,0,{krn: {'104': -0.0278, '107': -0.0278}}],
2159 [0.556,0.694], [0.444,0.431],
2160 [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}}],
2161 [0.5,0.431,0.194,{ic: 0.0139, krn: {'106': 0.0278}}],
2162 [0.556,0.694,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],
2163 [0.278,0.668], [0.306,0.668,0.194],
2164 [0.528,0.694,0,{krn: {'97': -0.0556, '101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],
2166 [0.833,0.431,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],
2167 [0.556,0.431,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],
2168 [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}}],
2170 [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}}],
2171 [0.528,0.431,0.194], [0.392,0.431], [0.394,0.431],
2172 [0.389,0.615,0,{krn: {'121': -0.0278, '119': -0.0278}}],
2173 [0.556,0.431,0,{krn: {'119': -0.0278}}],
2174 [0.528,0.431,0,{ic: 0.0139, krn: {'97': -0.0556, '101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],
2175 [0.722,0.431,0,{ic: 0.0139, krn: {'101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],
2177 [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}}],
2178 [0.444,0.431], [0.5,0.431,0,{ic: 0.0278, lig: {'45': 124}}],
2179 [1,0.431,0,{ic: 0.0278}], [0.5,0.694], [0.5,0.668], [0.5,0.668]
2183 [0.615,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],
2184 [0.833,0.683,0,{krn: {'127': 0.167}}],
2185 [0.763,0.683,0,{ic: 0.0278, krn: {'127': 0.0833}}],
2186 [0.694,0.683,0,{krn: {'127': 0.167}}],
2187 [0.742,0.683,0,{ic: 0.0757, krn: {'127': 0.0833}}],
2188 [0.831,0.683,0,{ic: 0.0812, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
2189 [0.78,0.683,0,{ic: 0.0576, krn: {'127': 0.0833}}],
2190 [0.583,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0556}}],
2191 [0.667,0.683,0,{krn: {'127': 0.0833}}],
2192 [0.612,0.683,0,{ic: 0.11, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
2193 [0.772,0.683,0,{ic: 0.0502, krn: {'127': 0.0833}}],
2194 [0.64,0.431,0,{ic: 0.0037, krn: {'127': 0.0278}}],
2195 [0.566,0.694,0.194,{ic: 0.0528, krn: {'127': 0.0833}}],
2196 [0.518,0.431,0.194,{ic: 0.0556}],
2197 [0.444,0.694,0,{ic: 0.0378, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0556}}],
2198 [0.406,0.431,0,{krn: {'127': 0.0556}}],
2200 [0.438,0.694,0.194,{ic: 0.0738, krn: {'127': 0.0833}}],
2201 [0.497,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0556}}],
2202 [0.469,0.694,0,{ic: 0.0278, krn: {'127': 0.0833}}],
2203 [0.354,0.431,0,{krn: {'127': 0.0556}}],
2204 [0.576,0.431], [0.583,0.694],
2205 [0.603,0.431,0.194,{krn: {'127': 0.0278}}],
2206 [0.494,0.431,0,{ic: 0.0637, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0278}}],
2207 [0.438,0.694,0.194,{ic: 0.046, krn: {'127': 0.111}}],
2208 [0.57,0.431,0,{ic: 0.0359}],
2209 [0.517,0.431,0.194,{krn: {'127': 0.0833}}],
2210 [0.571,0.431,0,{ic: 0.0359, krn: {'59': -0.0556, '58': -0.0556}}],
2211 [0.437,0.431,0,{ic: 0.113, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0278}}],
2212 [0.54,0.431,0,{ic: 0.0359, krn: {'127': 0.0278}}],
2213 [0.596,0.694,0.194,{krn: {'127': 0.0833}}],
2214 [0.626,0.431,0.194,{krn: {'127': 0.0556}}],
2216 [0.651,0.694,0.194,{ic: 0.0359, krn: {'127': 0.111}}],
2217 [0.622,0.431,0,{ic: 0.0359}],
2218 [0.466,0.431,0,{krn: {'127': 0.0833}}],
2219 [0.591,0.694,0,{krn: {'127': 0.0833}}],
2220 [0.828,0.431,0,{ic: 0.0278}],
2221 [0.517,0.431,0.194,{krn: {'127': 0.0833}}],
2222 [0.363,0.431,0.0972,{ic: 0.0799, krn: {'127': 0.0833}}],
2223 [0.654,0.431,0.194,{krn: {'127': 0.0833}}],
2224 [1,0.367,-0.133], [1,0.367,-0.133], [1,0.367,-0.133], [1,0.367,-0.133],
2225 [0.278,0.464,-0.0363], [0.278,0.464,-0.0363], [0.5,0.465,-0.0347], [0.5,0.465,-0.0347],
2227 [0.5,0.431], [0.5,0.431], [0.5,0.431], [0.5,0.431,0.194],
2228 [0.5,0.431,0.194], [0.5,0.431,0.194], [0.5,0.644], [0.5,0.431,0.194],
2229 [0.5,0.644], [0.5,0.431,0.194], [0.278,0.106], [0.278,0.106,0.194],
2230 [0.778,0.539,0.0391],
2231 [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}}],
2232 [0.778,0.539,0.0391], [0.5,0.465,-0.0347],
2234 [0.531,0.694,0,{ic: 0.0556, krn: {'127': 0.0833}}],
2235 [0.75,0.683,0,{krn: {'127': 0.139}}],
2236 [0.759,0.683,0,{ic: 0.0502, krn: {'127': 0.0833}}],
2237 [0.715,0.683,0,{ic: 0.0715, krn: {'61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
2238 [0.828,0.683,0,{ic: 0.0278, krn: {'127': 0.0556}}],
2239 [0.738,0.683,0,{ic: 0.0576, krn: {'127': 0.0833}}],
2240 [0.643,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],
2241 [0.786,0.683,0,{krn: {'127': 0.0833}}],
2242 [0.831,0.683,0,{ic: 0.0812, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
2243 [0.44,0.683,0,{ic: 0.0785, krn: {'127': 0.111}}],
2244 [0.555,0.683,0,{ic: 0.0962, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.167}}],
2245 [0.849,0.683,0,{ic: 0.0715, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
2246 [0.681,0.683,0,{krn: {'127': 0.0278}}],
2247 [0.97,0.683,0,{ic: 0.109, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
2248 [0.803,0.683,0,{ic: 0.109, krn: {'61': -0.0833, '61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
2249 [0.763,0.683,0,{ic: 0.0278, krn: {'127': 0.0833}}],
2251 [0.642,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],
2252 [0.791,0.683,0.194,{krn: {'127': 0.0833}}],
2253 [0.759,0.683,0,{ic: 0.00773, krn: {'127': 0.0833}}],
2254 [0.613,0.683,0,{ic: 0.0576, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
2255 [0.584,0.683,0,{ic: 0.139, krn: {'61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
2256 [0.683,0.683,0,{ic: 0.109, krn: {'59': -0.111, '58': -0.111, '61': -0.0556, '127': 0.0278}}],
2257 [0.583,0.683,0,{ic: 0.222, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],
2258 [0.944,0.683,0,{ic: 0.139, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],
2259 [0.828,0.683,0,{ic: 0.0785, krn: {'61': -0.0833, '61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
2260 [0.581,0.683,0,{ic: 0.222, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],
2261 [0.683,0.683,0,{ic: 0.0715, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
2262 [0.389,0.75], [0.389,0.694,0.194], [0.389,0.694,0.194],
2263 [1,0.358,-0.142], [1,0.358,-0.142],
2265 [0.417,0.694,0,{krn: {'127': 0.111}}],
2266 [0.529,0.431], [0.429,0.694], [0.433,0.431,0,{krn: {'127': 0.0556}}],
2267 [0.52,0.694,0,{krn: {'89': 0.0556, '90': -0.0556, '106': -0.111, '102': -0.167, '127': 0.167}}],
2268 [0.466,0.431,0,{krn: {'127': 0.0556}}],
2269 [0.49,0.694,0.194,{ic: 0.108, krn: {'59': -0.0556, '58': -0.0556, '127': 0.167}}],
2270 [0.477,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0278}}],
2271 [0.576,0.694,0,{krn: {'127': -0.0278}}], [0.345,0.66],
2272 [0.412,0.66,0.194,{ic: 0.0572, krn: {'59': -0.0556, '58': -0.0556}}],
2273 [0.521,0.694,0,{ic: 0.0315}], [0.298,0.694,0,{ic: 0.0197, krn: {'127': 0.0833}}],
2274 [0.878,0.431], [0.6,0.431], [0.485,0.431,0,{krn: {'127': 0.0556}}],
2276 [0.503,0.431,0.194,{krn: {'127': 0.0833}}],
2277 [0.446,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0833}}],
2278 [0.451,0.431,0,{ic: 0.0278, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0556}}],
2279 [0.469,0.431,0,{krn: {'127': 0.0556}}], [0.361,0.615,0,{krn: {'127': 0.0833}}],
2280 [0.572,0.431,0,{krn: {'127': 0.0278}}],
2281 [0.485,0.431,0,{ic: 0.0359, krn: {'127': 0.0278}}],
2282 [0.716,0.431,0,{ic: 0.0269, krn: {'127': 0.0833}}],
2283 [0.572,0.431,0,{krn: {'127': 0.0278}}],
2284 [0.49,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0556}}],
2285 [0.465,0.431,0,{ic: 0.044, krn: {'127': 0.0556}}],
2286 [0.322,0.431,0,{krn: {'127': 0.0278}}],
2287 [0.384,0.431,0.194,{krn: {'127': 0.0833}}],
2288 [0.636,0.431,0.194,{krn: {'127': 0.111}}],
2289 [0.5,0.714,0,{ic: 0.154}], [0.278,0.694,0,{ic: 0.399}]
2293 [0.778,0.583,0.0833], [0.278,0.444,-0.0556], [0.778,0.583,0.0833],
2294 [0.5,0.465,-0.0347], [0.778,0.583,0.0833], [0.5,0.444,-0.0556],
2295 [0.778,0.583,0.0833], [0.778,0.583,0.0833], [0.778,0.583,0.0833],
2296 [0.778,0.583,0.0833], [0.778,0.583,0.0833], [0.778,0.583,0.0833],
2297 [0.778,0.583,0.0833], [1,0.694,0.194], [0.5,0.444,-0.0556], [0.5,0.444,-0.0556],
2299 [0.778,0.464,-0.0363], [0.778,0.464,-0.0363], [0.778,0.636,0.136],
2300 [0.778,0.636,0.136], [0.778,0.636,0.136], [0.778,0.636,0.136],
2301 [0.778,0.636,0.136], [0.778,0.636,0.136], [0.778,0.367,-0.133],
2302 [0.778,0.483,-0.0169], [0.778,0.539,0.0391], [0.778,0.539,0.0391],
2303 [1,0.539,0.0391], [1,0.539,0.0391], [0.778,0.539,0.0391], [0.778,0.539,0.0391],
2305 [1,0.367,-0.133], [1,0.367,-0.133], [0.5,0.694,0.194], [0.5,0.694,0.194],
2306 [1,0.367,-0.133], [1,0.694,0.194], [1,0.694,0.194], [0.778,0.464,-0.0363],
2307 [1,0.367,-0.133], [1,0.367,-0.133], [0.611,0.694,0.194], [0.611,0.694,0.194],
2308 [1,0.367,-0.133], [1,0.694,0.194], [1,0.694,0.194], [0.778,0.431],
2310 [0.275,0.556], [1,0.431], [0.667,0.539,0.0391], [0.667,0.539,0.0391],
2311 [0.889,0.694,0.194], [0.889,0.694,0.194], [0,0.694,0.194], [0,0.367,-0.133],
2312 [0.556,0.694], [0.556,0.694], [0.667,0.431], [0.5,0.75,0.0556],
2313 [0.722,0.694], [0.722,0.694], [0.778,0.694], [0.778,0.694],
2315 [0.611,0.694], [0.798,0.683,0,{krn: {'48': 0.194}}],
2316 [0.657,0.683,0,{ic: 0.0304, krn: {'48': 0.139}}],
2317 [0.527,0.683,0,{ic: 0.0583, krn: {'48': 0.139}}],
2318 [0.771,0.683,0,{ic: 0.0278, krn: {'48': 0.0833}}],
2319 [0.528,0.683,0,{ic: 0.0894, krn: {'48': 0.111}}],
2320 [0.719,0.683,0,{ic: 0.0993, krn: {'48': 0.111}}],
2321 [0.595,0.683,0.0972,{ic: 0.0593, krn: {'48': 0.111}}],
2322 [0.845,0.683,0,{ic: 0.00965, krn: {'48': 0.111}}],
2323 [0.545,0.683,0,{ic: 0.0738, krn: {'48': 0.0278}}],
2324 [0.678,0.683,0.0972,{ic: 0.185, krn: {'48': 0.167}}],
2325 [0.762,0.683,0,{ic: 0.0144, krn: {'48': 0.0556}}],
2326 [0.69,0.683,0,{krn: {'48': 0.139}}], [1.2,0.683,0,{krn: {'48': 0.139}}],
2327 [0.82,0.683,0,{ic: 0.147, krn: {'48': 0.0833}}],
2328 [0.796,0.683,0,{ic: 0.0278, krn: {'48': 0.111}}],
2330 [0.696,0.683,0,{ic: 0.0822, krn: {'48': 0.0833}}],
2331 [0.817,0.683,0.0972,{krn: {'48': 0.111}}],
2332 [0.848,0.683,0,{krn: {'48': 0.0833}}],
2333 [0.606,0.683,0,{ic: 0.075, krn: {'48': 0.139}}],
2334 [0.545,0.683,0,{ic: 0.254, krn: {'48': 0.0278}}],
2335 [0.626,0.683,0,{ic: 0.0993, krn: {'48': 0.0833}}],
2336 [0.613,0.683,0,{ic: 0.0822, krn: {'48': 0.0278}}],
2337 [0.988,0.683,0,{ic: 0.0822, krn: {'48': 0.0833}}],
2338 [0.713,0.683,0,{ic: 0.146, krn: {'48': 0.139}}],
2339 [0.668,0.683,0.0972,{ic: 0.0822, krn: {'48': 0.0833}}],
2340 [0.725,0.683,0,{ic: 0.0794, krn: {'48': 0.139}}],
2341 [0.667,0.556], [0.667,0.556], [0.667,0.556], [0.667,0.556], [0.667,0.556],
2343 [0.611,0.694], [0.611,0.694], [0.444,0.75,0.25], [0.444,0.75,0.25],
2344 [0.444,0.75,0.25], [0.444,0.75,0.25], [0.5,0.75,0.25], [0.5,0.75,0.25],
2345 [0.389,0.75,0.25], [0.389,0.75,0.25], [0.278,0.75,0.25], [0.5,0.75,0.25],
2346 [0.5,0.75,0.25], [0.611,0.75,0.25], [0.5,0.75,0.25], [0.278,0.694,0.194],
2348 [0.833,0.04,0.96], [0.75,0.683], [0.833,0.683], [0.417,0.694,0.194,{ic: 0.111}],
2349 [0.667,0.556], [0.667,0.556], [0.778,0.636,0.136], [0.778,0.636,0.136],
2350 [0.444,0.694,0.194], [0.444,0.694,0.194], [0.444,0.694,0.194],
2351 [0.611,0.694,0.194], [0.778,0.694,0.13], [0.778,0.694,0.13],
2352 [0.778,0.694,0.13], [0.778,0.694,0.13]
2356 [0.458,0.04,1.16,{n: 16}], [0.458,0.04,1.16,{n: 17}],
2357 [0.417,0.04,1.16,{n: 104}], [0.417,0.04,1.16,{n: 105}],
2358 [0.472,0.04,1.16,{n: 106}], [0.472,0.04,1.16,{n: 107}],
2359 [0.472,0.04,1.16,{n: 108}], [0.472,0.04,1.16,{n: 109}],
2360 [0.583,0.04,1.16,{n: 110}], [0.583,0.04,1.16,{n: 111}],
2361 [0.472,0.04,1.16,{n: 68}], [0.472,0.04,1.16,{n: 69}],
2362 [0.333,0,0.6,{delim: {rep: 12}}], [0.556,0,0.6,{delim: {rep: 13}}],
2363 [0.578,0.04,1.16,{n: 46}], [0.578,0.04,1.16,{n: 47}],
2365 [0.597,0.04,1.76,{n: 18}], [0.597,0.04,1.76,{n: 19}],
2366 [0.736,0.04,2.36,{n: 32}], [0.736,0.04,2.36,{n: 33}],
2367 [0.528,0.04,2.36,{n: 34}], [0.528,0.04,2.36,{n: 35}],
2368 [0.583,0.04,2.36,{n: 36}], [0.583,0.04,2.36,{n: 37}],
2369 [0.583,0.04,2.36,{n: 38}], [0.583,0.04,2.36,{n: 39}],
2370 [0.75,0.04,2.36,{n: 40}], [0.75,0.04,2.36,{n: 41}],
2371 [0.75,0.04,2.36,{n: 42}], [0.75,0.04,2.36,{n: 43}],
2372 [1.04,0.04,2.36,{n: 44}], [1.04,0.04,2.36,{n: 45}],
2374 [0.792,0.04,2.96,{n: 48}], [0.792,0.04,2.96,{n: 49}],
2375 [0.583,0.04,2.96,{n: 50}], [0.583,0.04,2.96,{n: 51}],
2376 [0.639,0.04,2.96,{n: 52}], [0.639,0.04,2.96,{n: 53}],
2377 [0.639,0.04,2.96,{n: 54}], [0.639,0.04,2.96,{n: 55}],
2378 [0.806,0.04,2.96,{n: 56}], [0.806,0.04,2.96,{n: 57}],
2379 [0.806,0.04,2.96], [0.806,0.04,2.96],
2380 [1.28,0.04,2.96], [1.28,0.04,2.96],
2381 [0.811,0.04,1.76,{n: 30}], [0.811,0.04,1.76,{n: 31}],
2383 [0.875,0.04,1.76,{delim: {top: 48, bot: 64, rep: 66}}],
2384 [0.875,0.04,1.76,{delim: {top: 49, bot: 65, rep: 67}}],
2385 [0.667,0.04,1.76,{delim: {top: 50, bot: 52, rep: 54}}],
2386 [0.667,0.04,1.76,{delim: {top: 51, bot: 53, rep: 55}}],
2387 [0.667,0.04,1.76,{delim: {bot: 52, rep: 54}}],
2388 [0.667,0.04,1.76,{delim: {bot: 53, rep: 55}}],
2389 [0.667,0,0.6,{delim: {top: 50, rep: 54}}],
2390 [0.667,0,0.6,{delim: {top: 51, rep: 55}}],
2391 [0.889,0,0.9,{delim: {top: 56, mid: 60, bot: 58, rep: 62}}],
2392 [0.889,0,0.9,{delim: {top: 57, mid: 61, bot: 59, rep: 62}}],
2393 [0.889,0,0.9,{delim: {top: 56, bot: 58, rep: 62}}],
2394 [0.889,0,0.9,{delim: {top: 57, bot: 59, rep: 62}}],
2395 [0.889,0,1.8,{delim: {rep: 63}}],
2396 [0.889,0,1.8,{delim: {rep: 119}}],
2397 [0.889,0,0.3,{delim: {rep: 62}}],
2398 [0.667,0,0.6,{delim: {top: 120, bot: 121, rep: 63}}],
2400 [0.875,0.04,1.76,{delim: {top: 56, bot: 59, rep: 62}}],
2401 [0.875,0.04,1.76,{delim: {top: 57, bot: 58, rep: 62}}],
2402 [0.875,0,0.6,{delim: {rep: 66}}], [0.875,0,0.6,{delim: {rep: 67}}],
2403 [0.611,0.04,1.76,{n: 28}], [0.611,0.04,1.76,{n: 29}],
2404 [0.833,0,1,{n: 71}], [1.11,0.1,1.5], [0.472,0,1.11,{ic: 0.194, n: 73}],
2405 [0.556,0,2.22,{ic: 0.444}], [1.11,0,1,{n: 75}], [1.51,0.1,1.5],
2406 [1.11,0,1,{n: 77}], [1.51,0.1,1.5], [1.11,0,1,{n: 79}], [1.51,0.1,1.5],
2408 [1.06,0,1,{n: 88}], [0.944,0,1,{n: 89}], [0.472,0,1.11,{ic: 0.194, n: 90}],
2409 [0.833,0,1,{n: 91}], [0.833,0,1,{n: 92}], [0.833,0,1,{n: 93}],
2410 [0.833,0,1,{n: 94}], [0.833,0,1,{n: 95}], [1.44,0.1,1.5],
2411 [1.28,0.1,1.5], [0.556,0,2.22,{ic: 0.444}], [1.11,0.1,1.5],
2412 [1.11,0.1,1.5], [1.11,0.1,1.5], [1.11,0.1,1.5], [1.11,0.1,1.5],
2414 [0.944,0,1,{n: 97}], [1.28,0.1,1.5], [0.556,0.722,0,{n: 99}],
2415 [1,0.75,0,{n: 100}], [1.44,0.75], [0.556,0.722,0,{n: 102}],
2416 [1,0.75,0,{n: 103}], [1.44,0.75], [0.472,0.04,1.76,{n: 20}],
2417 [0.472,0.04,1.76,{n: 21}], [0.528,0.04,1.76,{n: 22}],
2418 [0.528,0.04,1.76,{n: 23}], [0.528,0.04,1.76,{n: 24}],
2419 [0.528,0.04,1.76,{n: 25}], [0.667,0.04,1.76,{n: 26}],
2420 [0.667,0.04,1.76,{n: 27}],
2422 [1,0.04,1.16,{n: 113}], [1,0.04,1.76,{n: 114}], [1,0.04,2.36,{n: 115}],
2423 [1,0.04,2.96,{n: 116}], [1.06,0,1.8,{delim: {top: 118, bot: 116, rep: 117}}],
2424 [1.06,0,0.6], [1.06,0.04,0.56],
2425 [0.778,0,0.6,{delim: {top: 126, bot: 127, rep: 119}}],
2426 [0.667,0,0.6,{delim: {top: 120, rep: 63}}],
2427 [0.667,0,0.6,{delim: {bot: 121, rep: 63}}],
2428 [0.45,0.12], [0.45,0.12], [0.45,0.12], [0.45,0.12],
2429 [0.778,0,0.6,{delim: {top: 126, rep: 119}}],
2430 [0.778,0,0.6,{delim: {bot: 127, rep: 119}}]
2434 [0.627,0.683,0,{ic: 0.133}], [0.818,0.683], [0.767,0.683,0,{ic: 0.094}],
2435 [0.692,0.683], [0.664,0.683,0,{ic: 0.153}], [0.743,0.683,0,{ic: 0.164}],
2436 [0.716,0.683,0,{ic: 0.12}], [0.767,0.683,0,{ic: 0.111}],
2437 [0.716,0.683,0,{ic: 0.0599}], [0.767,0.683,0,{ic: 0.111}],
2438 [0.716,0.683,0,{ic: 0.103}],
2439 [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}}],
2440 [0.562,0.694,0.194,{ic: 0.103}], [0.588,0.694,0.194,{ic: 0.103}],
2441 [0.882,0.694,0.194,{ic: 0.103}], [0.894,0.694,0.194,{ic: 0.103}],
2443 [0.307,0.431,0,{ic: 0.0767}], [0.332,0.431,0.194,{ic: 0.0374}],
2444 [0.511,0.694], [0.511,0.694,0,{ic: 0.0969}], [0.511,0.628,0,{ic: 0.083}],
2445 [0.511,0.694,0,{ic: 0.108}], [0.511,0.562,0,{ic: 0.103}], [0.831,0.694],
2446 [0.46,0,0.17], [0.537,0.694,0.194,{ic: 0.105}], [0.716,0.431,0,{ic: 0.0751}],
2447 [0.716,0.431,0,{ic: 0.0751}], [0.511,0.528,0.0972,{ic: 0.0919}],
2448 [0.883,0.683,0,{ic: 0.12}], [0.985,0.683,0,{ic: 0.12}],
2449 [0.767,0.732,0.0486,{ic: 0.094}],
2451 [0.256,0.431,0,{krn: {'108': -0.256, '76': -0.321}}],
2452 [0.307,0.694,0,{ic: 0.124, lig: {'96': 60}}],
2453 [0.514,0.694,0,{ic: 0.0696}], [0.818,0.694,0.194,{ic: 0.0662}],
2454 [0.769,0.694], [0.818,0.75,0.0556,{ic: 0.136}],
2455 [0.767,0.694,0,{ic: 0.0969}],
2456 [0.307,0.694,0,{ic: 0.124, krn: {'63': 0.102, '33': 0.102}, lig: {'39': 34}}],
2457 [0.409,0.75,0.25,{ic: 0.162}], [0.409,0.75,0.25,{ic: 0.0369}],
2458 [0.511,0.75,0,{ic: 0.149}], [0.767,0.562,0.0567,{ic: 0.0369}],
2459 [0.307,0.106,0.194], [0.358,0.431,0,{ic: 0.0283, lig: {'45': 123}}],
2460 [0.307,0.106], [0.511,0.75,0.25,{ic: 0.162}],
2462 [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
2463 [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
2464 [0.511,0.644,0.194,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
2465 [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0.194,{ic: 0.136}],
2466 [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
2467 [0.307,0.431,0,{ic: 0.0582}], [0.307,0.431,0.194,{ic: 0.0582}],
2468 [0.307,0.5,0.194,{ic: 0.0756}], [0.767,0.367,-0.133,{ic: 0.0662}],
2469 [0.511,0.5,0.194], [0.511,0.694,0,{ic: 0.122, lig: {'96': 62}}],
2471 [0.767,0.694,0,{ic: 0.096}],
2472 [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}}],
2473 [0.704,0.683,0,{ic: 0.103}], [0.716,0.683,0,{ic: 0.145}],
2474 [0.755,0.683,0,{ic: 0.094, krn: {'88': -0.0256, '87': -0.0256, '65': -0.0256, '86': -0.0256, '89': -0.0256}}],
2475 [0.678,0.683,0,{ic: 0.12}],
2476 [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}}],
2477 [0.774,0.683,0,{ic: 0.0872}], [0.743,0.683,0,{ic: 0.164}],
2478 [0.386,0.683,0,{ic: 0.158}], [0.525,0.683,0,{ic: 0.14}],
2479 [0.769,0.683,0,{ic: 0.145, krn: {'79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],
2480 [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}}],
2481 [0.897,0.683,0,{ic: 0.164}], [0.743,0.683,0,{ic: 0.164}],
2482 [0.767,0.683,0,{ic: 0.094, krn: {'88': -0.0256, '87': -0.0256, '65': -0.0256, '86': -0.0256, '89': -0.0256}}],
2484 [0.678,0.683,0,{ic: 0.103, krn: {'65': -0.0767}}],
2485 [0.767,0.683,0.194,{ic: 0.094}],
2486 [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}}],
2487 [0.562,0.683,0,{ic: 0.12}],
2488 [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}}],
2489 [0.743,0.683,0,{ic: 0.164}],
2490 [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}}],
2491 [0.999,0.683,0,{ic: 0.184, krn: {'65': -0.0767}}],
2492 [0.743,0.683,0,{ic: 0.158, krn: {'79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],
2493 [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}}],
2494 [0.613,0.683,0,{ic: 0.145}], [0.307,0.75,0.25,{ic: 0.188}],
2495 [0.514,0.694,0,{ic: 0.169}], [0.307,0.75,0.25,{ic: 0.105}],
2496 [0.511,0.694,0,{ic: 0.0665}], [0.307,0.668,0,{ic: 0.118}],
2498 [0.307,0.694,0,{ic: 0.124, lig: {'96': 92}}], [0.511,0.431,0,{ic: 0.0767}],
2499 [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}}],
2500 [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}}],
2501 [0.511,0.694,0,{ic: 0.103, krn: {'108': 0.0511}}],
2502 [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}}],
2503 [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}}],
2504 [0.46,0.431,0.194,{ic: 0.0885}], [0.511,0.694,0,{ic: 0.0767}],
2505 [0.307,0.655,0,{ic: 0.102}], [0.307,0.655,0.194,{ic: 0.145}],
2506 [0.46,0.694,0,{ic: 0.108}], [0.256,0.694,0,{ic: 0.103, krn: {'108': 0.0511}}],
2507 [0.818,0.431,0,{ic: 0.0767}], [0.562,0.431,0,{ic: 0.0767, krn: {'39': -0.102}}],
2508 [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}}],
2510 [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}}],
2511 [0.46,0.431,0.194,{ic: 0.0885}],
2512 [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}}],
2513 [0.409,0.431,0,{ic: 0.0821}], [0.332,0.615,0,{ic: 0.0949}],
2514 [0.537,0.431,0,{ic: 0.0767}], [0.46,0.431,0,{ic: 0.108}],
2515 [0.664,0.431,0,{ic: 0.108, krn: {'108': 0.0511}}],
2516 [0.464,0.431,0,{ic: 0.12}], [0.486,0.431,0.194,{ic: 0.0885}],
2517 [0.409,0.431,0,{ic: 0.123}], [0.511,0.431,0,{ic: 0.0921, lig: {'45': 124}}],
2518 [1.02,0.431,0,{ic: 0.0921}], [0.511,0.694,0,{ic: 0.122}],
2519 [0.511,0.668,0,{ic: 0.116}], [0.511,0.668,0,{ic: 0.105}]
2523 [0.692,0.686], [0.958,0.686], [0.894,0.686], [0.806,0.686],
2524 [0.767,0.686], [0.9,0.686], [0.831,0.686], [0.894,0.686],
2525 [0.831,0.686], [0.894,0.686], [0.831,0.686],
2526 [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}}],
2527 [0.639,0.694], [0.639,0.694], [0.958,0.694], [0.958,0.694],
2529 [0.319,0.444], [0.351,0.444,0.194], [0.575,0.694], [0.575,0.694],
2530 [0.575,0.632], [0.575,0.694], [0.575,0.596], [0.869,0.694],
2531 [0.511,0,0.17], [0.597,0.694], [0.831,0.444], [0.894,0.444],
2532 [0.575,0.542,0.0972], [1.04,0.686], [1.17,0.686], [0.894,0.735,0.0486],
2534 [0.319,0.444,0,{krn: {'108': -0.319, '76': -0.378}}],
2535 [0.35,0.694,0,{lig: {'96': 60}}], [0.603,0.694], [0.958,0.694,0.194],
2536 [0.575,0.75,0.0556], [0.958,0.75,0.0556], [0.894,0.694],
2537 [0.319,0.694,0,{krn: {'63': 0.128, '33': 0.128}, lig: {'39': 34}}],
2538 [0.447,0.75,0.25], [0.447,0.75,0.25], [0.575,0.75], [0.894,0.633,0.133],
2539 [0.319,0.156,0.194], [0.383,0.444,0,{lig: {'45': 123}}],
2540 [0.319,0.156], [0.575,0.75,0.25],
2542 [0.575,0.644], [0.575,0.644], [0.575,0.644], [0.575,0.644],
2543 [0.575,0.644], [0.575,0.644], [0.575,0.644], [0.575,0.644],
2544 [0.575,0.644], [0.575,0.644], [0.319,0.444], [0.319,0.444,0.194],
2545 [0.35,0.5,0.194], [0.894,0.391,-0.109], [0.543,0.5,0.194],
2546 [0.543,0.694,0,{lig: {'96': 62}}],
2549 [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}}],
2550 [0.818,0.686], [0.831,0.686],
2551 [0.882,0.686,0,{krn: {'88': -0.0319, '87': -0.0319, '65': -0.0319, '86': -0.0319, '89': -0.0319}}],
2553 [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}}],
2554 [0.904,0.686], [0.9,0.686], [0.436,0.686,0,{krn: {'73': 0.0319}}],
2556 [0.901,0.686,0,{krn: {'79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],
2557 [0.692,0.686,0,{krn: {'84': -0.0958, '89': -0.0958, '86': -0.128, '87': -0.128}}],
2558 [1.09,0.686], [0.9,0.686],
2559 [0.864,0.686,0,{krn: {'88': -0.0319, '87': -0.0319, '65': -0.0319, '86': -0.0319, '89': -0.0319}}],
2561 [0.786,0.686,0,{krn: {'65': -0.0958, '111': -0.0319, '101': -0.0319, '97': -0.0319, '46': -0.0958, '44': -0.0958}}],
2562 [0.864,0.686,0.194],
2563 [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}}],
2565 [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}}],
2567 [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}}],
2568 [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}}],
2569 [0.869,0.686,0,{krn: {'79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],
2570 [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}}],
2571 [0.703,0.686], [0.319,0.75,0.25], [0.603,0.694], [0.319,0.75,0.25],
2572 [0.575,0.694], [0.319,0.694],
2574 [0.319,0.694,0,{lig: {'96': 92}}],
2575 [0.559,0.444,0,{krn: {'118': -0.0319, '106': 0.0639, '121': -0.0319, '119': -0.0319}}],
2576 [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}}],
2577 [0.511,0.444,0,{krn: {'104': -0.0319, '107': -0.0319}}],
2578 [0.639,0.694], [0.527,0.444],
2579 [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}}],
2580 [0.575,0.444,0.194,{ic: 0.016, krn: {'106': 0.0319}}],
2581 [0.639,0.694,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],
2582 [0.319,0.694], [0.351,0.694,0.194],
2583 [0.607,0.694,0,{krn: {'97': -0.0639, '101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],
2585 [0.958,0.444,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],
2586 [0.639,0.444,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],
2587 [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}}],
2589 [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}}],
2590 [0.607,0.444,0.194], [0.474,0.444], [0.454,0.444],
2591 [0.447,0.635,0,{krn: {'121': -0.0319, '119': -0.0319}}],
2592 [0.639,0.444,0,{krn: {'119': -0.0319}}],
2593 [0.607,0.444,0,{ic: 0.016, krn: {'97': -0.0639, '101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],
2594 [0.831,0.444,0,{ic: 0.016, krn: {'101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],
2596 [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}}],
2597 [0.511,0.444], [0.575,0.444,0,{ic: 0.0319, lig: {'45': 124}}],
2598 [1.15,0.444,0,{ic: 0.0319}], [0.575,0.694], [0.575,0.694], [0.575,0.694]
2602 /***************************************************************************/
2605 * Implement image-based fonts for fallback method
2609 // font sizes available
2610 fonts: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249, 298, 358, 430],
2612 // em widths for the various font size directories
2613 w: {'50': 6.9, '60': 8.3, '70': 9.7, '85': 11.8, '100': 13.9,
2614 '120': 16.7, '144': 20.0, '173': 24.0, '207': 28.8, '249': 34.6,
2615 '298': 41.4, '358': 49.8, '430': 59.8},
2617 best: 4, // index of best font size in the fonts list
2618 update: {}, // fonts to update (see UpdateFonts below)
2619 factor: 1, // factor by which to shrink images (for better printing)
2620 loaded: 0, // image fonts are loaded
2622 // add characters to be drawn using images
2623 SetFont: function (change) {
2624 for (var font in change) {
2625 if (!this.update[font]) {this.update[font] = []}
2626 this.update[font] = this.update[font].concat(change[font]);
2631 * Called by the exta-font definition files to add an image font
2634 AddFont: function (size,def) {
2635 if (!jsMath.Img[size]) {jsMath.Img[size] = {}};
2636 jsMath.Add(jsMath.Img[size],def);
2640 * Update font(s) to use image data rather than native fonts
2641 * It looks in the jsMath.Img.update array to find the names
2642 * of the fonts to udpate, and the arrays of character codes
2643 * to set (or 'all' to change every character);
2645 UpdateFonts: function () {
2646 var change = this.update; if (!this.loaded) return;
2647 for (var font in change) {
2648 for (var i = 0; i < change[font].length; i++) {
2649 var c = change[font][i];
2650 if (c == 'all') {for (c in jsMath.TeX[font]) {jsMath.TeX[font][c].img = {}}}
2651 else {jsMath.TeX[font][c].img = {}}
2658 * Find the font size that best fits our current font
2659 * (this is the directory name for the img files used
2660 * in some fallback modes).
2662 BestSize: function () {
2663 var w = jsMath.em * this.factor;
2664 var m = this.w[this.fonts[0]];
2665 for (var i = 1; i < this.fonts.length; i++) {
2666 if (w < (this.w[this.fonts[i]] + 2*m) / 3) {return i-1}
2667 m = this.w[this.fonts[i]];
2673 * Get the scaling factor for the image fonts
2675 Scale: function () {
2676 if (!this.loaded) return;
2677 this.best = this.BestSize();
2678 this.em = jsMath.Img.w[this.fonts[this.best]];
2679 this.scale = (jsMath.em/this.em);
2680 if (Math.abs(this.scale - 1) < .12) {this.scale = 1}
2684 * Get URL to directory for given font and size, based on the
2685 * user's alpha/plain setting
2687 URL: function (name,size,C) {
2688 var type = (jsMath.Controls.cookie.alpha) ? '/alpha/': '/plain/';
2689 if (C == null) {C = "def.js"} else {C = 'char'+C+'.png'}
2690 if (size != "") {size += '/'}
2691 return this.root+name+type+size+C;
2695 * Laod the data for an image font
2697 LoadFont: function (name) {
2698 if (!this.loaded) this.Init();
2699 jsMath.Setup.Script(this.URL(name,""));
2703 * Setup for print mode, and create the hex code table
2706 if (jsMath.Controls.cookie.print || jsMath.Controls.cookie.stayhires) {
2707 jsMath.Controls.cookie.print = jsMath.Controls.cookie.stayhires;
2709 if (!jsMath.Controls.isLocalCookie || !jsMath.Global.isLocal) {jsMath.Controls.SetCookie(0)}
2710 if (jsMath.Browser.alphaPrintBug) {jsMath.Controls.cookie.alpha = 0}
2712 var codes = '0123456789ABCDEF';
2714 for (var i = 0; i < 128; i++) {
2715 var h = Math.floor(i/16); var l = i - 16*h;
2716 this.HexCode[i] = codes.charAt(h)+codes.charAt(l);
2723 /***************************************************************************/
2726 * jsMath.HTML handles creation of most of the HTML needed for
2727 * presenting mathematics in HTML pages.
2733 * Produce a string version of a measurement in ems,
2734 * showing only a limited number of digits, and
2735 * using 0 when the value is near zero.
2738 if (Math.abs(m) < .000001) {m = 0}
2739 var s = String(m); s = s.replace(/(\.\d\d\d).+/,'$1');
2744 * Create a horizontal space of width w
2746 Spacer: function (w) {
2747 if (w == 0) {return ''};
2748 return jsMath.Browser.msieSpaceFix+'<span class="spacer" style="margin-left:'+this.Em(w)+'"></span>';
2752 * Create a blank rectangle of the given size
2753 * If the height is small, it is converted to pixels so that it
2754 * will not disappear at small font sizes.
2757 Blank: function (w,h,d,isRule) {
2758 var backspace = ''; var style = ''
2760 style += 'border-left:'+this.Em(w)+' solid;';
2761 if (jsMath.Browser.widthAddsBorder) {w = 0};
2764 if (jsMath.Browser.blankWidthBug) {
2765 if (jsMath.Browser.quirks) {
2766 style += 'width:1px;';
2767 backspace = '<span class="spacer" style="margin-right:-1px"></span>'
2768 } else if (!isRule) {
2769 style += 'width:1px;margin-right:-1px;';
2772 } else {style += 'width:'+this.Em(w)+';'}
2773 if (d == null) {d = 0}
2775 var H = this.Em(h+d);
2776 if (isRule && h*jsMath.em <= 1.5) {H = "1.5px"; h = 1.5/jsMath.em}
2777 style += 'height:'+H+';';
2779 if (jsMath.Browser.mozInlineBlockBug) {d = -h}
2780 if (jsMath.Browser.msieBlockDepthBug && !isRule) {d -= jsMath.d}
2781 if (d) {style += 'vertical-align:'+this.Em(-d)}
2782 return backspace+'<span class="blank" style="'+style+'"></span>';
2786 * Create a rule line for fractions, etc.
2788 Rule: function (w,h) {
2789 if (h == null) {h = jsMath.TeX.default_rule_thickness}
2790 return this.Blank(w,h,0,1);
2794 * Create a strut for measuring position of baseline
2796 Strut: function (h) {return this.Blank(1,h,0,1)},
2797 msieStrut: function (h) {
2798 return '<img style="width:1px; height:'+this.Em(h)+'"/>'
2802 * Add a <SPAN> tag to activate a specific CSS class
2804 Class: function (tclass,html) {
2805 return '<span class="'+tclass+'">'+html+'</span>';
2809 * Use a <SPAN> to place some HTML at a specific position.
2810 * (This can be replaced by the ones below to overcome
2811 * some browser-specific bugs.)
2813 Place: function (html,x,y) {
2814 if (Math.abs(x) < .0001) {x = 0}
2815 if (Math.abs(y) < .0001) {y = 0}
2817 var span = '<span style="position: relative;';
2818 if (x) {span += ' margin-left:'+this.Em(x)+';'}
2819 if (y) {span += ' top:'+this.Em(-y)+';'}
2820 html = span + '">' + html + '</span>';
2826 * For MSIE on Windows, backspacing must be done in a separate
2827 * <SPAN>, otherwise the contents will be clipped. Netscape
2828 * also doesn't combine vertical and horizontal spacing well.
2829 * Here the x and y positioning are done in separate <SPAN> tags
2831 PlaceSeparateSkips: function (html,x,y,mw,Mw,w) {
2832 if (Math.abs(x) < .0001) {x = 0}
2833 if (Math.abs(y) < .0001) {y = 0}
2835 var lw = 0; var rw = 0; var width = "";
2837 rw = Mw - w; lw = mw;
2838 width = ' width:'+this.Em(Mw-mw)+';';
2841 this.Spacer(lw-rw) +
2842 '<span style="position: relative; '
2843 + 'top:'+this.Em(-y)+';'
2844 + 'left:'+this.Em(rw)+';'
2851 if (x) {html = this.Spacer(x) + html}
2856 * Place a SPAN with absolute coordinates
2858 PlaceAbsolute: function (html,x,y,mw,Mw,w) {
2859 if (Math.abs(x) < .0001) {x = 0}
2860 if (Math.abs(y) < .0001) {y = 0}
2861 var leftSpace = ""; var rightSpace = ""; var width = "";
2862 if (jsMath.Browser.msieRelativeClipBug && mw != null) {
2863 leftSpace = this.Spacer(-mw); x += mw;
2864 rightSpace = this.Spacer(Mw-w);
2866 if (jsMath.Browser.operaAbsoluteWidthBug) {width = " width: "+this.Em(w+2)}
2868 '<span style="position:absolute; left:'+this.Em(x)+'; '
2869 + 'top:'+this.Em(y)+';'+width+'">' +
2870 leftSpace + html + rightSpace +
2871 ' ' + // space normalizes line height in script styles
2876 Absolute: function(html,w,h,d,y) {
2878 if (Math.abs(y) < .0001) {y = 0}
2879 html = '<span style="position:absolute; '
2880 + 'top:'+jsMath.HTML.Em(y)+'; left:0em;">'
2881 + html + ' ' // space normalizes line height in script styles
2884 if (d == "none") {d = 0}
2885 html += this.Blank((jsMath.Browser.lineBreakBug ? 0 : w),h-d,d);
2886 if (jsMath.Browser.msieAbsoluteBug) { // for MSIE (Mac)
2887 html = '<span style="position:relative;">' + html + '</span>';
2889 html = '<span style="position:relative;'
2890 + jsMath.Browser.msieInlineBlockFix
2891 + '">' + html + '</span>';
2892 if (jsMath.Browser.lineBreakBug)
2893 {html = '<span style="display:inline-block; width:'+jsMath.HTML.Em(w)+'">'+html+'</span>'}
2900 /***************************************************************************/
2903 * jsMath.Box handles TeX's math boxes and jsMath's equivalent of hboxes.
2906 jsMath.Box = function (format,text,w,h,d) {
2907 if (d == null) {d = jsMath.d}
2908 this.type = 'typeset';
2909 this.w = w; this.h = h; this.d = d; this.bh = h; this.bd = d;
2910 this.x = 0; this.y = 0; this.mw = 0; this.Mw = w;
2911 this.html = text; this.format = format;
2915 jsMath.Add(jsMath.Box,{
2917 defaultH: 0, // default height for characters with none specified
2922 Null: function () {return new jsMath.Box('null','',0,0,0)},
2925 * A box containing only text whose class and style haven't been added
2926 * yet (so that we can combine ones with the same styles). It gets
2927 * the text dimensions, if needed. (In general, this has been
2928 * replaced by TeX() below, but is still used in fallback mode.)
2930 Text: function (text,tclass,style,size,a,d) {
2931 var html = jsMath.Typeset.AddClass(tclass,text);
2932 html = jsMath.Typeset.AddStyle(style,size,html);
2933 var BB = jsMath.EmBoxFor(html); var TeX = jsMath.Typeset.TeX(style,size);
2934 var bd = ((tclass == 'cmsy10' || tclass == 'cmex10')? BB.h-TeX.h: TeX.d*BB.h/TeX.hd);
2935 var box = new jsMath.Box('text',text,BB.w,BB.h-bd,bd);
2936 box.style = style; box.size = size; box.tclass = tclass;
2937 if (d != null) {box.d = d*TeX.scale} else {box.d = 0}
2938 if (a == null || a == 1) {box.h = .9*TeX.M_height}
2939 else {box.h = 1.1*TeX.x_height + TeX.scale*a}
2944 * Produce a box containing a given TeX character from a given font.
2945 * The box is a text box (like the ones above), so that characters from
2946 * the same font can be combined.
2948 TeX: function (C,font,style,size) {
2949 var c = jsMath.TeX[font][C];
2950 if (c.d == null) {c.d = 0}; if (c.h == null) {c.h = 0}
2951 if (c.img != null && c.c != '') this.TeXIMG(font,C,jsMath.Typeset.StyleSize(style,size));
2952 var scale = jsMath.Typeset.TeX(style,size).scale;
2953 var box = new jsMath.Box('text',c.c,c.w*scale,c.h*scale,c.d*scale);
2954 box.style = style; box.size = size;
2956 box.tclass = c.tclass;
2957 if (c.img) {box.bh = c.img.bh; box.bd = c.img.bd}
2958 else {box.bh = scale*jsMath.h; box.bd = scale*jsMath.d}
2961 box.bh = scale*jsMath.TeX[font].h;
2962 box.bd = scale*jsMath.TeX[font].d;
2963 if (jsMath.Browser.msieFontBug && box.html.match(/&#/)) {
2964 // hack to avoid font changing back to the default
2965 // font when a unicode reference is not followed
2966 // by a letter or number
2967 box.html += '<span style="display:none">x</span>';
2974 * In fallback modes, handle the fact that we don't have the
2975 * sizes of the characters precomputed
2977 TeXfallback: function (C,font,style,size) {
2978 var c = jsMath.TeX[font][C]; if (!c.tclass) {c.tclass = font}
2979 if (c.img != null) {return this.TeXnonfallback(C,font,style,size)}
2980 if (c.h != null && c.a == null) {c.a = c.h-1.1*jsMath.TeX.x_height}
2981 var a = c.a; var d = c.d; // avoid Firefox warnings
2982 var box = this.Text(c.c,c.tclass,style,size,a,d);
2983 var scale = jsMath.Typeset.TeX(style,size).scale;
2985 box.bh = c.bh*scale;
2986 box.bd = c.bd*scale;
2988 var h = box.bd+box.bh;
2989 var html = jsMath.Typeset.AddClass(box.tclass,box.html);
2990 html = jsMath.Typeset.AddStyle(style,size,html);
2991 box.bd = jsMath.EmBoxFor(html + jsMath.HTML.Strut(h)).h - h;
2992 box.bh = h - box.bd;
2993 if (scale == 1) {c.bh = box.bh; c.bd = box.bd}
2995 if (jsMath.msieFontBug && box.html.match(/&#/))
2996 {box.html += '<span style="display:none">x</span>'}
3001 * Set the character's string to the appropriate image file
3003 TeXIMG: function (font,C,size) {
3004 var c = jsMath.TeX[font][C];
3005 if (c.img.size != null && c.img.size == size &&
3006 c.img.best != null && c.img.best == jsMath.Img.best) return;
3007 var mustScale = (jsMath.Img.scale != 1);
3008 var id = jsMath.Img.best + size - 4;
3009 if (id < 0) {id = 0; mustScale = 1} else
3010 if (id >= jsMath.Img.fonts.length) {id = jsMath.Img.fonts.length-1; mustScale = 1}
3011 var imgFont = jsMath.Img[jsMath.Img.fonts[id]];
3012 var img = imgFont[font][C];
3013 var scale = 1/jsMath.Img.w[jsMath.Img.fonts[id]];
3014 if (id != jsMath.Img.best + size - 4) {
3015 if (c.w != null) {scale = c.w/img[0]} else {
3016 scale *= jsMath.Img.fonts[size]/jsMath.Img.fonts[4]
3017 * jsMath.Img.fonts[jsMath.Img.best]/jsMath.Img.fonts[id];
3020 var w = img[0]*scale; var h = img[1]*scale; var d = -img[2]*scale; var v;
3021 var wadjust = (c.w == null || Math.abs(c.w-w) < .01)? "" : " margin-right:"+jsMath.HTML.Em(c.w-w)+';';
3022 var resize = ""; C = jsMath.Img.HexCode[C];
3023 if (!mustScale && !jsMath.Controls.cookie.scaleImg) {
3024 if (jsMath.Browser.mozImageSizeBug || 2*w < h ||
3025 (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha))
3026 {resize = "height:"+(img[1]*jsMath.Browser.imgScale)+'px;'}
3027 resize += " width:"+(img[0]*jsMath.Browser.imgScale)+'px;'
3030 if (jsMath.Browser.mozImageSizeBug || 2*w < h ||
3031 (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha))
3032 {resize = "height:"+jsMath.HTML.Em(h*jsMath.Browser.imgScale)+';'}
3033 resize += " width:"+jsMath.HTML.Em(w*jsMath.Browser.imgScale)+';'
3034 v = jsMath.HTML.Em(d);
3036 var vadjust = (Math.abs(d) < .01 && !jsMath.Browser.valignBug)?
3037 "": " vertical-align:"+v+';';
3038 var URL = jsMath.Img.URL(font,jsMath.Img.fonts[id],C);
3039 if (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha) {
3040 c.c = '<img src="'+jsMath.blank+'" '
3041 + 'style="'+jsMath.Browser.msieCenterBugFix
3042 + resize + vadjust + wadjust
3043 + ' filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' + "'"
3044 + URL + "', sizingMethod='scale'" + ');" />';
3046 c.c = '<img src="'+URL+'" style="'+jsMath.Browser.msieCenterBugFix
3047 + resize + vadjust + wadjust + '" />';
3049 c.tclass = "normal";
3050 c.img.bh = h+d; c.img.bd = -d;
3051 c.img.size = size; c.img.best = jsMath.Img.best;
3055 * A box containing a spacer of a specific width
3057 Space: function (w) {
3058 return new jsMath.Box('html',jsMath.HTML.Spacer(w),w,0,0);
3062 * A box containing a horizontal rule
3064 Rule: function (w,h) {
3065 if (h == null) {h = jsMath.TeX.default_rule_thickness}
3066 var html = jsMath.HTML.Rule(w,h);
3067 return new jsMath.Box('html',html,w,h,0);
3071 * Get a character from a TeX font, and make sure that it has
3072 * its metrics specified.
3074 GetChar: function (code,font) {
3075 var c = jsMath.TeX[font][code];
3076 if (c.img != null) {this.TeXIMG(font,code,4)}
3077 if (c.tclass == null) {c.tclass = font}
3079 c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w;
3080 if (c.h == null) {c.h = jsMath.Box.defaultH}; if (c.d == null) {c.d = 0}
3087 * Locate the TeX delimiter character that matches a given height.
3088 * Return the character, font, style and actual height used.
3090 DelimBestFit: function (H,c,font,style) {
3091 if (c == 0 && font == 0) return null;
3092 var C; var h; font = jsMath.TeX.fam[font];
3093 var isSS = (style.charAt(1) == 'S');
3094 var isS = (style.charAt(0) == 'S');
3096 C = jsMath.TeX[font][c];
3097 if (C.h == null) {C.h = jsMath.Box.defaultH}; if (C.d == null) {C.d = 0}
3099 if (C.delim) {return [c,font,'',H]}
3100 if (isSS && .5*h >= H) {return [c,font,'SS',.5*h]}
3101 if (isS && .7*h >= H) {return [c,font,'S',.7*h]}
3102 if (h >= H || C.n == null) {return [c,font,'T',h]}
3109 * Create the HTML needed for a stretchable delimiter of a given height,
3110 * either centered or not. This version uses relative placement (i.e.,
3111 * backspaces, not line-breaks). This works with more browsers, but
3112 * if the font size changes, the backspacing may not be right, so the
3113 * delimiters may become jagged.
3115 DelimExtendRelative: function (H,c,font,a,nocenter) {
3116 var C = jsMath.TeX[font][c];
3117 var top = this.GetChar(C.delim.top? C.delim.top: C.delim.rep,font);
3118 var rep = this.GetChar(C.delim.rep,font);
3119 var bot = this.GetChar(C.delim.bot? C.delim.bot: C.delim.rep,font);
3120 var ext = jsMath.Typeset.AddClass(rep.tclass,rep.c);
3121 var w = rep.w; var h = rep.h+rep.d
3122 var y; var Y; var html; var dx; var i; var n;
3123 if (C.delim.mid) {// braces
3124 var mid = this.GetChar(C.delim.mid,font);
3125 n = Math.ceil((H-(top.h+top.d)-(mid.h+mid.d)-(bot.h+bot.d))/(2*(rep.h+rep.d)));
3126 H = 2*n*(rep.h+rep.d) + (top.h+top.d) + (mid.h+mid.d) + (bot.h+bot.d);
3127 if (nocenter) {y = 0} else {y = H/2+a}; Y = y;
3128 html = jsMath.HTML.Place(jsMath.Typeset.AddClass(top.tclass,top.c),0,y-top.h)
3129 + jsMath.HTML.Place(jsMath.Typeset.AddClass(bot.tclass,bot.c),-(top.w+bot.w)/2,y-(H-bot.d))
3130 + jsMath.HTML.Place(jsMath.Typeset.AddClass(mid.tclass,mid.c),-(bot.w+mid.w)/2,y-(H+mid.h-mid.d)/2);
3131 dx = (w-mid.w)/2; if (Math.abs(dx) < .0001) {dx = 0}
3132 if (dx) {html += jsMath.HTML.Spacer(dx)}
3133 y -= top.h+top.d + rep.h;
3134 for (i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}
3136 for (i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}
3137 } else {// everything else
3138 n = Math.ceil((H - (top.h+top.d) - (bot.h+bot.d))/(rep.h+rep.d));
3139 // make sure two-headed arrows have an extender
3140 if (top.h+top.d < .9*(rep.h+rep.d)) {n = Math.max(1,n)}
3141 H = n*(rep.h+rep.d) + (top.h+top.d) + (bot.h+bot.d);
3142 if (nocenter) {y = 0} else {y = H/2+a}; Y = y;
3143 html = jsMath.HTML.Place(jsMath.Typeset.AddClass(top.tclass,top.c),0,y-top.h)
3144 dx = (w-top.w)/2; if (Math.abs(dx) < .0001) {dx = 0}
3145 if (dx) {html += jsMath.HTML.Spacer(dx)}
3146 y -= top.h+top.d + rep.h;
3147 for (i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}
3148 html += jsMath.HTML.Place(jsMath.Typeset.AddClass(bot.tclass,bot.c),-(w+bot.w)/2,Y-(H-bot.d));
3150 if (nocenter) {h = top.h} else {h = H/2+a}
3151 var box = new jsMath.Box('html',html,rep.w,h,H-h);
3152 box.bh = jsMath.TeX[font].h; box.bd = jsMath.TeX[font].d;
3157 * Create the HTML needed for a stretchable delimiter of a given height,
3158 * either centered or not. This version uses absolute placement (i.e.,
3159 * line-breaks, not backspacing). This gives more reliable results,
3160 * but doesn't work with all browsers.
3162 DelimExtendAbsolute: function (H,c,font,a,nocenter) {
3163 var Font = jsMath.TeX[font];
3164 var C = Font[c]; var html;
3165 var top = this.GetChar(C.delim.top? C.delim.top: C.delim.rep,font);
3166 var rep = this.GetChar(C.delim.rep,font);
3167 var bot = this.GetChar(C.delim.bot? C.delim.bot: C.delim.rep,font);
3168 var n; var h; var y; var ext; var i;
3170 if (C.delim.mid) {// braces
3171 var mid = this.GetChar(C.delim.mid,font);
3172 n = Math.ceil((H-(top.h+top.d)-(mid.h+mid.d-.05)-(bot.h+bot.d-.05))/(2*(rep.h+rep.d-.05)));
3173 H = 2*n*(rep.h+rep.d-.05) + (top.h+top.d) + (mid.h+mid.d-.05) + (bot.h+bot.d-.05);
3175 html = jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(top.tclass,top.c),0,0);
3176 h = rep.h+rep.d - .05; y = top.d-.05 + rep.h;
3177 ext = jsMath.Typeset.AddClass(rep.tclass,rep.c)
3178 for (i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}
3179 html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(mid.tclass,mid.c),0,y+n*h-rep.h+mid.h);
3180 y += n*h + mid.h+mid.d - .05;
3181 for (i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}
3182 html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(bot.tclass,bot.c),0,y+n*h-rep.h+bot.h);
3183 } else {// all others
3184 n = Math.ceil((H - (top.h+top.d) - (bot.h+bot.d-.05))/(rep.h+rep.d-.05));
3185 H = n*(rep.h+rep.d-.05) + (top.h+top.d) + (bot.h+bot.d-.05);
3187 html = jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(top.tclass,top.c),0,0);
3188 h = rep.h+rep.d-.05; y = top.d-.05 + rep.h;
3189 ext = jsMath.Typeset.AddClass(rep.tclass,rep.c);
3190 for (i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}
3191 html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(bot.tclass,bot.c),0,y+n*h-rep.h+bot.h);
3195 if (nocenter) {h = top.h; y = 0} else {h = H/2 + a; y = h - top.h}
3196 if (jsMath.Controls.cookie.font === "unicode") {
3197 if (jsMath.Browser.msie8HeightBug) {y -= jsMath.hd}
3198 else if (jsMath.Browser.msieBlockDepthBug) {y += jsMath.d}
3200 html = jsMath.HTML.Absolute(html,w,Font.h,"none",-y);
3201 var box = new jsMath.Box('html',html,rep.w,h,H-h);
3202 box.bh = jsMath.TeX[font].h; box.bd = jsMath.TeX[font].d;
3207 * Get the HTML for a given delimiter of a given height.
3208 * It will return either a single character, if one exists, or the
3209 * more complex HTML needed for a stretchable delimiter.
3211 Delimiter: function (H,delim,style,nocenter) {
3212 var size = 4; //### pass this?
3213 var TeX = jsMath.Typeset.TeX(style,size);
3214 if (!delim) {return this.Space(TeX.nulldelimiterspace)}
3215 var CFSH = this.DelimBestFit(H,delim[2],delim[1],style);
3216 if (CFSH == null || CFSH[3] < H)
3217 {CFSH = this.DelimBestFit(H,delim[4],delim[3],style)}
3218 if (CFSH == null) {return this.Space(TeX.nulldelimiterspace)}
3220 {return this.DelimExtend(H,CFSH[0],CFSH[1],TeX.axis_height,nocenter)}
3221 var box = jsMath.Box.TeX(CFSH[0],CFSH[1],CFSH[2],size).Styled();
3222 if (!nocenter) {box.y = -((box.h+box.d)/2 - box.d - TeX.axis_height)}
3223 if (Math.abs(box.y) < .0001) {box.y = 0}
3224 if (box.y) {box = jsMath.Box.SetList([box],CFSH[2],size)}
3229 * Get a character by its TeX charcode, and make sure its width
3232 GetCharCode: function (code) {
3233 var font = jsMath.TeX.fam[code[0]];
3234 var Font = jsMath.TeX[font];
3235 var c = Font[code[1]];
3236 if (c.img != null) {this.TeXIMG(font,code[1],4)}
3237 if (c.w == null) {c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w}
3238 if (c.font == null) {c.font = font}
3243 * Add the class to the html, and use the font if there isn't one
3247 AddClass: function (tclass,html,font) {
3248 if (tclass == null) {tclass = font}
3249 return jsMath.Typeset.AddClass(tclass,html);
3253 * Create the HTML for an alignment (e.g., array or matrix)
3254 * Since the widths are not really accurate (they are based on pixel
3255 * widths not the sub-pixel widths of the actual characters), there
3256 * is some drift involved. We lay out the table column by column
3257 * to help reduce the problem.
3259 * ### still need to allow users to specify row and column attributes,
3260 * and do things like \span and \multispan ###
3262 LayoutRelative: function (size,table,align,cspacing,rspacing,vspace,useStrut,addWidth) {
3263 if (align == null) {align = []}
3264 if (cspacing == null) {cspacing = []}
3265 if (rspacing == null) {rspacing = []}
3266 if (useStrut == null) {useStrut = 1}
3267 if (addWidth == null) {addWidth = 1}
3269 // get row and column maximum dimensions
3270 var scale = jsMath.sizes[size]/100;
3271 var W = []; var H = []; var D = [];
3272 var unset = -1000; var bh = unset; var bd = unset;
3273 var i; var j; var row;
3274 for (i = 0; i < table.length; i++) {
3275 if (rspacing[i] == null) {rspacing[i] = 0}
3277 H[i] = useStrut*jsMath.h*scale; D[i] = useStrut*jsMath.d*scale;
3278 for (j = 0; j < row.length; j++) {
3279 row[j] = row[j].Remeasured();
3280 if (row[j].h > H[i]) {H[i] = row[j].h}
3281 if (row[j].d > D[i]) {D[i] = row[j].d}
3282 if (j >= W.length) {W[j] = row[j].w}
3283 else if (row[j].w > W[j]) {W[j] = row[j].w}
3284 if (row[j].bh > bh) {bh = row[j].bh}
3285 if (row[j].bd > bd) {bd = row[j].bd}
3288 if (rspacing[table.length] == null) {rspacing[table.length] = 0}
3289 if (bh == unset) {bh = 0}; if (bd == unset) {bd = 0}
3291 // lay out the columns
3292 var HD = useStrut*(jsMath.hd-.01)*scale;
3293 var dy = (vspace || 1) * scale/6;
3294 var html = ''; var pW = 0; var cW = 0;
3295 var w; var h; var y;
3296 var box; var mlist; var entry;
3297 for (j = 0; j < W.length; j++) {
3298 mlist = []; y = -H[0]-rspacing[0]; pW = 0;
3299 for (i = 0; i < table.length; i++) {
3300 entry = table[i][j];
3301 if (entry && entry.format != 'null') {
3302 if (align[j] == 'l') {w = 0} else
3303 if (align[j] == 'r') {w = W[j] - entry.w} else
3304 {w = (W[j] - entry.w)/2}
3305 entry.x = w - pW; pW = entry.w + w; entry.y = y;
3306 mlist[mlist.length] = entry;
3308 if (i+1 < table.length) {y -= Math.max(HD,D[i]+H[i+1]) + dy + rspacing[i+1]}
3310 if (cspacing[j] == null) cspacing[j] = scale;
3311 if (mlist.length > 0) {
3312 box = jsMath.Box.SetList(mlist,'T',size);
3313 html += jsMath.HTML.Place(box.html,cW,0);
3314 cW = W[j] - box.w + cspacing[j];
3315 } else {cW += cspacing[j]}
3318 // get the full width and height
3319 w = -cspacing[W.length-1]; y = (H.length-1)*dy + rspacing[0];
3320 for (i = 0; i < W.length; i++) {w += W[i] + cspacing[i]}
3321 for (i = 0; i < H.length; i++) {y += Math.max(HD,H[i]+D[i]) + rspacing[i+1]}
3322 h = y/2 + jsMath.TeX.axis_height; var d = y-h;
3324 // adjust the final row width, and vcenter the table
3325 // (add 1/6em at each side for the \,)
3326 html += jsMath.HTML.Spacer(cW-cspacing[W.length-1] + addWidth*scale/6);
3327 html = jsMath.HTML.Place(html,addWidth*scale/6,h);
3328 box = new jsMath.Box('html',html,w+addWidth*scale/3,h,d);
3329 box.bh = bh; box.bd = bd;
3334 * Create the HTML for an alignment (e.g., array or matrix)
3335 * Use absolute position for elements in the array.
3337 * ### still need to allow users to specify row and column attributes,
3338 * and do things like \span and \multispan ###
3340 LayoutAbsolute: function (size,table,align,cspacing,rspacing,vspace,useStrut,addWidth) {
3341 if (align == null) {align = []}
3342 if (cspacing == null) {cspacing = []}
3343 if (rspacing == null) {rspacing = []}
3344 if (useStrut == null) {useStrut = 1}
3345 if (addWidth == null) {addWidth = 1}
3346 // get row and column maximum dimensions
3347 var scale = jsMath.sizes[size]/100;
3348 var HD = useStrut*(jsMath.hd-.01)*scale;
3349 var dy = (vspace || 1) * scale/6;
3350 var W = []; var H = []; var D = [];
3351 var w = 0; var h; var x; var y;
3352 var i; var j; var row;
3353 for (i = 0; i < table.length; i++) {
3354 if (rspacing[i] == null) {rspacing[i] = 0}
3356 H[i] = useStrut*jsMath.h*scale; D[i] = useStrut*jsMath.d*scale;
3357 for (j = 0; j < row.length; j++) {
3358 row[j] = row[j].Remeasured();
3359 if (row[j].h > H[i]) {H[i] = row[j].h}
3360 if (row[j].d > D[i]) {D[i] = row[j].d}
3361 if (j >= W.length) {W[j] = row[j].w}
3362 else if (row[j].w > W[j]) {W[j] = row[j].w}
3365 if (rspacing[table.length] == null) {rspacing[table.length] = 0}
3367 // get the height and depth of the centered table
3368 y = (H.length-1)*dy + rspacing[0];
3369 for (i = 0; i < H.length; i++) {y += Math.max(HD,H[i]+D[i]) + rspacing[i+1]}
3370 h = y/2 + jsMath.TeX.axis_height; var d = y - h;
3372 // lay out the columns
3373 var html = ''; var entry; w = addWidth*scale/6;
3374 for (j = 0; j < W.length; j++) {
3375 y = H[0]-h + rspacing[0];
3376 for (i = 0; i < table.length; i++) {
3377 entry = table[i][j];
3378 if (entry && entry.format != 'null') {
3379 if (align[j] && align[j] == 'l') {x = 0} else
3380 if (align[j] && align[j] == 'r') {x = W[j] - entry.w} else
3381 {x = (W[j] - entry.w)/2}
3382 html += jsMath.HTML.PlaceAbsolute(entry.html,w+x,
3383 y-Math.max(0,entry.bh-jsMath.h*scale),
3384 entry.mw,entry.Mw,entry.w);
3386 if (i+1 < table.length) {y += Math.max(HD,D[i]+H[i+1]) + dy + rspacing[i+1]}
3388 if (cspacing[j] == null) cspacing[j] = scale;
3389 w += W[j] + cspacing[j];
3392 // get the full width
3393 w = -cspacing[W.length-1]+addWidth*scale/3;
3394 for (i = 0; i < W.length; i++) {w += W[i] + cspacing[i]}
3396 html = jsMath.HTML.Spacer(addWidth*scale/6)+html+jsMath.HTML.Spacer(addWidth*scale/6);
3397 if (jsMath.Browser.spanHeightVaries) {y = h-jsMath.h} else {y = 0}
3398 if (jsMath.Browser.msie8HeightBug) {y = d-jsMath.d}
3399 html = jsMath.HTML.Absolute(html,w,h+d,d,y);
3400 var box = new jsMath.Box('html',html,w+addWidth*scale/3,h,d);
3405 * Look for math within \hbox and other non-math text
3407 InternalMath: function (text,size) {
3408 if (!jsMath.safeHBoxes) {text = text.replace(/@\(([^)]*)\)/g,'<$1>')}
3409 if (!text.match(/\$|\\\(/))
3410 {return this.Text(this.safeHTML(text),'normal','T',size).Styled()}
3412 var i = 0; var k = 0; var c; var match = '';
3413 var mlist = []; var parse, s;
3414 while (i < text.length) {
3415 c = text.charAt(i++);
3418 parse = jsMath.Parse(text.slice(k,i-1),null,size);
3420 mlist[mlist.length] = this.Text(parse.error,'error','T',size,1,.2);
3423 mlist[mlist.length] = parse.mlist.Typeset('T',size).Styled();
3427 s = this.safeHTML(text.slice(k,i-1));
3428 mlist[mlist.length] = this.Text(s,'normal','T',size,1,.2);
3431 } else if (c == '\\') {
3432 c = text.charAt(i++);
3433 if (c == '(' && match == '') {
3434 s = this.safeHTML(text.slice(k,i-2));
3435 mlist[mlist.length] = this.Text(s,'normal','T',size,1,.2);
3437 } else if (c == ')' && match == ')') {
3438 parse = jsMath.Parse(text.slice(k,i-2),null,size);
3440 mlist[mlist.length] = this.Text(parse.error,'error','T',size,1,.2);
3443 mlist[mlist.length] = parse.mlist.Typeset('T',size).Styled();
3449 s = this.safeHTML(text.slice(k));
3450 mlist[mlist.length] = this.Text(s,'normal','T',size,1,.2);
3451 return this.SetList(mlist,'T',size);
3455 * Quote HTML characters if we are in safe mode
3457 safeHTML: function (s) {
3458 if (jsMath.safeHBoxes) {
3459 s = s.replace(/&/g,'&')
3460 .replace(/</g,'<')
3461 .replace(/>/g,'>');
3467 * Convert an abitrary box to a typeset box. I.e., make an
3468 * HTML version of the contents of the box, at its desired (x,y)
3471 Set: function (box,style,size,addstyle) {
3472 if (box && box.type) {
3473 if (box.type == 'typeset') {return box}
3474 if (box.type == 'mlist') {
3475 box.mlist.Atomize(style,size);
3476 return box.mlist.Typeset(style,size);
3478 if (box.type == 'text') {
3479 box = this.Text(box.text,box.tclass,style,size,box.ascend||null,box.descend||null);
3480 if (addstyle != 0) {box.Styled()}
3483 box = this.TeX(box.c,box.font,style,size);
3484 if (addstyle != 0) {box.Styled()}
3487 return jsMath.Box.Null();
3491 * Convert a list of boxes to a single typeset box. I.e., finalize
3492 * the HTML for the list of boxes, properly spaced and positioned.
3494 SetList: function (boxes,style,size) {
3495 var mlist = []; var box;
3496 for (var i = 0; i < boxes.length; i++) {
3498 if (box.type == 'typeset') {box = jsMath.mItem.Typeset(box)}
3499 mlist[mlist.length] = box;
3501 var typeset = new jsMath.Typeset(mlist);
3502 return typeset.Typeset(style,size);
3508 jsMath.Package(jsMath.Box,{
3511 * Add the class and style to a text box (i.e., finalize the
3512 * unpositioned HTML for the box).
3514 Styled: function () {
3515 if (this.format == 'text') {
3516 this.html = jsMath.Typeset.AddClass(this.tclass,this.html);
3517 this.html = jsMath.Typeset.AddStyle(this.style,this.size,this.html);
3518 delete this.tclass; delete this.style;
3519 this.format = 'html';
3525 * Recompute the box width to make it more accurate.
3527 Remeasured: function () {
3529 var w = this.w; this.w = jsMath.EmBoxFor(this.html).w;
3530 if (this.w > this.Mw) {this.Mw = this.w}
3531 w = this.w/w; if (Math.abs(w-1) > .05) {this.h *= w; this.d *= w}
3539 /***************************************************************************/
3542 * mItems are the building blocks of mLists (math lists) used to
3543 * store the information about a mathematical expression. These are
3544 * basically the items listed in the TeXbook in Appendix G (plus some
3545 * minor extensions).
3547 jsMath.mItem = function (type,def) {
3549 jsMath.Add(this,def);
3552 jsMath.Add(jsMath.mItem,{
3555 * A general atom (given a nucleus for the atom)
3557 Atom: function (type,nucleus) {
3558 return new jsMath.mItem(type,{atom: 1, nuc: nucleus});
3562 * An atom whose nucleus is a piece of text, in a given
3563 * class, with a given additional height and depth
3565 TextAtom: function (type,text,tclass,a,d) {
3566 var atom = new jsMath.mItem(type,{
3574 if (a != null) {atom.nuc.ascend = a}
3575 if (d != null) {atom.nuc.descend = d}
3580 * An atom whose nucleus is a TeX character in a specific font
3582 TeXAtom: function (type,c,font) {
3583 return new jsMath.mItem(type,{
3594 * A generalized fraction atom, with given delimiters, rule
3595 * thickness, and a numerator and denominator.
3597 Fraction: function (name,num,den,thickness,left,right) {
3598 return new jsMath.mItem('fraction',{
3599 from: name, num: num, den: den,
3600 thickness: thickness, left: left, right: right
3605 * An atom that inserts some glue
3607 Space: function (w) {return new jsMath.mItem('space',{w: w})},
3610 * An atom that contains a typeset box (like an hbox or vbox)
3612 Typeset: function (box) {return new jsMath.mItem('ord',{atom:1, nuc: box})},
3615 * An atom that contains some finished HTML (acts like a typeset box)
3617 HTML: function (html) {return new jsMath.mItem('html',{html: html})}
3621 /***************************************************************************/
3624 * mLists are lists of mItems, and encode the contents of
3625 * mathematical expressions and sub-expressions. They act as
3626 * the expression "stack" as the mathematics is parsed, and
3627 * contain some state information, like the position of the
3628 * most recent open paren and \over command, and the current font.
3630 jsMath.mList = function (list,font,size,style) {
3631 if (list) {this.mlist = list} else {this.mlist = []}
3632 if (style == null) {style = 'T'}; if (size == null) {size = 4}
3633 this.data = {openI: null, overI: null, overF: null,
3634 font: font, size: size, style: style};
3635 this.init = {size: size, style: style};
3638 jsMath.Package(jsMath.mList,{
3641 * Add an mItem to the list
3643 Add: function (box) {return (this.mlist[this.mlist.length] = box)},
3646 * Get the i-th mItem from the list
3648 Get: function (i) {return this.mlist[i]},
3651 * Get the length of the list
3653 Length: function() {return this.mlist.length},
3656 * Get the tail mItem of the list
3659 if (this.mlist.length == 0) {return null}
3660 return this.mlist[this.mlist.length-1]
3664 * Get a sublist of an mList
3666 Range: function (i,j) {
3667 if (j == null) {j = this.mlist.length}
3668 return new jsMath.mList(this.mlist.slice(i,j+1));
3672 * Remove a range of mItems from the list.
3674 Delete: function (i,j) {
3675 if (j == null) {j = i}
3676 if (this.mlist.splice) {this.mlist.splice(i,j-i+1)} else {
3678 for (var k = 0; k < this.mlist.length; k++)
3679 {if (k < i || k > j) {mlist[mlist.length] = this.mlist[k]}}
3685 * Add an open brace and maintain the stack information
3686 * about the previous open brace so we can recover it
3687 * when this one os closed.
3689 Open: function (left) {
3690 var box = this.Add(new jsMath.mItem('boundary',{data: this.data}));
3691 var olddata = this.data;
3692 this.data = {}; for (var i in olddata) {this.data[i] = olddata[i]}
3693 delete this.data.overI; delete this.data.overF;
3694 this.data.openI = this.mlist.length-1;
3695 if (left != null) {box.left = left}
3700 * Attempt to close a brace. Recover the stack information
3701 * about previous open braces and \over commands. If there was an
3702 * \over (or \above, etc) in this set of braces, create a fraction
3703 * atom from the two halves, otherwise create an inner or ord
3704 * from the contents of the braces.
3705 * Remove the braced material from the list and add the newly
3706 * created atom (the fraction, inner or ord).
3708 Close: function (right) {
3709 if (right != null) {right = new jsMath.mItem('boundary',{right: right})}
3710 var atom; var open = this.data.openI;
3711 var over = this.data.overI; var from = this.data.overF;
3712 this.data = this.mlist[open].data;
3714 atom = jsMath.mItem.Fraction(from.name,
3715 {type: 'mlist', mlist: this.Range(open+1,over-1)},
3716 {type: 'mlist', mlist: this.Range(over)},
3717 from.thickness,from.left,from.right);
3719 var mlist = new jsMath.mList([this.mlist[open],atom,right]);
3720 atom = jsMath.mItem.Atom('inner',{type: 'mlist', mlist: mlist});
3723 var openI = open+1; if (right) {this.Add(right); openI--}
3724 atom = jsMath.mItem.Atom((right)?'inner':'ord',
3725 {type: 'mlist', mlist: this.Range(openI)});
3727 this.Delete(open,this.Length());
3728 return this.Add(atom);
3732 * Create a generalized fraction from an mlist that
3733 * contains an \over (or \above, etc).
3736 var over = this.data.overI; var from = this.data.overF;
3737 var atom = jsMath.mItem.Fraction(from.name,
3738 {type: 'mlist', mlist: this.Range(open+1,over-1)},
3739 {type: 'mlist', mlist: this.Range(over)},
3740 from.thickness,from.left,from.right);
3741 this.mlist = [atom];
3745 * Take a raw mList (that has been produced by parsing some TeX
3746 * expression), and perform the modifications outlined in
3747 * Appendix G of the TeXbook.
3749 Atomize: function (style,size) {
3750 var mitem; var prev = '';
3751 this.style = style; this.size = size;
3752 for (var i = 0; i < this.mlist.length; i++) {
3753 mitem = this.mlist[i]; mitem.delta = 0;
3754 if (mitem.type == 'choice')
3755 {this.mlist = this.Atomize.choice(this.style,mitem,i,this.mlist); i--}
3756 else if (this.Atomize[mitem.type]) {
3757 var f = this.Atomize[mitem.type]; // Opera needs separate name
3758 f(this.style,this.size,mitem,prev,this,i);
3762 if (mitem && mitem.type == 'bin') {mitem.type = 'ord'}
3763 if (this.mlist.length >= 2 && mitem.type == 'boundary' &&
3764 this.mlist[0].type == 'boundary') {this.AddDelimiters(style,size)}
3768 * For a list that has boundary delimiters as its first and last
3769 * entries, we replace the boundary atoms by open and close
3770 * atoms whose nuclii are the specified delimiters properly sized
3771 * for the contents of the list. (Rule 19)
3773 AddDelimiters: function(style,size) {
3774 var unset = -10000; var h = unset; var d = unset;
3775 for (var i = 0; i < this.mlist.length; i++) {
3776 var mitem = this.mlist[i];
3777 if (mitem.atom || mitem.type == 'box') {
3778 h = Math.max(h,mitem.nuc.h+mitem.nuc.y);
3779 d = Math.max(d,mitem.nuc.d-mitem.nuc.y);
3782 var TeX = jsMath.TeX; var a = jsMath.Typeset.TeX(style,size).axis_height;
3783 var delta = Math.max(h-a,d+a);
3784 var H = Math.max(Math.floor(TeX.integer*delta/500)*TeX.delimiterfactor,
3785 TeX.integer*(2*delta-TeX.delimitershortfall))/TeX.integer;
3786 var left = this.mlist[0]; var right = this.mlist[this.mlist.length-1];
3787 left.nuc = jsMath.Box.Delimiter(H,left.left,style);
3788 right.nuc = jsMath.Box.Delimiter(H,right.right,style);
3789 left.type = 'open'; left.atom = 1; delete left.left;
3790 right.type = 'close'; right.atom = 1; delete right.right;
3794 * Typeset a math list to produce final HTML for the list.
3796 Typeset: function (style,size) {
3797 var typeset = new jsMath.Typeset(this.mlist);
3798 return typeset.Typeset(style,size);
3805 * These routines implement the main rules given in Appendix G of the
3809 jsMath.Add(jsMath.mList.prototype.Atomize,{
3812 * Handle \displaystyle, \textstyle, etc.
3814 style: function (style,size,mitem,prev,mlist) {
3815 mlist.style = mitem.style;
3819 * Handle \tiny, \small, etc.
3821 size: function (style,size,mitem,prev,mlist) {
3822 mlist.size = mitem.size;
3826 * Create empty boxes of the proper sizes for the various
3827 * phantom-type commands
3829 phantom: function (style,size,mitem) {
3830 var box = mitem.nuc = jsMath.Box.Set(mitem.phantom,style,size);
3831 if (mitem.h) {box.Remeasured(); box.html = jsMath.HTML.Spacer(box.w)}
3832 else {box.html = '', box.w = box.Mw = box.mw = 0;}
3833 if (!mitem.v) {box.h = box.d = 0}
3834 box.bd = box.bh = 0;
3835 delete mitem.phantom;
3840 * Create a box of zero height and depth containing the
3841 * contents of the atom
3843 smash: function (style,size,mitem) {
3844 var box = mitem.nuc = jsMath.Box.Set(mitem.smash,style,size).Remeasured();
3851 * Move a box up or down vertically
3853 raise: function (style,size,mitem) {
3854 mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size);
3855 var y = mitem.raise;
3857 jsMath.HTML.Place(mitem.nuc.html,0,y,mitem.nuc.mw,mitem.nuc.Mw,mitem.nuc.w);
3858 mitem.nuc.h += y; mitem.nuc.d -= y;
3859 mitem.type = 'ord'; mitem.atom = 1;
3863 * Hide the size of a box so that it laps to the left or right, or
3866 lap: function (style,size,mitem) {
3867 var box = jsMath.Box.Set(mitem.nuc,style,size).Remeasured();
3869 if (mitem.lap == 'llap') {box.x = -box.w} else
3870 if (mitem.lap == 'rlap') {mlist[1] = jsMath.mItem.Space(-box.w)} else
3871 if (mitem.lap == 'ulap') {box.y = box.d; box.h = box.d = 0} else
3872 if (mitem.lap == 'dlap') {box.y = -box.h; box.h = box.d = 0}
3873 mitem.nuc = jsMath.Box.SetList(mlist,style,size);
3874 if (mitem.lap == 'ulap' || mitem.lap == 'dlap') {mitem.nuc.h = mitem.nuc.d = 0}
3875 mitem.type = 'box'; delete mitem.atom;
3879 * Handle a Bin atom. (Rule 5)
3881 bin: function (style,size,mitem,prev) {
3882 if (prev && prev.type) {
3883 var type = prev.type;
3884 if (type == 'bin' || type == 'op' || type == 'rel' ||
3885 type == 'open' || type == 'punct' || type == '' ||
3886 (type == 'boundary' && prev.left != '')) {mitem.type = 'ord'}
3887 } else {mitem.type = 'ord'}
3888 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3892 * Handle a Rel atom. (Rule 6)
3894 rel: function (style,size,mitem,prev) {
3895 if (prev.type && prev.type == 'bin') {prev.type = 'ord'}
3896 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3900 * Handle a Close atom. (Rule 6)
3902 close: function (style,size,mitem,prev) {
3903 if (prev.type && prev.type == 'bin') {prev.type = 'ord'}
3904 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3908 * Handle a Punct atom. (Rule 6)
3910 punct: function (style,size,mitem,prev) {
3911 if (prev.type && prev.type == 'bin') {prev.type = 'ord'}
3912 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3916 * Handle an Open atom. (Rule 7)
3918 open: function (style,size,mitem) {
3919 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3923 * Handle an Inner atom. (Rule 7)
3925 inner: function (style,size,mitem) {
3926 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3930 * Handle a Vcent atom. (Rule 8)
3932 vcenter: function (style,size,mitem) {
3933 var box = jsMath.Box.Set(mitem.nuc,style,size);
3934 var TeX = jsMath.Typeset.TeX(style,size);
3935 box.y = TeX.axis_height - (box.h-box.d)/2;
3936 mitem.nuc = box; mitem.type = 'ord';
3937 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3941 * Handle an Over atom. (Rule 9)
3943 overline: function (style,size,mitem) {
3944 var TeX = jsMath.Typeset.TeX(style,size);
3945 var box = jsMath.Box.Set(mitem.nuc,jsMath.Typeset.PrimeStyle(style),size).Remeasured();
3946 var t = TeX.default_rule_thickness;
3947 var rule = jsMath.Box.Rule(box.w,t);
3948 rule.x = -rule.w; rule.y = box.h + 3*t;
3949 mitem.nuc = jsMath.Box.SetList([box,rule],style,size);
3952 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3956 * Handle an Under atom. (Rule 10)
3958 underline: function (style,size,mitem) {
3959 var TeX = jsMath.Typeset.TeX(style,size);
3960 var box = jsMath.Box.Set(mitem.nuc,jsMath.Typeset.PrimeStyle(style),size).Remeasured();
3961 var t = TeX.default_rule_thickness;
3962 var rule = jsMath.Box.Rule(box.w,t);
3963 rule.x = -rule.w; rule.y = -box.d - 3*t - t;
3964 mitem.nuc = jsMath.Box.SetList([box,rule],style,size);
3967 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
3971 * Handle a Rad atom. (Rule 11 plus stuff for \root..\of)
3973 radical: function (style,size,mitem) {
3974 var TeX = jsMath.Typeset.TeX(style,size);
3975 var Cp = jsMath.Typeset.PrimeStyle(style);
3976 var box = jsMath.Box.Set(mitem.nuc,Cp,size).Remeasured();
3977 var t = TeX.default_rule_thickness;
3978 var p = t; if (style == 'D' || style == "D'") {p = TeX.x_height}
3980 var surd = jsMath.Box.Delimiter(box.h+box.d+r+t,[0,2,0x70,3,0x70],style,1);
3981 // if (surd.h > 0) {t = surd.h} // thickness of rule is height of surd character
3982 if (surd.d > box.h+box.d+r) {r = (r+surd.d-box.h-box.d)/2}
3984 var rule = jsMath.Box.Rule(box.w,t);
3985 rule.y = surd.y-t/2; rule.h += 3*t/2; box.x = -box.w;
3986 var Cr = jsMath.Typeset.UpStyle(jsMath.Typeset.UpStyle(style));
3987 var root = jsMath.Box.Set(mitem.root || null,Cr,size).Remeasured();
3989 root.y = .55*(box.h+box.d+3*t+r)-box.d;
3990 surd.x = Math.max(root.w-(11/18)*surd.w,0);
3991 rule.x = (7/18)*surd.w;
3992 root.x = -(root.w+rule.x);
3994 mitem.nuc = jsMath.Box.SetList([surd,root,rule,box],style,size);
3996 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
4000 * Handle an Acc atom. (Rule 12)
4002 accent: function (style,size,mitem) {
4003 var TeX = jsMath.Typeset.TeX(style,size);
4004 var Cp = jsMath.Typeset.PrimeStyle(style);
4005 var box = jsMath.Box.Set(mitem.nuc,Cp,size);
4006 var u = box.w; var s; var Font; var ic = 0;
4007 if (mitem.nuc.type == 'TeX') {
4008 Font = jsMath.TeX[mitem.nuc.font];
4009 if (Font[mitem.nuc.c].krn && Font.skewchar)
4010 {s = Font[mitem.nuc.c].krn[Font.skewchar]}
4011 ic = Font[mitem.nuc.c].ic; if (ic == null) {ic = 0}
4013 if (s == null) {s = 0}
4015 var c = mitem.accent[2];
4016 var font = jsMath.TeX.fam[mitem.accent[1]]; Font = jsMath.TeX[font];
4017 while (Font[c].n && Font[Font[c].n].w <= u) {c = Font[c].n}
4019 var delta = Math.min(box.h,TeX.x_height);
4020 if (mitem.nuc.type == 'TeX') {
4021 var nitem = jsMath.mItem.Atom('ord',mitem.nuc);
4022 nitem.sup = mitem.sup; nitem.sub = mitem.sub; nitem.delta = 0;
4023 jsMath.mList.prototype.Atomize.SupSub(style,size,nitem);
4024 delta += (nitem.nuc.h - box.h);
4025 box = mitem.nuc = nitem.nuc;
4026 delete mitem.sup; delete mitem.sub;
4028 var acc = jsMath.Box.TeX(c,font,style,size);
4029 acc.y = box.h - delta; acc.x = -box.w + s + (u-acc.w)/2;
4030 if (jsMath.Browser.msieAccentBug)
4031 {acc.html += jsMath.HTML.Spacer(.1); acc.w += .1; acc.Mw += .1}
4032 if (Font[c].ic || ic) {acc.x += (ic - (Font[c].ic||0)) * TeX.scale}
4034 mitem.nuc = jsMath.Box.SetList([box,acc],style,size);
4035 if (mitem.nuc.w != box.w) {
4036 var space = jsMath.mItem.Space(box.w-mitem.nuc.w);
4037 mitem.nuc = jsMath.Box.SetList([mitem.nuc,space],style,size);
4040 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
4044 * Handle an Op atom. (Rules 13 and 13a)
4046 op: function (style,size,mitem) {
4047 var TeX = jsMath.Typeset.TeX(style,size); var box;
4048 mitem.delta = 0; var isD = (style.charAt(0) == 'D');
4049 if (mitem.limits == null && isD) {mitem.limits = 1}
4051 if (mitem.nuc.type == 'TeX') {
4052 var C = jsMath.TeX[mitem.nuc.font][mitem.nuc.c];
4053 if (isD && C.n) {mitem.nuc.c = C.n; C = jsMath.TeX[mitem.nuc.font][C.n]}
4054 box = mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size);
4056 mitem.delta = C.ic * TeX.scale;
4057 if (mitem.limits || !mitem.sub || jsMath.Browser.msieIntegralBug) {
4058 box = mitem.nuc = jsMath.Box.SetList([box,jsMath.mItem.Space(mitem.delta)],style,size);
4061 box.y = -((box.h+box.d)/2 - box.d - TeX.axis_height);
4062 if (Math.abs(box.y) < .0001) {box.y = 0}
4065 if (!box) {box = mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size).Remeasured()}
4067 var W = box.w; var x = box.w;
4068 var mlist = [box]; var dh = 0; var dd = 0;
4070 var sup = jsMath.Box.Set(mitem.sup,jsMath.Typeset.UpStyle(style),size).Remeasured();
4071 sup.x = ((box.w-sup.w)/2 + mitem.delta/2) - x; dh = TeX.big_op_spacing5;
4072 W = Math.max(W,sup.w); x += sup.x + sup.w;
4073 sup.y = box.h+sup.d + box.y +
4074 Math.max(TeX.big_op_spacing1,TeX.big_op_spacing3-sup.d);
4075 mlist[mlist.length] = sup; delete mitem.sup;
4078 var sub = jsMath.Box.Set(mitem.sub,jsMath.Typeset.DownStyle(style),size).Remeasured();
4079 sub.x = ((box.w-sub.w)/2 - mitem.delta/2) - x; dd = TeX.big_op_spacing5;
4080 W = Math.max(W,sub.w); x += sub.x + sub.w;
4081 sub.y = -box.d-sub.h + box.y -
4082 Math.max(TeX.big_op_spacing2,TeX.big_op_spacing4-sub.h);
4083 mlist[mlist.length] = sub; delete mitem.sub;
4085 if (W > box.w) {box.x = (W-box.w)/2; x += box.x}
4086 if (x < W) {mlist[mlist.length] = jsMath.mItem.Space(W-x)}
4087 mitem.nuc = jsMath.Box.SetList(mlist,style,size);
4088 mitem.nuc.h += dh; mitem.nuc.d += dd;
4090 if (jsMath.Browser.msieIntegralBug && mitem.sub && C && C.ic)
4091 {mitem.nuc = jsMath.Box.SetList([box,jsMath.Box.Space(-C.ic*TeX.scale)],style,size)}
4092 else if (box.y) {mitem.nuc = jsMath.Box.SetList([box],style,size)}
4093 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
4098 * Handle an Ord atom. (Rule 14)
4100 ord: function (style,size,mitem,prev,mList,i) {
4101 if (mitem.nuc.type == 'TeX' && !mitem.sup && !mitem.sub) {
4102 var nitem = mList.mlist[i+1];
4103 if (nitem && nitem.atom && nitem.type &&
4104 (nitem.type == 'ord' || nitem.type == 'op' || nitem.type == 'bin' ||
4105 nitem.type == 'rel' || nitem.type == 'open' ||
4106 nitem.type == 'close' || nitem.type == 'punct')) {
4107 if (nitem.nuc.type == 'TeX' && nitem.nuc.font == mitem.nuc.font) {
4108 mitem.textsymbol = 1;
4109 var krn = jsMath.TeX[mitem.nuc.font][mitem.nuc.c].krn;
4110 krn *= jsMath.Typeset.TeX(style,size).scale;
4111 if (krn && krn[nitem.nuc.c]) {
4112 for (var k = mList.mlist.length-1; k > i; k--)
4113 {mList.mlist[k+1] = mList.mlist[k]}
4114 mList.mlist[i+1] = jsMath.mItem.Space(krn[nitem.nuc.c]);
4119 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
4123 * Handle a generalized fraction. (Rules 15 to 15e)
4125 fraction: function (style,size,mitem) {
4126 var TeX = jsMath.Typeset.TeX(style,size); var t = 0;
4127 if (mitem.thickness != null) {t = mitem.thickness}
4128 else if (mitem.from.match(/over/)) {t = TeX.default_rule_thickness}
4129 var isD = (style.charAt(0) == 'D');
4130 var Cn = (style == 'D')? 'T': (style == "D'")? "T'": jsMath.Typeset.UpStyle(style);
4131 var Cd = (isD)? "T'": jsMath.Typeset.DownStyle(style);
4132 var num = jsMath.Box.Set(mitem.num,Cn,size).Remeasured();
4133 var den = jsMath.Box.Set(mitem.den,Cd,size).Remeasured();
4135 var u; var v; var w; var p; var r;
4136 var H = (isD)? TeX.delim1 : TeX.delim2;
4137 var mlist = [jsMath.Box.Delimiter(H,mitem.left,style)]
4138 var right = jsMath.Box.Delimiter(H,mitem.right,style);
4140 if (num.w < den.w) {
4141 num.x = (den.w-num.w)/2;
4142 den.x = -(num.w + num.x);
4143 w = den.w; mlist[1] = num; mlist[2] = den;
4145 den.x = (num.w-den.w)/2;
4146 num.x = -(den.w + den.x);
4147 w = num.w; mlist[1] = den; mlist[2] = num;
4149 if (isD) {u = TeX.num1; v = TeX.denom1} else {
4150 u = (t != 0)? TeX.num2: TeX.num3;
4153 if (t == 0) {// atop
4154 p = (isD)? 7*TeX.default_rule_thickness: 3*TeX.default_rule_thickness;
4155 r = (u - num.d) - (den.h - v);
4156 if (r < p) {u += (p-r)/2; v += (p-r)/2}
4158 p = (isD)? 3*t: t; var a = TeX.axis_height;
4159 r = (u-num.d)-(a+t/2); if (r < p) {u += p-r}
4160 r = (a-t/2)-(den.h-v); if (r < p) {v += p-r}
4161 var rule = jsMath.Box.Rule(w,t); rule.x = -w; rule.y = a - t/2;
4162 mlist[mlist.length] = rule;
4164 num.y = u; den.y = -v;
4166 mlist[mlist.length] = right;
4167 mitem.nuc = jsMath.Box.SetList(mlist,style,size);
4168 mitem.type = 'ord'; mitem.atom = 1;
4169 delete mitem.num; delete mitem.den;
4170 jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
4174 * Add subscripts and superscripts. (Rules 17-18f)
4176 SupSub: function (style,size,mitem) {
4177 var TeX = jsMath.Typeset.TeX(style,size);
4178 var nuc = mitem.nuc;
4179 var box = mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size,0);
4180 if (box.format == 'null')
4181 {box = mitem.nuc = jsMath.Box.Text('','normal',style,size)}
4183 if (nuc.type == 'TeX') {
4184 if (!mitem.textsymbol) {
4185 var C = jsMath.TeX[nuc.font][nuc.c];
4187 mitem.delta = C.ic * TeX.scale;
4189 box = mitem.nuc = jsMath.Box.SetList([box,jsMath.Box.Space(mitem.delta)],style,size);
4193 } else {mitem.delta = 0}
4196 if (!mitem.sup && !mitem.sub) return;
4199 var Cd = jsMath.Typeset.DownStyle(style);
4200 var Cu = jsMath.Typeset.UpStyle(style);
4201 var q = jsMath.Typeset.TeX(Cu,size).sup_drop;
4202 var r = jsMath.Typeset.TeX(Cd,size).sub_drop;
4203 var u = 0; var v = 0; var p;
4204 if (nuc.type && nuc.type != 'text' && nuc.type != 'TeX' && nuc.type != 'null')
4205 {u = box.h - q; v = box.d + r}
4208 var sub = jsMath.Box.Set(mitem.sub,Cd,size);
4209 sub = jsMath.Box.SetList([sub,jsMath.mItem.Space(TeX.scriptspace)],style,size);
4213 sub.y = -Math.max(v,TeX.sub1,sub.h-(4/5)*jsMath.Typeset.TeX(Cd,size).x_height);
4214 mitem.nuc = jsMath.Box.SetList([box,sub],style,size).Styled(); delete mitem.sub;
4218 var sup = jsMath.Box.Set(mitem.sup,Cu,size);
4219 sup = jsMath.Box.SetList([sup,jsMath.mItem.Space(TeX.scriptspace)],style,size);
4220 if (style == 'D') {p = TeX.sup1}
4221 else if (style.charAt(style.length-1) == "'") {p = TeX.sup3}
4223 u = Math.max(u,p,sup.d+jsMath.Typeset.TeX(Cu,size).x_height/4);
4227 mitem.nuc = jsMath.Box.SetList([box,sup],style,size); delete mitem.sup;
4231 v = Math.max(v,jsMath.Typeset.TeX(Cd,size).sub2);
4232 var t = TeX.default_rule_thickness;
4233 if ((u-sup.d) - (sub.h -v) < 4*t) {
4234 v = 4*t + sub.h - (u-sup.d);
4235 p = (4/5)*TeX.x_height - (u-sup.d);
4236 if (p > 0) {u += p; v -= p}
4238 sup.Remeasured(); sub.Remeasured();
4239 sup.y = u; sub.y = -v; sup.x = mitem.delta;
4240 if (sup.w+sup.x > sub.w)
4241 {sup.x -= sub.w; mitem.nuc = jsMath.Box.SetList([box,sub,sup],style,size)} else
4242 {sub.x -= (sup.w+sup.x); mitem.nuc = jsMath.Box.SetList([box,sup,sub],style,size)}
4244 delete mitem.sup; delete mitem.sub;
4250 /***************************************************************************/
4253 * The Typeset object handles most of the TeX-specific processing
4256 jsMath.Typeset = function (mlist) {
4257 this.type = 'typeset';
4261 jsMath.Add(jsMath.Typeset,{
4264 * The "C-uparrow" style table (TeXbook, p. 441)
4267 D: "S", T: "S", "D'": "S'", "T'": "S'",
4268 S: "SS", SS: "SS", "S'": "SS'", "SS'": "SS'"
4272 * The "C-downarrow" style table (TeXbook, p. 441)
4275 D: "S'", T: "S'", "D'": "S'", "T'": "S'",
4276 S: "SS'", SS: "SS'", "S'": "SS'", "SS'": "SS'"
4280 * Get the various styles given the current style
4281 * (see TeXbook, p. 441)
4283 UpStyle: function (style) {return this.upStyle[style]},
4284 DownStyle: function (style) {return this.downStyle[style]},
4285 PrimeStyle: function (style) {
4286 if (style.charAt(style.length-1) == "'") {return style}
4291 * A value scaled to the appropriate size for scripts
4293 StyleValue: function (style,v) {
4294 if (style == "S" || style == "S'") {return .7*v}
4295 if (style == "SS" || style == "SS'") {return .5*v}
4300 * Return the size associated with a given style and size
4302 StyleSize: function (style,size) {
4303 if (style == "S" || style == "S'") {size = Math.max(0,size-2)}
4304 else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}
4309 * Return the font parameter table for the given style
4311 TeX: function (style,size) {
4312 if (style == "S" || style == "S'") {size = Math.max(0,size-2)}
4313 else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}
4314 return jsMath.TeXparams[size];
4319 * Add the CSS class for the given TeX style
4321 AddStyle: function (style,size,html) {
4322 if (style == "S" || style == "S'") {size = Math.max(0,size-2)}
4323 else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}
4324 if (size != 4) {html = '<span class="size'+size+'">' + html + '</span>'}
4329 * Add the font class, if needed
4331 AddClass: function (tclass,html) {
4332 if (tclass != '' && tclass != 'normal') {html = jsMath.HTML.Class(tclass,html)}
4339 jsMath.Package(jsMath.Typeset,{
4342 * The spacing tables for inter-atom spacing
4343 * (See rule 20, and Chapter 18, p 170)
4346 ord: {op: 1, bin: 2, rel: 3, inner: 1},
4347 op: {ord: 1, op: 1, rel: 3, inner: 1},
4348 bin: {ord: 2, op: 2, open: 2, inner: 2},
4349 rel: {ord: 3, op: 3, open: 3, inner: 3},
4351 close: {op: 1, bin:2, rel: 3, inner: 1},
4352 punct: {ord: 1, op: 1, rel: 1, open: 1, close: 1, punct: 1, inner: 1},
4353 inner: {ord: 1, op: 1, bin: 2, rel: 3, open: 1, punct: 1, inner: 1}
4358 op: {ord: 1, op: 1},
4368 * The sizes used in the tables above
4370 sepW: ['','thinmuskip','medmuskip','thickmuskip'],
4374 * Find the amount of separation to use between two adjacent
4375 * atoms in the given style
4377 GetSeparation: function (l,r,style) {
4378 if (l && l.atom && r.atom) {
4379 var table = this.DTsep; if (style.charAt(0) == "S") {table = this.SSsep}
4380 var row = table[l.type];
4381 if (row && row[r.type] != null) {return jsMath.TeX[this.sepW[row[r.type]]]}
4387 * Typeset an mlist (i.e., turn it into HTML).
4388 * Here, text items of the same class and style are combined
4389 * to reduce the number of <SPAN> tags used (though it is still
4390 * huge). Spaces are combined, when possible.
4391 * ### More needs to be done with that. ###
4392 * The width of the final box is recomputed at the end, since
4393 * the final width is not necessarily the sum of the widths of
4394 * the individual parts (widths are in pixels, but the browsers
4395 * puts pieces together using sub-pixel accuracy).
4397 Typeset: function (style,size) {
4398 this.style = style; this.size = size; var unset = -10000
4399 this.w = 0; this.mw = 0; this.Mw = 0;
4400 this.h = unset; this.d = unset;
4401 this.bh = this.h; this.bd = this.d;
4402 this.tbuf = ''; this.tx = 0; this.tclass = '';
4403 this.cbuf = ''; this.hbuf = ''; this.hx = 0;
4404 var mitem = null; var prev; this.x = 0; this.dx = 0;
4406 for (var i = 0; i < this.mlist.length; i++) {
4407 prev = mitem; mitem = this.mlist[i];
4408 switch (mitem.type) {
4411 this.FlushClassed();
4412 this.size = mitem.size;
4413 mitem = prev; // hide this from TeX
4417 this.FlushClassed();
4418 if (this.style.charAt(this.style.length-1) == "'")
4419 {this.style = mitem.style + "'"} else {this.style = mitem.style}
4420 mitem = prev; // hide this from TeX
4424 if (typeof(mitem.w) == 'object') {
4425 if (this.style.charAt(1) == 'S') {mitem.w = .5*mitem.w[0]/18}
4426 else if (this.style.charAt(0) == 'S') {mitem.w = .7*mitem.w[0]/18}
4427 else {mitem.w = mitem.w[0]/18}
4429 this.dx += mitem.w-0; // mitem.w is sometimes a string?
4430 mitem = prev; // hide this from TeX
4434 this.FlushClassed();
4435 if (this.hbuf == '') {this.hx = this.x}
4436 this.hbuf += mitem.html;
4437 mitem = prev; // hide this from TeX
4441 if (!mitem.atom && mitem.type != 'box') break;
4442 mitem.nuc.x += this.dx + this.GetSeparation(prev,mitem,this.style);
4443 if (mitem.nuc.x || mitem.nuc.y) mitem.nuc.Styled();
4444 this.dx = 0; this.x = this.x + this.w;
4445 if (this.x + mitem.nuc.x + mitem.nuc.mw < this.mw)
4446 {this.mw = this.x + mitem.nuc.x + mitem.nuc.mw}
4447 if (this.w + mitem.nuc.x + mitem.nuc.Mw > this.Mw)
4448 {this.Mw = this.w + mitem.nuc.x + mitem.nuc.Mw}
4449 this.w += mitem.nuc.w + mitem.nuc.x;
4450 if (mitem.nuc.format == 'text') {
4451 if (this.tclass != mitem.nuc.tclass && this.tclass != '') this.FlushText();
4452 if (this.tbuf == '' && this.cbuf == '') {this.tx = this.x}
4453 this.tbuf += mitem.nuc.html; this.tclass = mitem.nuc.tclass;
4455 this.FlushClassed();
4456 if (mitem.nuc.x || mitem.nuc.y) this.Place(mitem.nuc);
4457 if (this.hbuf == '') {this.hx = this.x}
4458 this.hbuf += mitem.nuc.html;
4460 this.h = Math.max(this.h,mitem.nuc.h+mitem.nuc.y); this.bh = Math.max(this.bh,mitem.nuc.bh);
4461 this.d = Math.max(this.d,mitem.nuc.d-mitem.nuc.y); this.bd = Math.max(this.bd,mitem.nuc.bd);
4466 this.FlushClassed(); // make sure scaling is included
4468 this.hbuf += jsMath.HTML.Spacer(this.dx); this.w += this.dx;
4469 if (this.w > this.Mw) {this.Mw = this.w}
4470 if (this.w < this.mw) {this.mw = this.w}
4472 if (this.hbuf == '') {return jsMath.Box.Null()}
4473 if (this.h == unset) {this.h = 0}
4474 if (this.d == unset) {this.d = 0}
4475 var box = new jsMath.Box('html',this.hbuf,this.w,this.h,this.d);
4476 box.bh = this.bh; box.bd = this.bd;
4477 box.mw = this.mw; box.Mw = this.Mw;
4482 * Add the font to the buffered text and move it to the
4483 * classed-text buffer.
4485 FlushText: function () {
4486 if (this.tbuf == '') return;
4487 this.cbuf += jsMath.Typeset.AddClass(this.tclass,this.tbuf);
4488 this.tbuf = ''; this.tclass = '';
4492 * Add the script or scriptscript style to the text and
4493 * move it to the HTML buffer
4495 FlushClassed: function () {
4497 if (this.cbuf == '') return;
4498 if (this.hbuf == '') {this.hx = this.tx}
4499 this.hbuf += jsMath.Typeset.AddStyle(this.style,this.size,this.cbuf);
4504 * Add a <SPAN> to position an item's HTML, and
4505 * adjust the item's height and depth.
4506 * (This may be replaced buy one of the following browser-specific
4507 * versions by Browser.Init().)
4509 Place: function (item) {
4510 var html = '<span style="position: relative;';
4511 if (item.x) {html += ' margin-left:'+jsMath.HTML.Em(item.x)+';'}
4512 if (item.y) {html += ' top:'+jsMath.HTML.Em(-item.y)+';'}
4513 item.html = html + '">' + item.html + '</span>';
4514 item.h += item.y; item.d -= item.y;
4515 item.x = 0; item.y = 0;
4519 * For MSIE on Windows, backspacing must be done in a separate
4520 * <SPAN>, otherwise the contents will be clipped. Netscape
4521 * also doesn't combine vertical and horizontal spacing well.
4522 * Here, the horizontal and vertical spacing are done separately.
4525 PlaceSeparateSkips: function (item) {
4527 var rw = item.Mw - item.w; var lw = item.mw;
4528 var W = item.Mw - item.mw;
4530 jsMath.HTML.Spacer(lw-rw) +
4531 '<span style="position: relative; '
4532 + 'top:'+jsMath.HTML.Em(-item.y)+'; '
4533 + 'left:'+jsMath.HTML.Em(rw)+'; width:'+jsMath.HTML.Em(W)+';">' +
4534 jsMath.HTML.Spacer(-lw) +
4536 jsMath.HTML.Spacer(rw) +
4539 if (item.x) {item.html = jsMath.HTML.Spacer(item.x) + item.html}
4540 item.h += item.y; item.d -= item.y;
4541 item.x = 0; item.y = 0;
4548 /***************************************************************************/
4551 * The Parse object handles the parsing of the TeX input string, and creates
4552 * the mList to be typeset by the Typeset object above.
4555 jsMath.Parse = function (s,font,size,style) {
4556 var parse = new jsMath.Parser(s,font,size,style);
4561 jsMath.Parser = function (s,font,size,style) {
4562 this.string = s; this.i = 0;
4563 this.mlist = new jsMath.mList(null,font,size,style);
4566 jsMath.Package(jsMath.Parser,{
4568 // special characters
4573 // patterns for letters and numbers
4576 // pattern for macros to ^ and _ that should be read with arguments
4577 scriptargs: /^((math|text)..|mathcal|[hm]box)$/,
4579 // the \mathchar definitions (see Appendix B of the TeXbook).
4584 '*': [2,2,0x03], // \ast
4603 // handle special \catcode characters
4606 '^': 'HandleSuperscript',
4607 '_': 'HandleSubscript',
4614 '%': 'HandleComment',
4619 // the \mathchardef table (see Appendix B of the TeXbook).
4622 braceld: [0,3,0x7A],
4623 bracerd: [0,3,0x7B],
4624 bracelu: [0,3,0x7C],
4625 braceru: [0,3,0x7D],
4632 epsilon: [0,1,0x0F],
4646 upsilon: [0,1,0x1D],
4651 varepsilon: [0,1,0x22],
4652 vartheta: [0,1,0x23],
4655 varsigma: [0,1,0x26],
4665 Upsilon: [7,0,0x07],
4678 partial: [0,1,0x40],
4681 emptyset: [0,2,0x3B],
4686 triangle: [0,2,0x34],
4692 natural: [0,1,0x5C],
4694 clubsuit: [0,2,0x7C],
4695 diamondsuit: [0,2,0x7D],
4696 heartsuit: [0,2,0x7E],
4697 spadesuit: [0,2,0x7F],
4702 bigwedge: [1,3,0x56],
4703 biguplus: [1,3,0x55],
4709 bigotimes: [1,3,0x4E],
4710 bigoplus: [1,3,0x4C],
4711 bigodot: [1,3,0x4A],
4713 bigsqcup: [1,3,0x46],
4714 smallint: [1,2,0x73],
4716 // binary operations
4717 triangleleft: [2,1,0x2F],
4718 triangleright: [2,1,0x2E],
4719 bigtriangleup: [2,2,0x34],
4720 bigtriangledown: [2,2,0x35],
4727 ddagger: [2,2,0x7A],
4733 diamond: [2,2,0x05],
4745 bigcirc: [2,2,0x0D],
4746 setminus: [2,2,0x6E], // for set difference A\setminus B
4754 sqsubseteq: [3,2,0x76],
4755 sqsupseteq: [3,2,0x77],
4756 parallel: [3,2,0x6B],
4764 lt: [3,1,0x3C], // extra since < and > are hard
4765 gt: [3,1,0x3E], // to get in HTML
4773 supseteq: [3,2,0x13],
4774 subseteq: [3,2,0x12],
4790 Leftrightarrow: [3,2,0x2C],
4791 Leftarrow: [3,2,0x28],
4792 Rightarrow: [3,2,0x29],
4793 leftrightarrow: [3,2,0x24],
4794 leftarrow: [3,2,0x20],
4796 rightarrow: [3,2,0x21],
4798 mapstochar: [3,2,0x37],
4799 leftharpoonup: [3,1,0x28],
4800 leftharpoondown: [3,1,0x29],
4801 rightharpoonup: [3,1,0x2A],
4802 rightharpoondown: [3,1,0x2B],
4803 nearrow: [3,2,0x25],
4804 searrow: [3,2,0x26],
4805 nwarrow: [3,2,0x2D],
4806 swarrow: [3,2,0x2E],
4808 minuschar: [3,2,0x00], // for longmapsto
4809 hbarchar: [0,0,0x16], // for \hbar
4813 ldotp: [6,1,0x3A], // ldot as a punctuation mark
4814 cdotp: [6,2,0x01], // cdot as a punctuation mark
4815 colon: [6,0,0x3A], // colon as a punctuation mark
4823 // The delimiter table (see Appendix B of the TeXbook)
4825 '(': [0,0,0x28,3,0x00],
4826 ')': [0,0,0x29,3,0x01],
4827 '[': [0,0,0x5B,3,0x02],
4828 ']': [0,0,0x5D,3,0x03],
4829 '<': [0,2,0x68,3,0x0A],
4830 '>': [0,2,0x69,3,0x0B],
4831 '\\lt': [0,2,0x68,3,0x0A], // extra since < and > are
4832 '\\gt': [0,2,0x69,3,0x0B], // hard to get in HTML
4833 '/': [0,0,0x2F,3,0x0E],
4834 '|': [0,2,0x6A,3,0x0C],
4835 '.': [0,0,0x00,0,0x00],
4836 '\\': [0,2,0x6E,3,0x0F],
4837 '\\lmoustache': [4,3,0x7A,3,0x40], // top from (, bottom from )
4838 '\\rmoustache': [5,3,0x7B,3,0x41], // top from ), bottom from (
4839 '\\lgroup': [4,6,0x28,3,0x3A], // extensible ( with sharper tips
4840 '\\rgroup': [5,6,0x29,3,0x3B], // extensible ) with sharper tips
4841 '\\arrowvert': [0,2,0x6A,3,0x3C], // arrow without arrowheads
4842 '\\Arrowvert': [0,2,0x6B,3,0x3D], // double arrow without arrowheads
4843 // '\\bracevert': [0,7,0x7C,3,0x3E], // the vertical bar that extends braces
4844 '\\bracevert': [0,2,0x6A,3,0x3E], // we don't load tt, so use | instead
4845 '\\Vert': [0,2,0x6B,3,0x0D],
4846 '\\|': [0,2,0x6B,3,0x0D],
4847 '\\vert': [0,2,0x6A,3,0x0C],
4848 '\\uparrow': [3,2,0x22,3,0x78],
4849 '\\downarrow': [3,2,0x23,3,0x79],
4850 '\\updownarrow': [3,2,0x6C,3,0x3F],
4851 '\\Uparrow': [3,2,0x2A,3,0x7E],
4852 '\\Downarrow': [3,2,0x2B,3,0x7F],
4853 '\\Updownarrow': [3,2,0x6D,3,0x77],
4854 '\\backslash': [0,2,0x6E,3,0x0F], // for double coset G\backslash H
4855 '\\rangle': [5,2,0x69,3,0x0B],
4856 '\\langle': [4,2,0x68,3,0x0A],
4857 '\\rbrace': [5,2,0x67,3,0x09],
4858 '\\lbrace': [4,2,0x66,3,0x08],
4859 '\\}': [5,2,0x67,3,0x09],
4860 '\\{': [4,2,0x66,3,0x08],
4861 '\\rceil': [5,2,0x65,3,0x07],
4862 '\\lceil': [4,2,0x64,3,0x06],
4863 '\\rfloor': [5,2,0x63,3,0x05],
4864 '\\lfloor': [4,2,0x62,3,0x04],
4865 '\\lbrack': [0,0,0x5B,3,0x02],
4866 '\\rbrack': [0,0,0x5D,3,0x03]
4870 * The basic macros for plain TeX.
4872 * When the control sequence on the left is called, the JavaScript
4873 * funtion on the right is called, with the name of the control sequence
4874 * as its first parameter (this way, the same function can be called by
4875 * several different control sequences to do similar actions, and the
4876 * function can still tell which TeX command was issued). If the right
4877 * is an array, the first entry is the routine to call, and the
4878 * remaining entries in the array are parameters to pass to the function
4879 * as the second parameter (they are in an array reference).
4881 * Note: TeX macros as defined by the user are discussed below.
4884 displaystyle: ['HandleStyle','D'],
4885 textstyle: ['HandleStyle','T'],
4886 scriptstyle: ['HandleStyle','S'],
4887 scriptscriptstyle: ['HandleStyle','SS'],
4889 rm: ['HandleFont',0],
4890 mit: ['HandleFont',1],
4891 oldstyle: ['HandleFont',1],
4892 cal: ['HandleFont',2],
4893 it: ['HandleFont',4],
4894 bf: ['HandleFont',6],
4896 font: ['Extension','font'],
4899 right: 'HandleRight',
4901 arcsin: ['NamedOp',0],
4902 arccos: ['NamedOp',0],
4903 arctan: ['NamedOp',0],
4906 cosh: ['NamedOp',0],
4908 coth: ['NamedOp',0],
4920 liminf: ['NamedOp',null,'lim<span style="margin-left: '+1/6+'em"></span>inf'],
4921 limsup: ['NamedOp',null,'lim<span style="margin-left: '+1/6+'em"></span>sup'],
4929 sinh: ['NamedOp',0],
4932 tanh: ['NamedOp',0],
4934 vcenter: ['HandleAtom','vcenter'],
4935 overline: ['HandleAtom','overline'],
4936 underline: ['HandleAtom','underline'],
4938 overwithdelims: 'HandleOver',
4940 atopwithdelims: 'HandleOver',
4941 above: 'HandleOver',
4942 abovewithdelims: 'HandleOver',
4943 brace: ['HandleOver','\\{','\\}'],
4944 brack: ['HandleOver','[',']'],
4945 choose: ['HandleOver','(',')'],
4947 overbrace: ['Extension','leaders'],
4948 underbrace: ['Extension','leaders'],
4949 overrightarrow: ['Extension','leaders'],
4950 underrightarrow: ['Extension','leaders'],
4951 overleftarrow: ['Extension','leaders'],
4952 underleftarrow: ['Extension','leaders'],
4953 overleftrightarrow: ['Extension','leaders'],
4954 underleftrightarrow: ['Extension','leaders'],
4955 overset: ['Extension','underset-overset'],
4956 underset: ['Extension','underset-overset'],
4962 raise: 'RaiseLower',
4963 lower: 'RaiseLower',
4964 moveleft: 'MoveLeftRight',
4965 moveright: 'MoveLeftRight',
4971 // TeX substitution macros
4972 hbar: ['Macro','\\hbarchar\\kern-.5em h'],
4973 ne: ['Macro','\\not='],
4974 neq: ['Macro','\\not='],
4975 notin: ['Macro','\\mathrel{\\rlap{\\kern2mu/}}\\in'],
4976 cong: ['Macro','\\mathrel{\\lower2mu{\\mathrel{{\\rlap{=}\\raise6mu\\sim}}}}'],
4977 bmod: ['Macro','\\mathbin{\\rm mod}'],
4978 pmod: ['Macro','\\kern 18mu ({\\rm mod}\\,\\,#1)',1],
4979 'int': ['Macro','\\intop\\nolimits'],
4980 oint: ['Macro','\\ointop\\nolimits'],
4981 doteq: ['Macro','\\buildrel\\textstyle.\\over='],
4982 ldots: ['Macro','\\mathinner{\\ldotp\\ldotp\\ldotp}'],
4983 cdots: ['Macro','\\mathinner{\\cdotp\\cdotp\\cdotp}'],
4984 vdots: ['Macro','\\mathinner{\\rlap{\\raise8pt{.\\rule 0pt 6pt 0pt}}\\rlap{\\raise4pt{.}}.}'],
4985 ddots: ['Macro','\\mathinner{\\kern1mu\\raise7pt{\\rule 0pt 7pt 0pt .}\\kern2mu\\raise4pt{.}\\kern2mu\\raise1pt{.}\\kern1mu}'],
4986 joinrel: ['Macro','\\mathrel{\\kern-4mu}'],
4987 relbar: ['Macro','\\mathrel{\\smash-}'], // \smash, because - has the same height as +
4988 Relbar: ['Macro','\\mathrel='],
4989 bowtie: ['Macro','\\mathrel\\triangleright\\joinrel\\mathrel\\triangleleft'],
4990 models: ['Macro','\\mathrel|\\joinrel='],
4991 mapsto: ['Macro','\\mathrel{\\mapstochar\\rightarrow}'],
4992 rightleftharpoons: ['Macro','\\vcenter{\\mathrel{\\rlap{\\raise3mu{\\rightharpoonup}}}\\leftharpoondown}'],
4993 hookrightarrow: ['Macro','\\lhook\\joinrel\\rightarrow'],
4994 hookleftarrow: ['Macro','\\leftarrow\\joinrel\\rhook'],
4995 Longrightarrow: ['Macro','\\Relbar\\joinrel\\Rightarrow'],
4996 longrightarrow: ['Macro','\\relbar\\joinrel\\rightarrow'],
4997 longleftarrow: ['Macro','\\leftarrow\\joinrel\\relbar'],
4998 Longleftarrow: ['Macro','\\Leftarrow\\joinrel\\Relbar'],
4999 longmapsto: ['Macro','\\mathrel{\\mapstochar\\minuschar\\joinrel\\rightarrow}'],
5000 longleftrightarrow: ['Macro','\\leftarrow\\joinrel\\rightarrow'],
5001 Longleftrightarrow: ['Macro','\\Leftarrow\\joinrel\\Rightarrow'],
5002 iff: ['Macro','\\;\\Longleftrightarrow\\;'],
5003 mathcal: ['Macro','{\\cal #1}',1],
5004 mathrm: ['Macro','{\\rm #1}',1],
5005 mathbf: ['Macro','{\\bf #1}',1],
5006 mathbb: ['Macro','{\\bf #1}',1],
5007 mathit: ['Macro','{\\it #1}',1],
5008 textrm: ['Macro','\\mathord{\\hbox{#1}}',1],
5009 textit: ['Macro','\\mathord{\\class{textit}{\\hbox{#1}}}',1],
5010 textbf: ['Macro','\\mathord{\\class{textbf}{\\hbox{#1}}}',1],
5011 pmb: ['Macro','\\rlap{#1}\\kern1px{#1}',1],
5013 TeX: ['Macro','T\\kern-.1667em\\lower.5ex{E}\\kern-.125em X'],
5015 limits: ['Limits',1],
5016 nolimits: ['Limits',0],
5018 ',': ['Spacer',1/6],
5019 ':': ['Spacer',1/6], // for LaTeX
5020 '>': ['Spacer',2/9],
5021 ';': ['Spacer',5/18],
5022 '!': ['Spacer',-1/6],
5023 enspace: ['Spacer',1/2],
5025 qquad: ['Spacer',2],
5026 thinspace: ['Spacer',1/6],
5027 negthinspace: ['Spacer',-1/6],
5031 rule: ['Rule','colored'],
5032 space: ['Rule','blank'],
5034 big: ['MakeBig','ord',0.85],
5035 Big: ['MakeBig','ord',1.15],
5036 bigg: ['MakeBig','ord',1.45],
5037 Bigg: ['MakeBig','ord',1.75],
5038 bigl: ['MakeBig','open',0.85],
5039 Bigl: ['MakeBig','open',1.15],
5040 biggl: ['MakeBig','open',1.45],
5041 Biggl: ['MakeBig','open',1.75],
5042 bigr: ['MakeBig','close',0.85],
5043 Bigr: ['MakeBig','close',1.15],
5044 biggr: ['MakeBig','close',1.45],
5045 Biggr: ['MakeBig','close',1.75],
5046 bigm: ['MakeBig','rel',0.85],
5047 Bigm: ['MakeBig','rel',1.15],
5048 biggm: ['MakeBig','rel',1.45],
5049 Biggm: ['MakeBig','rel',1.75],
5051 mathord: ['HandleAtom','ord'],
5052 mathop: ['HandleAtom','op'],
5053 mathopen: ['HandleAtom','open'],
5054 mathclose: ['HandleAtom','close'],
5055 mathbin: ['HandleAtom','bin'],
5056 mathrel: ['HandleAtom','rel'],
5057 mathpunct: ['HandleAtom','punct'],
5058 mathinner: ['HandleAtom','inner'],
5060 mathchoice: ['Extension','mathchoice'],
5061 buildrel: 'BuildRel',
5066 fbox: ['Extension','fbox'],
5069 mathstrut: ['Macro','\\vphantom{(}'],
5070 phantom: ['Phantom',1,1],
5071 vphantom: ['Phantom',1,0],
5072 hphantom: ['Phantom',0,1],
5075 acute: ['MathAccent', [7,0,0x13]],
5076 grave: ['MathAccent', [7,0,0x12]],
5077 ddot: ['MathAccent', [7,0,0x7F]],
5078 tilde: ['MathAccent', [7,0,0x7E]],
5079 bar: ['MathAccent', [7,0,0x16]],
5080 breve: ['MathAccent', [7,0,0x15]],
5081 check: ['MathAccent', [7,0,0x14]],
5082 hat: ['MathAccent', [7,0,0x5E]],
5083 vec: ['MathAccent', [0,1,0x7E]],
5084 dot: ['MathAccent', [7,0,0x5F]],
5085 widetilde: ['MathAccent', [0,3,0x65]],
5086 widehat: ['MathAccent', [0,3,0x62]],
5088 '_': ['Replace','ord','_','normal',-.4,.1],
5089 ' ': ['Replace','ord',' ','normal'],
5090 // angle: ['Replace','ord','∠','normal'],
5091 angle: ['Macro','\\kern2.5mu\\raise1.54pt{\\rlap{\\scriptstyle \\char{cmsy10}{54}}\\kern1pt\\rule{.45em}{-1.2pt}{1.54pt}\\kern2.5mu}'],
5094 array: 'Matrix', // ### still need to do alignment options ###
5095 pmatrix: ['Matrix','(',')','c'],
5096 cases: ['Matrix','\\{','.',['l','l'],null,2],
5097 eqalign: ['Matrix',null,null,['r','l'],[5/18],3,'D'],
5098 displaylines: ['Matrix',null,null,['c'],null,3,'D'],
5101 newline: 'HandleRow',
5102 noalign: 'HandleNoAlign',
5103 eqalignno: ['Matrix',null,null,['r','l','r'],[5/8,3],3,'D'],
5104 leqalignno: ['Matrix',null,null,['r','l','r'],[5/8,3],3,'D'],
5109 tiny: ['HandleSize',0],
5110 Tiny: ['HandleSize',1], // non-standard
5111 scriptsize: ['HandleSize',2],
5112 small: ['HandleSize',3],
5113 normalsize: ['HandleSize',4],
5114 large: ['HandleSize',5],
5115 Large: ['HandleSize',6],
5116 LARGE: ['HandleSize',7],
5117 huge: ['HandleSize',8],
5118 Huge: ['HandleSize',9],
5119 dots: ['Macro','\\ldots'],
5121 newcommand: ['Extension','newcommand'],
5122 newenvironment: ['Extension','newcommand'],
5123 def: ['Extension','newcommand'],
5125 // Extensions to TeX
5126 color: ['Extension','HTML'],
5127 href: ['Extension','HTML'],
5128 'class': ['Extension','HTML'],
5129 style: ['Extension','HTML'],
5130 cssId: ['Extension','HTML'],
5131 unicode: ['Extension','HTML'],
5132 bbox: ['Extension','bbox'],
5136 // debugging and test routines
5141 * LaTeX environments
5145 matrix: ['Array',null,null,'c'],
5146 pmatrix: ['Array','(',')','c'],
5147 bmatrix: ['Array','[',']','c'],
5148 Bmatrix: ['Array','\\{','\\}','c'],
5149 vmatrix: ['Array','\\vert','\\vert','c'],
5150 Vmatrix: ['Array','\\Vert','\\Vert','c'],
5151 cases: ['Array','\\{','.','ll',null,2],
5152 eqnarray: ['Array',null,null,'rcl',[5/18,5/18],3,'D'],
5153 'eqnarray*': ['Array',null,null,'rcl',[5/18,5/18],3,'D'],
5154 equation: 'Equation',
5155 'equation*': 'Equation',
5157 align: ['Extension','AMSmath'],
5158 'align*': ['Extension','AMSmath'],
5159 aligned: ['Extension','AMSmath'],
5160 multline: ['Extension','AMSmath'],
5161 'multline*': ['Extension','AMSmath'],
5162 split: ['Extension','AMSmath'],
5163 gather: ['Extension','AMSmath'],
5164 'gather*': ['Extension','AMSmath'],
5165 gathered: ['Extension','AMSmath']
5169 /***************************************************************************/
5172 * Add special characters to list above. (This makes it possible
5173 * to define them in a variable that the user can change.)
5175 AddSpecial: function (obj) {
5176 for (var id in obj) {
5177 jsMath.Parser.prototype.special[jsMath.Parser.prototype[id]] = obj[id];
5184 Error: function (s) {
5185 this.i = this.string.length;
5186 if (s.error) {this.error = s.error} else {
5187 if (!this.error) {this.error = s}
5191 /***************************************************************************/
5194 * Check if the next character is a space
5196 nextIsSpace: function () {
5197 return this.string.charAt(this.i).match(/[ \n\r\t]/);
5201 * Trim spaces from a string
5203 trimSpaces: function (text) {
5204 if (typeof(text) != 'string') {return text}
5205 return text.replace(/^\s+|\s+$/g,'');
5209 * Parse a substring to get its mList, and return it.
5210 * Check that no errors occured
5212 Process: function (arg) {
5213 var data = this.mlist.data;
5214 arg = jsMath.Parse(arg,data.font,data.size,data.style);
5215 if (arg.error) {this.Error(arg); return null}
5216 if (arg.mlist.Length() == 0) {return null}
5217 if (arg.mlist.Length() == 1) {
5218 var atom = arg.mlist.Last();
5219 if (atom.atom && atom.type == 'ord' && atom.nuc &&
5220 !atom.sub && !atom.sup && (atom.nuc.type == 'text' || atom.nuc.type == 'TeX'))
5223 return {type: 'mlist', mlist: arg.mlist};
5227 * Get and return a control-sequence name from the TeX string
5229 GetCommand: function () {
5230 var letter = /^([a-z]+|.) ?/i;
5231 var cmd = letter.exec(this.string.slice(this.i));
5232 if (cmd) {this.i += cmd[1].length; return cmd[1]}
5233 this.i++; return " ";
5237 * Get and return a TeX argument (either a single character or control sequence,
5238 * or the contents of the next set of braces).
5240 GetArgument: function (name,noneOK) {
5241 while (this.nextIsSpace()) {this.i++}
5242 if (this.i >= this.string.length) {if (!noneOK) this.Error("Missing argument for "+name); return null}
5243 if (this.string.charAt(this.i) == this.close) {if (!noneOK) this.Error("Extra close brace"); return null}
5244 if (this.string.charAt(this.i) == this.cmd) {this.i++; return this.cmd+this.GetCommand()}
5245 if (this.string.charAt(this.i) != this.open) {return this.string.charAt(this.i++)}
5246 var j = ++this.i; var pcount = 1; var c = '';
5247 while (this.i < this.string.length) {
5248 c = this.string.charAt(this.i++);
5249 if (c == this.cmd) {this.i++}
5250 else if (c == this.open) {pcount++}
5251 else if (c == this.close) {
5252 if (pcount == 0) {this.Error("Extra close brace"); return null}
5253 if (--pcount == 0) {return this.string.slice(j,this.i-1)}
5256 this.Error("Missing close brace");
5261 * Get an argument and process it into an mList
5263 ProcessArg: function (name) {
5264 var arg = this.GetArgument(name); if (this.error) {return null}
5265 return this.Process(arg);
5269 * Get and process an argument for a super- or subscript.
5270 * (read extra args for \frac, \sqrt, \mathrm, etc.)
5271 * This handles these macros as special cases, so is really
5272 * rather a hack. A more general method for indicating
5273 * how to handle macros in scripts needs to be developed.
5275 ProcessScriptArg: function (name) {
5276 var arg = this.GetArgument(name); if (this.error) {return null}
5277 if (arg.charAt(0) == this.cmd) {
5278 var csname = arg.substr(1);
5279 if (csname == "frac") {
5280 arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
5281 arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
5282 } else if (csname == "sqrt") {
5283 arg += '['+this.GetBrackets(csname)+']'; if (this.error) {return null}
5284 arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
5285 } else if (csname.match(this.scriptargs)) {
5286 arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
5289 return this.Process(arg);
5293 * Get the name of a delimiter (check it in the delimiter list).
5295 GetDelimiter: function (name) {
5296 while (this.nextIsSpace()) {this.i++}
5297 var c = this.string.charAt(this.i);
5298 if (this.i < this.string.length) {
5300 if (c == this.cmd) {c = '\\'+this.GetCommand(name); if (this.error) return null}
5301 if (this.delimiter[c] != null) {return this.delimiter[c]}
5303 this.Error("Missing or unrecognized delimiter for "+name);
5308 * Get a dimension (including its units).
5309 * Convert the dimen to em's, except for mu's, which must be
5310 * converted when typeset.
5312 GetDimen: function (name,nomu) {
5313 var rest; var advance = 0;
5314 if (this.nextIsSpace()) {this.i++}
5315 if (this.string.charAt(this.i) == '{') {
5316 rest = this.GetArgument(name);
5318 rest = this.string.slice(this.i);
5321 return this.ParseDimen(rest,name,advance,nomu);
5324 ParseDimen: function (dimen,name,advance,nomu) {
5325 var match = dimen.match(/^\s*([-+]?(\.\d+|\d+(\.\d*)?))(pt|em|ex|mu|px)/);
5326 if (!match) {this.Error("Missing dimension or its units for "+name); return null}
5328 this.i += match[0].length;
5329 if (this.nextIsSpace()) {this.i++}
5332 if (match[4] == 'px') {d /= jsMath.em}
5333 else if (match[4] == 'pt') {d /= 10}
5334 else if (match[4] == 'ex') {d *= jsMath.TeX.x_height}
5335 else if (match[4] == 'mu') {if (nomu) {d = d/18} else {d = [d,'mu']}}
5340 * Get the next non-space character
5342 GetNext: function () {
5343 while (this.nextIsSpace()) {this.i++}
5344 return this.string.charAt(this.i);
5348 * Get an optional LaTeX argument in brackets
5350 GetBrackets: function (name) {
5351 var c = this.GetNext(); if (c != '[') return '';
5352 var start = ++this.i; var pcount = 0;
5353 while (this.i < this.string.length) {
5354 c = this.string.charAt(this.i++);
5355 if (c == '{') {pcount++}
5356 else if (c == '}') {
5358 {this.Error("Extra close brace while looking for ']'"); return null}
5360 } else if (c == this.cmd) {
5362 } else if (c == ']') {
5363 if (pcount == 0) {return this.string.slice(start,this.i-1)}
5366 this.Error("Couldn't find closing ']' for argument to "+this.cmd+name);
5371 * Get everything up to the given control sequence name (token)
5373 GetUpto: function (name,token) {
5374 while (this.nextIsSpace()) {this.i++}
5375 var start = this.i; var pcount = 0;
5376 while (this.i < this.string.length) {
5377 var c = this.string.charAt(this.i++);
5378 if (c == '{') {pcount++}
5379 else if (c == '}') {
5381 {this.Error("Extra close brace while looking for "+this.cmd+token); return null}
5383 } else if (c == this.cmd) {
5384 // really need separate counter for begin/end
5385 // and it should really be a stack (new pcount for each begin)
5386 if (this.string.slice(this.i,this.i+5) == "begin") {pcount++; this.i+=4}
5387 else if (this.string.slice(this.i,this.i+3) == "end") {
5388 if (pcount > 0) {pcount--; this.i += 2}
5391 if (this.string.slice(this.i,this.i+token.length) == token) {
5392 c = this.string.charAt(this.i+token.length);
5393 if (c.match(/[^a-z]/i) || !token.match(/[a-z]/i)) {
5394 var arg = this.string.slice(start,this.i-1);
5395 this.i += token.length;
5403 this.Error("Couldn't find "+this.cmd+token+" for "+name);
5408 * Get a parameter delimited by a control sequence, and
5409 * process it to get its mlist
5411 ProcessUpto: function (name,token) {
5412 var arg = this.GetUpto(name,token); if (this.error) return null;
5413 return this.Process(arg);
5417 * Get everything up to \end{env}
5419 GetEnd: function (env) {
5420 var body = ''; var name = '';
5421 while (name != env) {
5422 body += this.GetUpto('begin{'+env+'}','end'); if (this.error) return null;
5423 name = this.GetArgument(this.cmd+'end'); if (this.error) return null;
5429 /***************************************************************************/
5435 Space: function () {},
5438 * Collect together any primes and convert them to a superscript
5440 Prime: function (c) {
5441 var base = this.mlist.Last();
5442 if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))
5443 {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
5444 if (base.sup) {this.Error("Prime causes double exponent: use braces to clarify"); return}
5446 while (c == "'") {sup += this.cmd+'prime'; c = this.GetNext(); if (c == "'") {this.i++}}
5447 base.sup = this.Process(sup);
5448 base.sup.isPrime = 1;
5452 * Raise or lower its parameter by a given amount
5453 * @@@ Note that this is different from TeX, which requires an \hbox @@@
5454 * ### make this work with mu's ###
5456 RaiseLower: function (name) {
5457 var h = this.GetDimen(this.cmd+name,1); if (this.error) return;
5458 var box = this.ProcessScriptArg(this.cmd+name); if (this.error) return;
5459 if (name == 'lower') {h = -h}
5460 this.mlist.Add(new jsMath.mItem('raise',{nuc: box, raise: h}));
5464 * Shift an expression to the right or left
5465 * @@@ Note that this is different from TeX, which requires a \vbox @@@
5466 * ### make this work with mu's ###
5468 MoveLeftRight: function (name) {
5469 var x = this.GetDimen(this.cmd+name,1); if (this.error) return;
5470 var box = this.ProcessScriptArg(this.cmd+name); if (this.error) return;
5471 if (name == 'moveleft') {x = -x}
5472 this.mlist.Add(jsMath.mItem.Space(x));
5473 this.mlist.Add(jsMath.mItem.Atom('ord',box));
5474 this.mlist.Add(jsMath.mItem.Space(-x));
5478 * Load an extension if it has not already been loaded
5480 Require: function (name) {
5481 var file = this.GetArgument(this.cmd+name); if (this.error) return;
5482 file = jsMath.Extension.URL(file);
5483 if (jsMath.Setup.loaded[file]) return;
5484 this.Extension(null,[file]);
5488 * Load an extension file and restart processing the math
5490 Extension: function (name,data) {
5491 jsMath.Translate.restart = 1;
5492 if (name != null) {delete jsMath.Parser.prototype[data[1]||'macros'][name]}
5493 jsMath.Extension.Require(data[0],jsMath.Translate.asynchronous);
5498 * Implements \frac{num}{den}
5500 Frac: function (name) {
5501 var num = this.ProcessArg(this.cmd+name); if (this.error) return;
5502 var den = this.ProcessArg(this.cmd+name); if (this.error) return;
5503 this.mlist.Add(jsMath.mItem.Fraction('over',num,den));
5507 * Implements \sqrt[n]{...}
5509 Sqrt: function (name) {
5510 var n = this.GetBrackets(this.cmd+name); if (this.error) return;
5511 var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
5512 var box = jsMath.mItem.Atom('radical',arg);
5513 if (n != '') {box.root = this.Process(n); if (this.error) return}
5514 this.mlist.Add(box);
5518 * Implements \root...\of{...}
5520 Root: function (name) {
5521 var n = this.ProcessUpto(this.cmd+name,'of'); if (this.error) return;
5522 var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
5523 var box = jsMath.mItem.Atom('radical',arg);
5524 box.root = n; this.mlist.Add(box);
5529 * Implements \buildrel...\over{...}
5531 BuildRel: function (name) {
5532 var top = this.ProcessUpto(this.cmd+name,'over'); if (this.error) return;
5533 var bot = this.ProcessArg(this.cmd+name); if (this.error) return;
5534 var op = jsMath.mItem.Atom('op',bot);
5535 op.limits = 1; op.sup = top;
5540 * Create a delimiter of the type and size specified in the parameters
5542 MakeBig: function (name,data) {
5543 var type = data[0]; var h = data[1] * jsMath.p_height;
5544 var delim = this.GetDelimiter(this.cmd+name); if (this.error) return;
5545 this.mlist.Add(jsMath.mItem.Atom(type,jsMath.Box.Delimiter(h,delim,'T')));
5549 * Insert the specified character in the given font.
5550 * (Try to load the font if it is not already available.)
5552 Char: function (name) {
5553 var font = this.GetArgument(this.cmd+name); if (this.error) return;
5554 var n = this.GetArgument(this.cmd+name); if (this.error) return;
5555 if (!jsMath.TeX[font]) {
5556 jsMath.TeX[font] = [];
5557 this.Extension(null,[jsMath.Font.URL(font)]);
5559 this.mlist.Add(jsMath.mItem.Typeset(jsMath.Box.TeX(n-0,font,this.mlist.data.style,this.mlist.data.size)));
5564 * Create an array or matrix.
5566 Matrix: function (name,delim) {
5567 var data = this.mlist.data;
5568 var arg = this.GetArgument(this.cmd+name); if (this.error) return;
5569 var parse = new jsMath.Parser(arg+this.cmd+'\\',null,data.size,delim[5] || 'T');
5570 parse.matrix = name; parse.row = []; parse.table = []; parse.rspacing = [];
5571 parse.Parse(); if (parse.error) {this.Error(parse); return}
5572 parse.HandleRow(name,1); // be sure the last row is recorded
5573 var box = jsMath.Box.Layout(data.size,parse.table,delim[2]||null,delim[3]||null,parse.rspacing,delim[4]||null);
5574 // Add parentheses, if needed
5575 if (delim[0] && delim[1]) {
5576 var left = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[0]],'T');
5577 var right = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[1]],'T');
5578 box = jsMath.Box.SetList([left,box,right],data.style,data.size);
5580 this.mlist.Add(jsMath.mItem.Atom((delim[0]? 'inner': 'ord'),box));
5584 * When we see an '&', try to add a matrix entry to the row data.
5585 * (Use all the data in the current mList, and then clear it)
5587 HandleEntry: function (name) {
5589 {this.Error(name+" can only appear in a matrix or array"); return}
5590 if (this.mlist.data.openI != null) {
5591 var open = this.mlist.Get(this.mlist.data.openI);
5592 if (open.left) {this.Error("Missing "+this.cmd+"right")}
5593 else {this.Error("Missing close brace")}
5595 if (this.mlist.data.overI != null) {this.mlist.Over()}
5596 var data = this.mlist.data;
5597 this.mlist.Atomize(data.style,data.size);
5598 var box = this.mlist.Typeset(data.style,data.size);
5599 box.entry = data.entry; delete data.entry; if (!box.entry) {box.entry = {}};
5600 this.row[this.row.length] = box;
5601 this.mlist = new jsMath.mList(null,null,data.size,data.style);
5605 * When we see a \cr or \\, try to add a row to the table
5607 HandleRow: function (name,last) {
5609 if (!this.matrix) {this.Error(this.cmd+name+" can only appear in a matrix or array"); return}
5611 dimen = this.GetBrackets(this.cmd+name); if (this.error) return;
5612 if (dimen) {dimen = this.ParseDimen(dimen,this.cmd+name,0,1)}
5614 this.HandleEntry(name);
5615 if (!last || this.row.length > 1 || this.row[0].format != 'null')
5616 {this.table[this.table.length] = this.row}
5617 if (dimen) {this.rspacing[this.table.length] = dimen}
5622 * Look for \vskip or \vspace in \noalign parameters
5624 HandleNoAlign: function (name) {
5625 var arg = this.GetArgument(this.cmd+name); if (this.error) return;
5626 var skip = arg.replace(/^.*(vskip|vspace)([^a-z])/i,'$2');
5627 if (skip.length == arg.length) return;
5628 var d = this.ParseDimen(skip,this.cmd+RegExp.$1,0,1); if (this.error) return;
5629 this.rspacing[this.table.length] = (this.rspacing[this.table.length] || 0) + d;
5633 * LaTeX array environment
5635 Array: function (name,delim) {
5636 var columns = delim[2]; var cspacing = delim[3];
5638 columns = this.GetArgument(this.cmd+'begin{'+name+'}');
5639 if (this.error) return;
5641 columns = columns.replace(/[^clr]/g,'');
5642 columns = columns.split('');
5643 var data = this.mlist.data; var style = delim[5] || 'T';
5644 var arg = this.GetEnd(name); if (this.error) return;
5645 var parse = new jsMath.Parser(arg+this.cmd+'\\',null,data.size,style);
5646 parse.matrix = name; parse.row = []; parse.table = []; parse.rspacing = [];
5647 parse.Parse(); if (parse.error) {this.Error(parse); return}
5648 parse.HandleRow(name,1); // be sure the last row is recorded
5649 var box = jsMath.Box.Layout(data.size,parse.table,columns,cspacing,parse.rspacing,delim[4],delim[6],delim[7]);
5650 // Add parentheses, if needed
5651 if (delim[0] && delim[1]) {
5652 var left = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[0]],'T');
5653 var right = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[1]],'T');
5654 box = jsMath.Box.SetList([left,box,right],data.style,data.size);
5656 this.mlist.Add(jsMath.mItem.Atom((delim[0]? 'inner': 'ord'),box));
5662 Begin: function (name) {
5663 var env = this.GetArgument(this.cmd+name); if (this.error) return;
5664 if (env.match(/[^a-z*]/i)) {this.Error('Invalid environment name "'+env+'"'); return}
5665 if (!this.environments[env]) {this.Error('Unknown environment "'+env+'"'); return}
5666 var cmd = this.environments[env];
5667 if (typeof(cmd) == "string") {cmd = [cmd]}
5668 this[cmd[0]](env,cmd.slice(1));
5674 End: function (name) {
5675 var env = this.GetArgument(this.cmd+name); if (this.error) return;
5676 this.Error(this.cmd+name+'{'+env+'} without matching '+this.cmd+'begin');
5680 * LaTeX equation environment (just remove the environment)
5682 Equation: function (name) {
5683 var arg = this.GetEnd(name); if (this.error) return;
5684 this.string = arg+this.string.slice(this.i); this.i = 0;
5688 * Add a fixed amount of horizontal space
5690 Spacer: function (name,w) {
5691 this.mlist.Add(jsMath.mItem.Space(w-0));
5695 * Add horizontal space given by the argument
5697 Hskip: function (name) {
5698 var w = this.GetDimen(this.cmd+name); if (this.error) return;
5699 this.mlist.Add(jsMath.mItem.Space(w));
5703 * Typeset the argument as plain text rather than math.
5705 HBox: function (name) {
5706 var text = this.GetArgument(this.cmd+name); if (this.error) return;
5707 var box = jsMath.Box.InternalMath(text,this.mlist.data.size);
5708 this.mlist.Add(jsMath.mItem.Typeset(box));
5712 * Insert a rule of a particular width, height and depth
5713 * This replaces \hrule and \vrule
5714 * @@@ not a standard TeX command, and all three parameters must be given @@@
5716 Rule: function (name,style) {
5717 var w = this.GetDimen(this.cmd+name,1); if (this.error) return;
5718 var h = this.GetDimen(this.cmd+name,1); if (this.error) return;
5719 var d = this.GetDimen(this.cmd+name,1); if (this.error) return;
5721 if (h != 0) {h = Math.max(1.05/jsMath.em,h)}
5722 if (h == 0 || w == 0 || style == "blank")
5723 {html = jsMath.HTML.Blank(w,h)} else {html = jsMath.HTML.Rule(w,h)}
5725 html = '<span style="vertical-align:'+jsMath.HTML.Em(-d)+'">'
5728 this.mlist.Add(jsMath.mItem.Typeset(new jsMath.Box('html',html,w,h-d,d)));
5732 * Inserts an empty box of a specific height and depth
5734 Strut: function () {
5735 var size = this.mlist.data.size;
5736 var box = jsMath.Box.Text('','normal','T',size).Styled();
5737 box.bh = box.bd = 0; box.h = .8; box.d = .3; box.w = box.Mw = 0;
5738 this.mlist.Add(jsMath.mItem.Typeset(box));
5742 * Handles \phantom, \vphantom and \hphantom
5744 Phantom: function (name,data) {
5745 var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
5746 this.mlist.Add(new jsMath.mItem('phantom',{phantom: arg, v: data[0], h: data[1]}));
5752 Smash: function (name,data) {
5753 var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
5754 this.mlist.Add(new jsMath.mItem('smash',{smash: arg}));
5758 * Puts an accent on the following argument
5760 MathAccent: function (name,accent) {
5761 var c = this.ProcessArg(this.cmd+name); if (this.error) return;
5762 var atom = jsMath.mItem.Atom('accent',c); atom.accent = accent[0];
5763 this.mlist.Add(atom);
5767 * Handles functions and operators like sin, cos, sum, etc.
5769 NamedOp: function (name,data) {
5770 var a = (name.match(/[^acegm-su-z]/)) ? 1: 0;
5771 var d = (name.match(/[gjpqy]/)) ? .2: 0;
5772 if (data[1]) {name = data[1]}
5773 var box = jsMath.mItem.TextAtom('op',name,jsMath.TeX.fam[0],a,d);
5774 if (data[0] != null) {box.limits = data[0]}
5775 this.mlist.Add(box);
5779 * Implements \limits
5781 Limits: function (name,data) {
5782 var atom = this.mlist.Last();
5783 if (!atom || atom.type != 'op')
5784 {this.Error(this.cmd+name+" is allowed only on operators"); return}
5785 atom.limits = data[0];
5789 * Implements macros like those created by \def. The named control
5790 * sequence is replaced by the string given as the first data value.
5791 * If there is a second data value, this specifies how many arguments
5792 * the macro uses, and in this case, those arguments are substituted
5793 * for #1, #2, etc. within the replacement string.
5795 * See the jsMath.Macro() command below for more details.
5796 * The "newcommand" extension implements \newcommand and \def
5797 * and are loaded automatically if needed.
5799 Macro: function (name,data) {
5803 for (var i = 0; i < data[1]; i++)
5804 {args[args.length] = this.GetArgument(this.cmd+name); if (this.error) return}
5805 text = this.SubstituteArgs(args,text);
5807 this.string = this.AddArgs(text,this.string.slice(this.i));
5812 * Replace macro paramters with their values
5814 SubstituteArgs: function (args,string) {
5815 var text = ''; var newstring = ''; var c; var i = 0;
5816 while (i < string.length) {
5817 c = string.charAt(i++);
5818 if (c == this.cmd) {text += c + string.charAt(i++)}
5819 else if (c == '#') {
5820 c = string.charAt(i++);
5821 if (c == "#") {text += c} else {
5822 if (!c.match(/[1-9]/) || c > args.length)
5823 {this.Error("Illegal macro parameter reference"); return null}
5824 newstring = this.AddArgs(this.AddArgs(newstring,text),args[c-1]);
5829 return this.AddArgs(newstring,text);
5833 * Make sure that macros are followed by a space if their names
5834 * could accidentally be continued into the following text.
5836 AddArgs: function (s1,s2) {
5837 if (s2.match(/^[a-z]/i) && s1.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)) {s1 += ' '}
5842 * Replace the control sequence with the given text
5844 Replace: function (name,data) {
5845 this.mlist.Add(jsMath.mItem.TextAtom(data[0],data[1],data[2],data[3]));
5849 * Error for # (must use \#)
5851 Hash: function (name) {
5852 this.Error("You can't use 'macro parameter character #' in math mode");
5856 * Insert space for ~
5858 Tilde: function (name) {
5859 this.mlist.Add(jsMath.mItem.TextAtom('ord',' ','normal'));
5863 * Implements \llap, \rlap, etc.
5865 HandleLap: function (name) {
5866 var box = this.ProcessArg(); if (this.error) return;
5867 box = this.mlist.Add(new jsMath.mItem('lap',{nuc: box, lap: name}));
5871 * Adds the argument as a specific type of atom (for commands like
5874 HandleAtom: function (name,data) {
5875 var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
5876 this.mlist.Add(jsMath.mItem.Atom(data[0],arg));
5881 * Process the character associated with a specific \mathcharcode
5883 HandleMathCode: function (name,code) {
5884 this.HandleTeXchar(code[0],code[1],code[2]);
5888 * Add a specific character from a TeX font (use the current
5889 * font if the type is 7 (variable) or the font is not specified)
5890 * Load the font if it is not already loaded.
5892 HandleTeXchar: function (type,font,code) {
5893 if (type == 7 && this.mlist.data.font != null) {font = this.mlist.data.font}
5894 font = jsMath.TeX.fam[font];
5895 if (!jsMath.TeX[font]) {
5896 jsMath.TeX[font] = [];
5897 this.Extension(null,[jsMath.Font.URL(font)]);
5899 this.mlist.Add(jsMath.mItem.TeXAtom(jsMath.TeX.atom[type],code,font));
5904 * Add a TeX variable character or number
5906 HandleVariable: function (c) {this.HandleTeXchar(7,1,c.charCodeAt(0))},
5907 HandleNumber: function (c) {this.HandleTeXchar(7,0,c.charCodeAt(0))},
5910 * For unmapped characters, just add them in as normal
5911 * (non-TeX) characters
5913 HandleOther: function (c) {
5914 this.mlist.Add(jsMath.mItem.TextAtom('ord',c,'normal'));
5918 * Ignore comments in TeX data
5919 * ### Some browsers remove the newlines, so this might cause
5920 * extra stuff to be ignored; look into this ###
5922 HandleComment: function () {
5924 while (this.i < this.string.length) {
5925 c = this.string.charAt(this.i++);
5926 if (c == "\r" || c == "\n") return;
5931 * Add a style change (e.g., \displaystyle, etc)
5933 HandleStyle: function (name,style) {
5934 this.mlist.data.style = style[0];
5935 this.mlist.Add(new jsMath.mItem('style',{style: style[0]}));
5939 * Implements \small, \large, etc.
5941 HandleSize: function (name,size) {
5942 this.mlist.data.size = size[0];
5943 this.mlist.Add(new jsMath.mItem('size',{size: size[0]}));
5947 * Set the current font (e.g., \rm, etc)
5949 HandleFont: function (name,font) {
5950 this.mlist.data.font = font[0];
5954 * Look for and process a control sequence
5956 HandleCS: function () {
5957 var cmd = this.GetCommand(); if (this.error) return;
5958 if (this.macros[cmd]) {
5959 var macro = this.macros[cmd];
5960 if (typeof(macro) == "string") {macro = [macro]}
5961 this[macro[0]](cmd,macro.slice(1)); return;
5963 if (this.mathchardef[cmd]) {
5964 this.HandleMathCode(cmd,this.mathchardef[cmd]);
5967 if (this.delimiter[this.cmd+cmd]) {
5968 this.HandleMathCode(cmd,this.delimiter[this.cmd+cmd].slice(0,3))
5971 this.Error("Unknown control sequence '"+this.cmd+cmd+"'");
5975 * Process open and close braces
5977 HandleOpen: function () {this.mlist.Open()},
5978 HandleClose: function () {
5979 if (this.mlist.data.openI == null) {this.Error("Extra close brace"); return}
5980 var open = this.mlist.Get(this.mlist.data.openI);
5981 if (!open || open.left == null) {this.mlist.Close()}
5982 else {this.Error("Extra close brace or missing "+this.cmd+"right"); return}
5988 HandleLeft: function (name) {
5989 var left = this.GetDelimiter(this.cmd+name); if (this.error) return;
5990 this.mlist.Open(left);
5996 HandleRight: function (name) {
5997 var right = this.GetDelimiter(this.cmd+name); if (this.error) return;
5998 var open = this.mlist.Get(this.mlist.data.openI);
5999 if (open && open.left != null) {this.mlist.Close(right)}
6000 else {this.Error("Extra open brace or missing "+this.cmd+"left");}
6004 * Implements generalized fractions (\over, \above, etc.)
6006 HandleOver: function (name,data) {
6007 if (this.mlist.data.overI != null)
6008 {this.Error('Ambiguous use of '+this.cmd+name); return}
6009 this.mlist.data.overI = this.mlist.Length();
6010 this.mlist.data.overF = {name: name};
6011 if (data.length > 0) {
6012 this.mlist.data.overF.left = this.delimiter[data[0]];
6013 this.mlist.data.overF.right = this.delimiter[data[1]];
6014 } else if (name.match(/withdelims$/)) {
6015 this.mlist.data.overF.left = this.GetDelimiter(this.cmd+name); if (this.error) return;
6016 this.mlist.data.overF.right = this.GetDelimiter(this.cmd+name); if (this.error) return;
6018 this.mlist.data.overF.left = null;
6019 this.mlist.data.overF.right = null;
6021 if (name.match(/^above/)) {
6022 this.mlist.data.overF.thickness = this.GetDimen(this.cmd+name,1);
6023 if (this.error) return;
6025 this.mlist.data.overF.thickness = null;
6030 * Add a superscript to the preceeding atom
6032 HandleSuperscript: function () {
6033 var base = this.mlist.Last();
6034 if (this.mlist.data.overI == this.mlist.Length()) {base = null}
6035 if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))
6036 {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
6038 if (base.sup.isPrime) {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
6039 else {this.Error("Double exponent: use braces to clarify"); return}
6041 base.sup = this.ProcessScriptArg('superscript'); if (this.error) return;
6045 * Add a subscript to the preceeding atom
6047 HandleSubscript: function () {
6048 var base = this.mlist.Last();
6049 if (this.mlist.data.overI == this.mlist.Length()) {base = null}
6050 if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))
6051 {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
6052 if (base.sub) {this.Error("Double subscripts: use braces to clarify"); return}
6053 base.sub = this.ProcessScriptArg('subscript'); if (this.error) return;
6057 * Parse a TeX math string, handling macros, etc.
6059 Parse: function () {
6061 while (this.i < this.string.length) {
6062 c = this.string.charAt(this.i++);
6063 if (this.mathchar[c]) {this.HandleMathCode(c,this.mathchar[c])}
6064 else if (this.special[c]) {this[this.special[c]](c)}
6065 else if (this.letter.test(c)) {this.HandleVariable(c)}
6066 else if (this.number.test(c)) {this.HandleNumber(c)}
6067 else {this.HandleOther(c)}
6069 if (this.mlist.data.openI != null) {
6070 var open = this.mlist.Get(this.mlist.data.openI);
6071 if (open.left) {this.Error("Missing "+this.cmd+"right")}
6072 else {this.Error("Missing close brace")}
6074 if (this.mlist.data.overI != null) {this.mlist.Over()}
6078 * Perform the processing of Appendix G
6080 Atomize: function () {
6081 var data = this.mlist.init;
6082 if (!this.error) this.mlist.Atomize(data.style,data.size)
6086 * Produce the final HTML.
6088 * We have to wrap the HTML it appropriate <SPAN> tags to hide its
6089 * actual dimensions when these don't match the TeX dimensions of the
6090 * results. We also include an image to force the results to take up
6091 * the right amount of space. The results may need to be vertically
6092 * adjusted to make the baseline appear in the correct place.
6094 Typeset: function () {
6095 var data = this.mlist.init;
6096 var box = this.typeset = this.mlist.Typeset(data.style,data.size);
6097 if (this.error) {return '<span class="error">'+this.error+'</span>'}
6098 if (box.format == 'null') {return ''};
6100 box.Styled().Remeasured(); var isSmall = 0; var isBig = 0;
6101 if (box.bh > box.h && box.bh > jsMath.h+.001) {isSmall = 1}
6102 if (box.bd > box.d && box.bd > jsMath.d+.001) {isSmall = 1}
6103 if (box.h > jsMath.h || box.d > jsMath.d) {isBig = 1}
6105 var html = box.html;
6106 if (isSmall) {// hide the extra size
6107 if (jsMath.Browser.allowAbsolute) {
6108 var y = (box.bh > jsMath.h+.001 ? jsMath.h - box.bh : 0);
6109 html = jsMath.HTML.Absolute(html,box.w,jsMath.h,0,y);
6110 } else if (jsMath.Browser.valignBug) {
6111 // remove line height
6112 html = '<span style="line-height:'+jsMath.HTML.Em(jsMath.d)+';">'
6114 } else if (!jsMath.Browser.operaLineHeightBug) {
6115 // remove line height and try to hide the depth
6116 var dy = jsMath.HTML.Em(Math.max(0,box.bd-jsMath.hd)/3);
6117 html = '<span style="line-height:'+jsMath.HTML.Em(jsMath.d)+';'
6118 + ' position:relative; top:'+dy+'; vertical-align:'+dy
6119 + '">' + html + '</span>';
6124 // add height and depth to the line
6125 // (force a little extra to separate lines if needed)
6126 html += jsMath.HTML.Blank(0,box.h+.05,box.d+.05);
6128 return '<nobr><span class="scale">'+html+'</span></nobr>';
6134 * Make these characters special (and call the given routines)
6136 jsMath.Parser.prototype.AddSpecial({
6139 close: 'HandleClose'
6144 * The web-page author can call jsMath.Macro to create additional
6145 * TeX macros for use within his or her mathematics. See the
6146 * author's documentation for more details.
6150 Macro: function (name) {
6151 var macro = jsMath.Parser.prototype.macros;
6152 macro[name] = ['Macro'];
6153 for (var i = 1; i < arguments.length; i++)
6154 {macro[name][macro[name].length] = arguments[i]}
6159 * Use these commands to create macros that load
6160 * JavaScript files and reprocess the mathematics when
6161 * the file is loaded. This lets you to have macros or
6162 * LaTeX environments that autoload their own definitions
6163 * only when they are needed, saving initial download time
6164 * on pages where they are not used. See the author's
6165 * documentation for more details.
6169 jsMath.Extension = {
6171 safeRequire: 1, // disables access to files outside of jsMath/extensions
6173 Macro: function (name,file) {
6174 var macro = jsMath.Parser.prototype.macros;
6175 if (file == null) {file = name}
6176 macro[name] = ['Extension',file];
6179 LaTeX: function (env,file) {
6180 var latex = jsMath.Parser.prototype.environments;
6181 latex[env] = ['Extension',file,'environments'];
6184 Font: function (name,font) {
6185 if (font == null) {font = name + "10"}
6186 var macro = jsMath.Parser.prototype.macros;
6187 macro[name] = ['Extension',jsMath.Font.URL(font)];
6190 MathChar: function (font,defs) {
6191 var fam = jsMath.TeX.famName[font];
6193 fam = jsMath.TeX.fam.length;
6194 jsMath.TeX.fam[fam] = font;
6195 jsMath.TeX.famName[font] = fam;
6197 var mathchardef = jsMath.Parser.prototype.mathchardef;
6198 for (var c in defs) {mathchardef[c] = [defs[c][0],fam,defs[c][1]]}
6201 Require: function (file,show) {
6202 if (this.safeRequire && (file.match(/\.\.\/|[^-a-z0-9.\/:_+=%~]/i) ||
6203 (file.match(/:/) && file.substr(0,jsMath.root.length) != jsMath.root))) {
6204 jsMath.Setup.loaded[file] = 1;
6207 jsMath.Setup.Script(this.URL(file),show);
6210 URL: function (file) {
6211 file = file.replace(/^\s+|\s+$/g,'');
6212 if (!file.match(/^([a-z]+:|\/|fonts|extensions\/)/i)) {file = 'extensions/'+file}
6213 if (!file.match(/\.js$/)) {file += '.js'}
6219 /***************************************************************************/
6222 * These routines look through the web page for math elements to process.
6223 * There are two main entry points you can call:
6225 * <script> jsMath.Process() </script>
6227 * <script> jsMath.ProcessBeforeShowing() </script>
6229 * The first will process the page asynchronously (so the user can start
6230 * reading the top of the file while jsMath is still processing the bottom)
6231 * while the second does not update until all the mathematics is typeset.
6236 * Call this at the bottom of your HTML page to have the
6237 * mathematics typeset asynchronously. This lets the user
6238 * start reading the mathematics while the rest of the page
6239 * is being processed.
6241 Process: function (obj) {
6242 jsMath.Setup.Body();
6243 jsMath.Script.Push(jsMath.Translate,'Asynchronous',obj);
6247 * Call this at the bottom of your HTML page to have the
6248 * mathematics typeset before the page is displayed.
6249 * This can take a long time, so the user could cancel the
6250 * page before it is complete; use it with caution, and only
6251 * when there is a relatively small amount of math on the page.
6253 ProcessBeforeShowing: function (obj) {
6254 jsMath.Setup.Body();
6255 var method = (jsMath.Controls.cookie.asynch ? "Asynchronous": "Synchronous");
6256 jsMath.Script.Push(jsMath.Translate,method,obj);
6260 * Process the contents of a single element. It must be of
6263 ProcessElement: function (obj) {
6264 jsMath.Setup.Body();
6265 jsMath.Script.Push(jsMath.Translate,'ProcessOne',obj);
6270 jsMath.Translate = {
6272 element: [], // the list of math elements on the page
6273 cancel: 0, // set to 1 to cancel asynchronous processing
6276 * Parse a TeX string in Text or Display mode and return
6277 * the HTML for it (taking it from the cache, if available)
6279 Parse: function (style,s,noCache) {
6280 var cache = jsMath.Global.cache[style];
6281 if (!cache[jsMath.em]) {cache[jsMath.em] = {}}
6282 var HTML = cache[jsMath.em][s];
6283 if (!HTML || noCache) {
6284 var parse = jsMath.Parse(s,null,null,style);
6285 parse.Atomize(); HTML = parse.Typeset();
6286 if (!noCache) {cache[jsMath.em][s] = HTML}
6291 TextMode: function (s,noCache) {this.Parse('T',s,noCache)},
6292 DisplayMode: function (s,noCache) {this.Parse('D',s,noCache)},
6295 * Return the text of a given DOM element
6297 GetElementText: function (element) {
6298 if (element.childNodes.length == 1 && element.childNodes[0].nodeName === "#comment") {
6299 var result = element.childNodes[0].nodeValue.match(/^\[CDATA\[(.*)\]\]$/);
6300 if (result != null) {return result[1]};
6302 var text = this.recursiveElementText(element);
6304 if (text.search('&') >= 0) {
6305 text = text.replace(/</g,'<');
6306 text = text.replace(/>/g,'>');
6307 text = text.replace(/"/g,'"');
6308 text = text.replace(/&/g,'&');
6312 recursiveElementText: function (element) {
6313 if (element.nodeValue != null) {
6314 if (element.nodeName !== "#comment") {return element.nodeValue}
6315 return element.nodeValue.replace(/^\[CDATA\[((.|\n)*)\]\]$/,"$1");
6317 if (element.childNodes.length === 0) {return " "}
6319 for (var i = 0; i < element.childNodes.length; i++)
6320 {text += this.recursiveElementText(element.childNodes[i])}
6325 * Move hidden to the location of the math element to be
6326 * processed and reinitialize sizes for that location.
6328 ResetHidden: function (element) {
6330 '<span id="jsMath_hiddenSpan" style="position:absolute"></span>'
6331 + jsMath.Browser.operaHiddenFix; // needed by Opera in tables
6332 element.className = '';
6333 jsMath.hidden = element.firstChild;
6334 if (!jsMath.BBoxFor("x").w) {jsMath.hidden = jsMath.hiddenTop}
6340 * Typeset the contents of an element in \textstyle or \displaystyle
6342 ConvertMath: function (style,element,noCache) {
6343 var text = this.GetElementText(element);
6344 this.ResetHidden(element);
6345 if (text.match(/^\s*\\nocache([^a-zA-Z])/))
6346 {noCache = true; text = text.replace(/\s*\\nocache/,'')}
6347 text = this.Parse(style,text,noCache);
6348 element.className = 'typeset';
6349 element.innerHTML = text;
6353 * Process a math element
6355 ProcessElement: function (element) {
6357 if (!element.className.match(/(^| )math( |$)/)) return; // don't reprocess elements
6358 var noCache = (element.className.toLowerCase().match(/(^| )nocache( |$)/) != null);
6360 var style = (element.tagName.toLowerCase() == 'div' ? 'D' : 'T');
6361 this.ConvertMath(style,element,noCache);
6362 element.onclick = jsMath.Click.CheckClick;
6363 element.ondblclick = jsMath.Click.CheckDblClick;
6366 var tex = element.alt;
6367 tex = tex.replace(/&/g,'&')
6368 .replace(/</g,'<')
6369 .replace(/>/g,'>');
6370 element.innerHTML = tex;
6371 element.className = 'math';
6372 if (noCache) {element.className += ' nocache'}
6374 jsMath.hidden = jsMath.hiddenTop;
6379 * Asynchronously process all the math elements starting with
6380 * the k-th one. Do them in blocks of 8 (more efficient than one
6381 * at a time, but still allows screen updates periodically).
6383 ProcessElements: function (k) {
6384 jsMath.Script.blocking = 1;
6385 for (var i = 0; i < jsMath.Browser.processAtOnce; i++, k++) {
6386 if (k >= this.element.length || this.cancel) {
6387 this.ProcessComplete();
6389 jsMath.Message.Set("Process Math: Canceled");
6390 jsMath.Message.Clear()
6392 jsMath.Script.blocking = 0;
6393 jsMath.Script.Process();
6396 var savedQueue = jsMath.Script.SaveQueue();
6397 this.ProcessElement(this.element[k]);
6399 jsMath.Script.Push(this,'ProcessElements',k);
6400 jsMath.Script.RestoreQueue(savedQueue);
6401 jsMath.Script.blocking = 0;
6402 setTimeout('jsMath.Script.Process()',jsMath.Browser.delay);
6407 jsMath.Script.RestoreQueue(savedQueue);
6408 var p = Math.floor(100 * k / this.element.length);
6409 jsMath.Message.Set('Processing Math: '+p+'%');
6410 setTimeout('jsMath.Translate.ProcessElements('+k+')',jsMath.Browser.delay);
6414 * Start the asynchronous processing of mathematics
6416 Asynchronous: function (obj) {
6417 if (!jsMath.initialized) {jsMath.Init()}
6418 this.element = this.GetMathElements(obj);
6419 jsMath.Script.blocking = 1;
6420 this.cancel = 0; this.asynchronous = 1;
6421 jsMath.Message.Set('Processing Math: 0%',1);
6422 setTimeout('jsMath.Translate.ProcessElements(0)',jsMath.Browser.delay);
6426 * Do synchronous processing of mathematics
6428 Synchronous: function (obj,i) {
6430 if (!jsMath.initialized) {jsMath.Init()}
6431 this.element = this.GetMathElements(obj);
6434 this.asynchronous = 0;
6435 while (i < this.element.length) {
6436 this.ProcessElement(this.element[i]);
6438 jsMath.Synchronize('jsMath.Translate.Synchronous(null,'+i+')');
6439 jsMath.Script.Process();
6444 this.ProcessComplete(1);
6448 * Synchronously process the contents of a single element
6450 ProcessOne: function (obj) {
6451 if (!jsMath.initialized) {jsMath.Init()}
6452 this.element = [obj];
6453 this.Synchronous(null,0);
6457 * Look up all the math elements on the page and
6458 * put them in a list sorted from top to bottom of the page
6460 GetMathElements: function (obj) {
6461 var element = []; var k;
6462 if (!obj) {obj = jsMath.document}
6463 if (typeof(obj) == 'string') {obj = jsMath.document.getElementById(obj)}
6464 if (!obj.getElementsByTagName) return null;
6465 var math = obj.getElementsByTagName('div');
6466 for (k = 0; k < math.length; k++) {
6467 if (math[k].className && math[k].className.match(/(^| )math( |$)/)) {
6468 if (jsMath.Browser.renameOK && obj.getElementsByName)
6469 {math[k].setAttribute('name','_jsMath_')}
6470 else {element[element.length] = math[k]}
6473 math = obj.getElementsByTagName('span');
6474 for (k = 0; k < math.length; k++) {
6475 if (math[k].className && math[k].className.match(/(^| )math( |$)/)) {
6476 if (jsMath.Browser.renameOK && obj.getElementsByName)
6477 {math[k].setAttribute('name','_jsMath_')}
6478 else {element[element.length] = math[k]}
6481 // this gets the SPAN and DIV elements interleaved in order
6482 if (jsMath.Browser.renameOK && obj.getElementsByName) {
6483 element = obj.getElementsByName('_jsMath_');
6484 } else if (jsMath.hidden.sourceIndex) {
6485 element.sort(function (a,b) {return a.sourceIndex - b.sourceIndex});
6491 * Remove the window message about processing math
6492 * and clean up any marked <SPAN> or <DIV> tags
6494 ProcessComplete: function (noMessage) {
6495 if (jsMath.Browser.renameOK) {
6496 var element = jsMath.document.getElementsByName('_jsMath_');
6497 for (var i = element.length-1; i >= 0; i--) {
6498 element[i].removeAttribute('name');
6501 jsMath.hidden = jsMath.hiddenTop;
6502 this.element = []; this.restart = null;
6504 jsMath.Message.Set('Processing Math: Done');
6505 jsMath.Message.Clear();
6507 jsMath.Message.UnBlank();
6508 if (jsMath.Browser.safariImgBug &&
6509 (jsMath.Controls.cookie.font == 'symbol' ||
6510 jsMath.Controls.cookie.font == 'image')) {
6512 // For Safari, the images don't always finish
6513 // updating, so nudge the window to cause a
6516 if (this.timeout) {clearTimeout(this.timeout)}
6517 this.timeout = setTimeout("jsMath.window.resizeBy(-1,0); "
6518 + "jsMath.window.resizeBy(1,0); "
6519 + "jsMath.Translate.timeout = null",2000);
6524 * Cancel procesing elements
6526 Cancel: function () {
6527 jsMath.Translate.cancel = 1;
6528 if (jsMath.Script.cancelTimer) {jsMath.Script.cancelLoad()}
6535 // Synchronize these with the loading of the tex2math plugin.
6537 ConvertTeX: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertTeX',element)},
6538 ConvertTeX2: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertTeX2',element)},
6539 ConvertLaTeX: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertLaTeX',element)},
6540 ConvertCustom: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertCustom',element)},
6541 CustomSearch: function (om,cm,od,cd) {jsMath.Script.Push(null,function () {jsMath.tex2math.CustomSearch(om,cm,od,cd)})},
6543 ConvertTeX: function () {},
6544 ConvertTeX2: function () {},
6545 ConvertLaTeX: function () {},
6546 ConvertCustom: function () {},
6547 CustomSearch: function () {}
6550 jsMath.Synchronize = jsMath.Script.Synchronize;
6552 /***************************************************************************/
6559 if (window.parent != window && window.jsMathAutoload) {
6560 window.parent.jsMath = jsMath;
6561 jsMath.document = window.parent.document;
6562 jsMath.window = window.parent;
6567 jsMath.Global.Register();
6569 jsMath.Controls.GetCookie();
6570 jsMath.Setup.Source();
6571 jsMath.Global.Init();
6572 jsMath.Script.Init();
6573 jsMath.Setup.Fonts();
6574 if (jsMath.document.body) {jsMath.Setup.Body()}
6575 jsMath.Setup.User("onload");