File:  [LON-CAPA] / loncom / html / adm / jsMath / uncompressed / jsMath.js
Revision 1.2: download - view: text, annotated - select for diffs
Wed May 17 22:19:41 2006 UTC (18 years, 1 month ago) by albertel
Branches: MAIN
CVS tags: version_2_5_X, version_2_5_2, version_2_5_1, version_2_5_0, version_2_4_X, version_2_4_99_0, version_2_4_2, version_2_4_1, version_2_4_0, version_2_3_X, version_2_3_99_0, version_2_3_2, version_2_3_1, version_2_3_0, version_2_2_X, version_2_2_99_1, version_2_2_99_0, version_2_2_2, version_2_2_1, version_2_2_0, version_2_1_X, version_2_1_99_3, version_2_1_99_2, version_2_1_99_1, version_2_1_99_0, HEAD
- jsmath 3.3

    1: /*****************************************************************************
    2:  * 
    3:  *  jsMath: Mathematics on the Web
    4:  *  
    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
    8:  *  
    9:  *            http://www.math.union.edu/locate/jsMath
   10:  *
   11:  *  for the latest version, and for documentation on how to use jsMath.
   12:  *
   13:  *  Copyright 2004-2006 by Davide P. Cervone
   14:  * 
   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
   18:  * 
   19:  *      http://www.apache.org/licenses/LICENSE-2.0
   20:  * 
   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.
   26:  *  
   27:  *****************************************************************************/
   28: 
   29: /*
   30:  *  Prevent running everything again if this file is loaded twice
   31:  */
   32: if (!window.jsMath || !window.jsMath.loaded) {
   33: 
   34: var jsMath_old = window.jsMath;  // save user customizations
   35: 
   36: //
   37: // debugging routine
   38: // 
   39: /* 
   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 + '  ')
   47:  *           + spaces + "}\n";
   48:  *       } else if (typeof(obj[i]) != "function") {
   49:  *         s += spaces + i + ': ' + obj[i] + "\n";
   50:  *       }
   51:  *     }
   52:  *   }
   53:  *   return s;
   54:  * }
   55:  */
   56: 
   57: /***************************************************************************/
   58: //
   59: //  Check for DOM support
   60: //
   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.');
   64: } else {
   65: 
   66: /***************************************************************************/
   67: 
   68: window.jsMath = {
   69:   
   70:   version: "3.3",  // change this if you edit the file, but don't edit this file
   71:   
   72:   document: document,  // the document loading jsMath
   73:   window: window,      // the window of the of loading document
   74:   
   75:   // Font sizes for \tiny, \small, etc. (must match styles below)
   76:   sizes: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249],
   77: 
   78:   //
   79:   //  The styles needed for the TeX fonts
   80:   //
   81:   styles: {
   82:     '.math':              'font-family: serif; font-style: normal; font-weight: normal',
   83: 
   84:     '.typeset':           'font-family: serif; font-style: normal; font-weight: normal',
   85:     'div.typeset':        'text-align: center; margin: 1em 0px;',
   86:     'span.typeset':       'text-align: left',
   87:     '.typeset span':      'text-align: left; border:0px; margin:0px; padding:0px',
   88:     
   89:     '.typeset .normal':   'font-family: serif; font-style: normal; font-weight: normal',
   90: 
   91:     '.typeset .size0':    'font-size: 50%',  // tiny (\scriptscriptsize)
   92:     '.typeset .size1':    'font-size: 60%',  //       (50% of \large for consistency)
   93:     '.typeset .size2':    'font-size: 70%',  // scriptsize
   94:     '.typeset .size3':    'font-size: 85%',  // small (70% of \large for consistency)
   95:     '.typeset .size4':    'font-size: 100%', // normalsize
   96:     '.typeset .size5':    'font-size: 120%', // large
   97:     '.typeset .size6':    'font-size: 144%', // Large
   98:     '.typeset .size7':    'font-size: 173%', // LARGE
   99:     '.typeset .size8':    'font-size: 207%', // huge
  100:     '.typeset .size9':    'font-size: 249%', // Huge
  101:   
  102:     '.typeset .cmr10':    'font-family: jsMath-cmr10, serif',
  103:     '.typeset .cmbx10':   'font-family: jsMath-cmbx10, jsMath-cmr10',
  104:     '.typeset .cmti10':   'font-family: jsMath-cmti10, jsMath-cmr10',
  105:     '.typeset .cmmi10':   'font-family: jsMath-cmmi10',
  106:     '.typeset .cmsy10':   'font-family: jsMath-cmsy10',
  107:     '.typeset .cmex10':   'font-family: jsMath-cmex10',
  108:     
  109:     '.typeset .textit':   'font-family: serif; font-style:italic',
  110:     '.typeset .textbf':   'font-family: serif; font-weight:bold',
  111:     
  112:     '.typeset .link':     'text-decoration: none',
  113:     '.typeset .error':    'font-size: 10pt; font-style: italic; '
  114:                              + 'background-color: #FFFFCC; padding: 1px; '
  115:                              + 'border: 1px solid #CC0000',
  116: 
  117:     '.typeset .blank':    'display:inline-block; overflow:hidden; border:0px none; width:0px; height:0px;',
  118:     '.typeset .spacer':   'display:inline-block',
  119: 
  120:     '#jsMath_message':         'position:fixed; bottom:1px; left:2px; background-color:#E6E6E6; '
  121:                                  + 'border: solid 1px #959595; margin:0px; padding: 1px 8px; '
  122:                                  + 'z-index:102; color: black; font-size:small; width:auto;',
  123:     '#jsMath_panel':           'position:fixed; bottom:1.5em; right:1.5em; padding: .8em 1.6em; '
  124:                                  + 'background-color:#DDDDDD; border: outset 2px; '
  125:                                  + 'z-index:103; width:auto;',
  126:     '#jsMath_panel .disabled': 'color:#888888',
  127:     '#jsMath_panel .infoLink': 'font-size:85%',
  128:     '#jsMath_button':          'position:fixed; bottom:1px; right:2px; background-color:white; '
  129:                                  + 'border: solid 1px #959595; margin:0px; padding: 0px 3px 1px 3px; '
  130:                                  + 'z-index:102; color:black; text-decoration:none; font-size:x-small; '
  131:                                  + 'width:auto; cursor:hand;',
  132:     '#jsMath_global':          'font-style:italic;',
  133:     '#jsMath_float':           'position:absolute; top:0px; left:0px; max-width:80%; '
  134:                                  + 'z-index:101; width:auto; height:auto;',
  135:     '#jsMath_float .drag':     'background-color:#DDDDDD; border: outset 1px; height:12px; font-size: 1px;',
  136:     '#jsMath_float .close':    'background-color:#E6E6E6; border: inset 1px; width:8px; height:8px; margin: 1px 2px;',
  137:     '#jsMath_float .source':   'background-color:#E2E2E2; border: outset 1px; '
  138:                                  + 'width:auto; height:auto; padding: 8px 15px; '
  139:                                  + 'font-family: courier, fixed; font-size: 90%',
  140: 
  141:     '#jsMath_noFont .message': 'text-align: center; padding: .8em 1.6em; border: 3px solid #DD0000; '
  142:                                   + 'background-color: #FFF8F8; color: #AA0000; font-size:small; width:auto;',
  143:     '#jsMath_noFont .link':    'padding: 0px 5px 2px 5px; border: 2px outset; background-color:#E8E8E8; '
  144:                                   + 'color:black; font-size:80%; width:auto; cursor:hand;',
  145: 
  146:     '#jsMath_PrintWarning .message':
  147:                                  'text-align: center; padding: .8em 1.6em; border: 3px solid #DD0000; '
  148:                                    + 'background-color: #FFF8F8; color: #AA0000; font-size:x-small; width:auto;',
  149: 
  150:     '@media print':      '#jsMath_button {display:none}\n' +
  151:                          '#jsMath_Warning {display:none}',
  152:                          
  153:     '@media screen':     '#jsMath_PrintWarning {display:none}'
  154: 
  155:   },
  156:   
  157: 
  158:   /***************************************************************************/
  159: 
  160:   /*
  161:    *  Get a jsMath DOM element
  162:    */
  163:   Element: function (name) {return jsMath.document.getElementById('jsMath_'+name)},
  164:   
  165:   /*
  166:    *  Get the width and height (in pixels) of an HTML string
  167:    */
  168:   BBoxFor: function (s) {
  169:     this.hidden.innerHTML = 
  170:       '<nobr><span class="typeset"><span class="scale">'+s+'</span></span></nobr>';
  171:     var bbox = {w: this.hidden.offsetWidth, h: this.hidden.offsetHeight};
  172:     this.hidden.innerHTML = '';
  173:     return bbox;
  174:   },
  175: 
  176:   /*
  177:    *  Get the width and height (in ems) of an HTML string.
  178:    *  Check the cache first to see if we've already measured it.
  179:    */
  180:   EmBoxFor: function (s) {
  181:     var cache = jsMath.Global.cache.R;
  182:     if (!cache[this.em]) {cache[this.em] = {}}
  183:     if (!cache[this.em][s]) {
  184:       var bbox = this.BBoxFor(s);
  185:       cache[this.em][s] = {w: bbox.w/this.em, h: bbox.h/this.em};
  186:     }
  187:     return cache[this.em][s];
  188:   },
  189: 
  190:   /*
  191:    *  For browsers that don't handle sizes of italics properly (MSIE).
  192:    *  Check the cache first to see if we've already measured it.
  193:    */
  194:   EmBoxForItalics: function (s) {
  195:     var cache = jsMath.Global.cache.R;
  196:     if (!cache[this.em]) {cache[this.em] = {}}
  197:     if (!cache[this.em][s]) {
  198:       var bbox = this.BBoxFor(s);
  199:       if (s.match(/<i>|class=\"(icm|italic|igreek|iaccent)/i)) {
  200:         bbox.w = this.BBoxFor(s+jsMath.Browser.italicString).w
  201:                   - jsMath.Browser.italicCorrection;
  202:       }
  203:       cache[this.em][s] = {w: bbox.w/this.em, h: bbox.h/this.em};
  204:     }
  205:     return cache[this.em][s];
  206:   },
  207: 
  208:   /*
  209:    *  Initialize jsMath.  This determines the em size, and a variety
  210:    *  of other parameters used throughout jsMath.
  211:    */
  212:   Init: function () {
  213:     if (jsMath.Setup.inited != 1) {
  214:       if (!jsMath.Setup.inited) {jsMath.Setup.Body()}
  215:       if (jsMath.Setup.inited != 1) {
  216:         alert("It looks like jsMath failed to set up properly (error code "
  217:                + jsMath.Setup.inited + ").  "
  218:                + "I will try to keep going, but it could get ugly.");
  219:         jsMath.Setup.inited = 1;
  220:       }
  221:     }
  222:     this.em = this.BBoxFor('<span style="'+jsMath.Browser.block+';width:13em;height:1em"></span>').w/13;
  223:     if (this.em == 0) {
  224:       // handle older browsers
  225:       this.em = this.BBoxFor('<img src="'+jsMath.blank+'" style="width:13em;height:1em"/>').w/13;
  226:     }
  227:     var cache = jsMath.Global.cache.B;
  228:     if (!cache[this.em]) {
  229:       cache[this.em] = {};
  230:       cache[this.em].bb = this.BBoxFor('x'); var hh = cache[this.em].bb.h;
  231:       cache[this.em].d = this.BBoxFor('x'+jsMath.HTML.Rule(1,hh/jsMath.em)).h - hh;
  232:       if (jsMath.Browser.italicString) 
  233:         {cache[this.em].ic = jsMath.BBoxFor(jsMath.Browser.italicString).w}
  234:     }
  235:     jsMath.Browser.italicCorrection = cache[this.em].ic;
  236:     var bb = cache[this.em].bb; var h = bb.h; var d = cache[this.em].d
  237:     this.h = (h-d)/this.em; this.d = d/this.em;
  238:     this.hd = this.h + this.d;
  239:     this.xWidth = bb.w;  // used to tell if scale has changed
  240: 
  241:     this.Setup.TeXfonts();
  242:     
  243:     var x_height = this.EmBoxFor('<span class="cmr10">M</span>').w/2;
  244:     this.TeX.M_height = x_height*(26/14);
  245:     this.TeX.h = this.h; this.TeX.d = this.d; this.TeX.hd = this.hd;
  246:     
  247:     this.Img.Scale();
  248:     if (!this.initialized) {
  249:       this.Setup.Sizes();
  250:       this.Img.UpdateFonts();
  251:     }
  252: 
  253:     // factor for \big and its brethren
  254:     this.p_height = (this.TeX.cmex10[0].h + this.TeX.cmex10[0].d) / .85;
  255: 
  256:     this.initialized = 1;
  257:   },
  258:   
  259:   /*
  260:    *  Get the xWidth size and if it has changed, reinitialize the sizes
  261:    */
  262:   ReInit: function () {
  263:     var w = this.BBoxFor('x').w;
  264:     if (w != this.xWidth) {this.Init()}
  265:   },
  266:   
  267:   /*
  268:    *  Mark jsMath as loaded and copy any user-provided overrides
  269:    */
  270:   Loaded: function () {
  271:     if (jsMath_old) {
  272:       var override = ['Process', 'ProcessBeforeShowing',
  273:         'ConvertTeX','ConvertTeX2','ConvertLaTeX','ConvertCustom',
  274:         'CustomSearch', 'Synchronize', 'Macro', 'document'];
  275:       for (var i = 0; i < override.length; i++) {
  276:         if (jsMath_old[override[i]]) {delete jsMath_old[override[i]]}
  277:       }
  278:     }
  279:     if (jsMath_old) {this.Insert(jsMath,jsMath_old)}
  280:     jsMath_old = null;
  281:     jsMath.loaded = 1;
  282:   },
  283:   
  284:   /*
  285:    *  Manage JavaScript objects:
  286:    *  
  287:    *      Add:        add/replace items in an object
  288:    *      Insert:     add items to an object
  289:    *      Package:    add items to an object prototype
  290:    */
  291:   Add: function (dst,src) {for (var id in src) {dst[id] = src[id]}},
  292:   Insert: function (dst,src) {
  293:     for (var id in src) {
  294:       if (dst[id] && typeof(src[id]) == 'object'
  295:                   && (typeof(dst[id]) == 'object'
  296:                   ||  typeof(dst[id]) == 'function')) {
  297:         this.Insert(dst[id],src[id]);
  298:       } else {
  299:         dst[id] = src[id];
  300:       }
  301:     }
  302:   },
  303:   Package: function (obj,def) {this.Insert(obj.prototype,def)}
  304: 
  305: };
  306: 
  307: 
  308: /***************************************************************************/
  309: 
  310:   /*
  311:    *  Implements items associated with the global cache.
  312:    *
  313:    *  This object will be replaced by a global version when 
  314:    *  (and if) jsMath-global.html is loaded.
  315:    */
  316: jsMath.Global = {
  317:     isLocal: 1,  // a local copy if jsMath-global.html hasn't been loaded
  318:     cache: {T: {}, D: {}, R: {}, B: {}},
  319: 
  320:     /*
  321:      *  Clear the global (or local) cache
  322:      */
  323:     ClearCache: function () {jsMath.Global.cache = {T: {}, D: {}, R: {}, B: {}}},
  324: 
  325:     /*
  326:      *  Initiate global mode
  327:      */
  328:     GoGlobal: function (cookie) {
  329:       var url = String(jsMath.window.location);
  330:       var c = (jsMath.window.location.protocol == 'mk:') ? '#' : '?';
  331:       if (cookie) {url = url.replace(/\?.*/,'') + '?' + cookie}
  332:       jsMath.Controls.Reload(jsMath.root + "jsMath-global.html" + c +escape(url));
  333:     },
  334: 
  335:     /*
  336:      *  Check if we need to go to global mode
  337:      */
  338:     Init: function () {
  339:       if (jsMath.Controls.cookie.global == "always" && !jsMath.noGoGlobal) {
  340:         if (navigator.accentColorName) return; // OmniWeb craches on GoGlobal
  341:         if (!jsMath.window) {jsMath.window = window}
  342:         jsMath.Controls.loaded = 1;
  343:         jsMath.Controls.defaults.hiddenGlobal = null;
  344:         this.GoGlobal(jsMath.Controls.SetCookie(2));
  345:       }
  346:     },
  347: 
  348:     /*
  349:      *  Try to register with a global.html window that contains us
  350:      */
  351:     Register: function () {
  352:       try {
  353:         this.Domain();
  354: 	if (parent.jsMath && parent.jsMath.isGlobal)
  355:           {parent.jsMath.Register(jsMath.window)}
  356:       } catch (err) {}
  357:     },
  358: 
  359:     /*
  360:      *  If we're not the parent window, try to set the domain to
  361:      *  match the parent's domain (so we can use the Global data
  362:      *  if the surrounding frame is a Global frame.
  363:      */
  364:     Domain: function () {
  365:       // MSIE/Mac can't do domain changes, so don't bother trying
  366:       if (navigator.appName == 'Microsoft Internet Explorer' &&
  367:           navigator.platform == 'MacPPC' && navigator.userProfile != null) return;
  368:       if (window == parent) return;
  369:       var oldDomain = jsMath.document.domain;
  370:       try {
  371:         while (true) {
  372:           try {if (parent.document.title != null) return} catch (err) {}
  373: 	  if (!document.domain.match(/\..*\./)) break;
  374:           jsMath.document.domain = jsMath.document.domain.replace(/^[^.]*\./,'');
  375:         }
  376:       } catch (err) {}
  377:       jsMath.document.domain = oldDomain;
  378:     }
  379: 
  380: };
  381:   
  382: 
  383: 
  384: /***************************************************************************/
  385: 
  386: /*
  387:  *
  388:  *  Implement loading of remote scripts using XMLHttpRequest, if
  389:  *  possible, otherwise use a hidden IFRAME and fake it.  That
  390:  *  method runs asynchronously, which causes lots of headaches.
  391:  *  Solve these using Push command, which queues actions
  392:  *  until files have loaded.
  393:  */
  394: 
  395: jsMath.Script = {
  396: 
  397:   request: null, // the XMLHttpRequest object
  398: 
  399:   /*
  400:    *  Create the XMLHttpRequest object, if we can.
  401:    *  Otherwise, use the iframe-based fallback method.
  402:    */
  403:   Init: function () {
  404:     if (!(jsMath.Controls.cookie.asynch && jsMath.Controls.cookie.progress)) {
  405:       if (window.XMLHttpRequest) {
  406:         this.request = new XMLHttpRequest;
  407:       } else if (window.ActiveXObject) {
  408:         try {this.request = new ActiveXObject("Microsoft.XMLHTTP")} catch (err) {}
  409:       }
  410:     }
  411:     //
  412:     //  Use the delayed-script fallback for MSIE/Mac and old versions
  413:     //  of several browsers (Opera 7.5, OmniWeb 4.5).
  414:     //
  415:     if (!this.request || jsMath.Setup.domainChanged)
  416:       {this.Load = this.delayedLoad; this.needsBody = 1}
  417:   },
  418: 
  419:   /*
  420:    *  Load a script and evaluate it in the window's context
  421:    */
  422:   Load: function (url,show) {
  423:     if (show) {
  424:       jsMath.Message.Set("Loading "+url);
  425:       jsMath.Script.Delay(1);
  426:       jsMath.Script.Push(this,'xmlRequest',url);
  427:       jsMath.Script.Push(jsMath.Message,'Clear');
  428:     } else {
  429:       jsMath.Script.Push(this,'xmlRequest',url);
  430:     }
  431:   },
  432: 
  433:   /*
  434:    *  Load a URL and run the contents of the file
  435:    */
  436:   xmlRequest: function (url) {
  437:     this.blocking = 1;
  438: //    this.debug('xmlRequest: '+url);
  439:     try {
  440:       this.request.open("GET",url,false);
  441:       this.request.send(null);
  442:     } catch (err) {
  443:       throw "jsMath can't load the file '"+url+"'\n"
  444:           + "Message: "+err.message;
  445:     }
  446:     if (this.request.status && this.request.status >= 400) {
  447:       // Do we need to deal with redirected links?
  448:       throw "jsMath can't load the file '"+url+"'\n"
  449:           + "Error status: "+this.request.status;
  450:     }
  451:     var tmpQueue = this.queue; this.queue = [];
  452: //    this.debug('xml Eval ['+tmpQueue.length+']');
  453:     jsMath.window.eval(this.request.responseText);
  454: //    this.debug('xml Done ['+this.queue.length+' + '+tmpQueue.length+']');
  455:     this.blocking = 0; this.queue = this.queue.concat(tmpQueue);
  456:     this.Process();
  457:   },
  458: 
  459:   /********************************************************************
  460:    *
  461:    *  Implement asynchronous loading and execution of scripts
  462:    *  (via hidden IFRAME) interleved with other JavaScript commands
  463:    *  that must be synchronized with the file loading.  (Basically, this
  464:    *  is for MSIE/Mac and Opera 7.5, which don't have XMLHttpRequest.)
  465:    */
  466: 
  467:   cancelTimeout: 30*1000,   // delay for canceling load (30 sec)
  468: 
  469:   iframe: null,      // the hidden iframe
  470:   blocking: 0,       // true when an asynchronous action is being performed
  471:   cancelTimer: null, // timer to cancel load if it takes too long
  472:   needsBody: 0,      // true if loading files requires BODY to be present
  473:   
  474:   queue: [],         // the stack of pending actions
  475: 
  476:   /*
  477:    *  Provide mechanism for synchronizing with the asynchronous jsMath
  478:    *  file-loading mechanism.  'code' can be a string or a function.
  479:    */
  480:   Synchronize: function (code,data) {
  481:     if (typeof(code) != 'string') {jsMath.Script.Push(null,code,data)}
  482:       else {jsMath.Script.Push(jsMath.window,'eval',code)}
  483:   },
  484:   
  485:   /*
  486:    *  Queue a function to be processed.
  487:    *  If nothing is being loaded, do the pending commands.
  488:    */
  489:   Push: function (object,method,data) {
  490: //    this.debug('Pushing: '+method+' at '+this.queue.length);
  491:     this.queue[this.queue.length] = [object,method,data];
  492:     if (!(this.blocking || (this.needsBody && !jsMath.document.body))) this.Process();
  493:   },
  494: 
  495:   /*
  496:    *  Do any pending functions (stopping if a file load is started)
  497:    */
  498:   Process: function () {
  499:     while (this.queue.length && !this.blocking) {
  500:       var call = this.queue[0]; var tmpQueue = this.queue.slice(1); this.queue = [];
  501:       var object = call[0]; var method = call[1]; var data = call[2];
  502: //      this.debug('Calling: '+method+' ['+tmpQueue.length+']');
  503:       if (object) {object[method](data)} else if (method) {method(data)}
  504: //      this.debug('Done:    '+method+' ['+this.queue.length+' + '+tmpQueue.length+']');
  505:       this.queue = this.queue.concat(tmpQueue);
  506:     }
  507:   },
  508:   
  509:   /*
  510:    *  Handle loading of scripts that run asynchronously
  511:    */
  512:   delayedLoad: function (url) {
  513: //    this.debug('Loading: '+url);
  514:     this.Push(this,'startLoad',url);
  515:   },
  516:   startLoad: function (url) {
  517:     this.iframe = jsMath.document.createElement('iframe');
  518:     this.iframe.style.visibility = 'hidden';
  519:     this.iframe.style.position = 'absolute';
  520:     this.iframe.style.width = '0px';
  521:     this.iframe.style.height = '0px';
  522:     if (jsMath.document.body.firstChild) {
  523:       jsMath.document.body.insertBefore(this.iframe,jsMath.document.body.firstChild);
  524:     } else {
  525:       jsMath.document.body.appendChild(this.iframe);
  526:     }
  527:     this.blocking = 1; this.url = url;
  528:     if (!url.match(/\.js$/)) {this.iframe.src = url}
  529:                         else {this.iframe.src = jsMath.root+"jsMath-loader.html"}
  530:     if (url.substr(0,jsMath.root.length) == jsMath.root)
  531:       {url = url.substr(jsMath.root.length)}
  532:     jsMath.Message.Set("Loading "+url);
  533:     this.cancelTimer = setTimeout('jsMath.Script.cancelLoad()',this.cancelTimeout);
  534:   },
  535:   endLoad: function (action) {
  536:     if (this.cancelTimer) {clearTimeout(this.cancelTimer); this.cancelTimer = null;}
  537:     jsMath.Message.Clear();
  538:     if (action != 'cancel') {this.blocking = 0; this.Process()}
  539:   },
  540:   
  541:   Start: function () {
  542: //    this.debug('Starting: ['+this.queue.length+'] '+this.url);
  543:     this.tmpQueue = this.queue; this.queue = [];
  544:   },
  545:   End:   function () {
  546: //    this.debug('Ending:   ['+this.queue.length+' + '+this.tmpQueue.length+'] '+this.url);
  547:     this.queue = this.queue.concat(this.tmpQueue); delete this.tmpQueue;
  548:   },
  549: 
  550:   /*
  551:    *  If the loading takes too long, cancel it and end the load.
  552:    */
  553:   cancelLoad: function () {
  554:     this.cancelTimer = null;
  555:     jsMath.Message.Set("Can't load file");
  556:     this.endLoad("cancel");
  557:   },
  558: 
  559:   /*
  560:    *  Perform a delay (to let the browser catch up)
  561:    */
  562:   Delay: function (time) {
  563:     this.blocking = 1;
  564:     setTimeout('jsMath.Script.endDelay()',time);
  565:   },
  566:   endDelay: function () {
  567: //    this.debug('endDelay');
  568:     this.blocking = 0;
  569:     this.Process();
  570:   },
  571:   
  572:   /*
  573:    *  Load an image and wait for it
  574:    *  (so MSIE won't load extra copies of it)
  575:    */
  576:   imageCount: 0,
  577:   WaitForImage: function (file) {
  578:     this.blocking = 1; this.imageCount++;
  579:     if (this.img == null) {this.img = []}
  580:     var img = new Image(); this.img[this.img.length] = img;
  581:     img.onload = function () {if (--jsMath.Script.imageCount == 0) jsMath.Script.endDelay()}
  582:     img.onerror = img.onload; img.onabort = img.onload;
  583:     img.src = file;
  584:   },
  585:   
  586:   /*
  587:    *  The code uncompressor
  588:    */
  589:   Uncompress: function (data) {
  590:     for (var k = 0; k <  data.length; k++) {
  591:       var d = data[k]; var n = d.length;
  592:       for (var i = 0; i < n; i++) {if (typeof(d[i]) == 'number') {d[i] = d[d[i]]}}
  593:       data[k] = d.join('');
  594:     }
  595:     window.eval(data.join(''));
  596:   }//,
  597:   
  598:   /*
  599:    *  for debugging the event queue
  600:    */
  601: //  debug: function (message) {
  602: //    if (jsMath.document.body && jsMath.window.debug) {jsMath.window.debug(message)}
  603: //      else {alert(message)}
  604: //  }
  605: 
  606: };
  607: 
  608: /***************************************************************************/
  609: 
  610: /*
  611:  *  Message and screen blanking facility
  612:  */
  613: 
  614: jsMath.Message = {
  615:   
  616:   blank: null,    // the div to blank out the screen
  617:   message: null,  // the div for the messages
  618:   text: null,     // the text node for messages
  619:   clear: null,    // timer for clearing message
  620: 
  621:   /*
  622:    *  Create the elements needed for the message box
  623:    */
  624:   Init: function () {
  625:     if (!jsMath.document.body || !jsMath.Controls.cookie.progress) return;
  626:     if (jsMath.Setup.stylesReady) {
  627:       this.message = jsMath.Setup.DIV('message',{visibility:'hidden'});
  628:     } else {
  629:       this.message = jsMath.Setup.DIV('message',{
  630:         visibility:'hidden', position:'absolute', bottom:'1px', left:'2px',
  631:         backgroundColor:'#E6E6E6', border:'solid 1px #959595',
  632:         margin:'0px', padding:'1px 8px', zIndex:102,
  633:         color:'black', fontSize:'small', width:'auto'
  634:       });
  635:     }
  636:     this.text = jsMath.document.createTextNode('');
  637:     this.message.appendChild(this.text);
  638:     this.message.onmousedown = jsMath.Translate.Cancel;
  639:   },
  640:   
  641:   /*
  642:    *  Set the contents of the message box, or use the window status line
  643:    */
  644:   Set: function (text,canCancel) {
  645:     if (this.clear) {clearTimeout(this.clear); this.clear = null}
  646:     if (jsMath.Controls.cookie.progress) {
  647:       if (!this.text) {this.Init(); if (!this.text) return}
  648:       if (jsMath.Browser.textNodeBug) {this.message.innerHTML = text}
  649:         else {this.text.nodeValue = text}
  650:       this.message.style.visibility = 'visible';
  651:       if (canCancel) {
  652:         this.message.style.cursor = 'pointer';
  653:         if (!this.message.style.cursor) {this.message.style.cursor = 'hand'}
  654:         this.message.title = ' Cancel Processing of Math ';
  655:       } else {
  656:         this.message.style.cursor = '';
  657:         this.message.title = '';
  658:       }
  659:     } else {
  660:       if (text.substr(0,8) != "Loading ") {jsMath.window.status = text}
  661:     }
  662:   },
  663:   
  664:   /*
  665:    *  Clear the message box or status line
  666:    */
  667:   Clear: function () {
  668:     if (this.clear) {clearTimeout(this.clear)}
  669:     this.clear = setTimeout("jsMath.Message.doClear()",1000);
  670:   },
  671:   doClear: function () {
  672:     if (this.clear) {
  673:       this.clear = null;
  674:       jsMath.window.status = '';
  675:       if (this.text) {this.text.nodeValue = ''}
  676:       if (this.message) {this.message.style.visibility = 'hidden'}
  677:     }
  678:   },
  679:   
  680:   
  681:   /*
  682:    *  Put up a DIV that covers the window so that the
  683:    *  "flicker" of processing the mathematics will not be visible
  684:    */
  685:   Blank: function () {
  686:     if (this.blank || !jsMath.document.body) return;
  687:     this.blank = jsMath.Setup.DIV("blank",{
  688:       position:(jsMath.Browser.msiePositionFixedBug? 'absolute': 'fixed'),
  689:       top:'0px', left:'0px', bottom:'0px', right:'0px',
  690:       zIndex:101, backgroundColor:'white'
  691:     });
  692:     if (jsMath.Browser.msieBlankBug) {
  693:       this.blank.innerHTML = '&nbsp;';
  694:       this.blank.style.width = "110%";
  695:       this.blank.style.height = "110%";
  696:     }
  697:   },
  698:   
  699:   UnBlank: function () {
  700:     if (this.blank) {jsMath.document.body.removeChild(this.blank)}
  701:     this.blank = null;
  702:   }
  703: };
  704: 
  705: 
  706: /***************************************************************************/
  707: 
  708: /*
  709:  *  Miscellaneous setup and initialization
  710:  */
  711: jsMath.Setup = {
  712:   
  713:   loaded: [],  // array of files already loaded
  714:   
  715:   /*
  716:    *  Insert a DIV at the top of the page with given ID,
  717:    *  attributes, and style settings
  718:    */
  719:   DIV: function (id,styles) {
  720:     var div = jsMath.document.createElement('div');
  721:     div.id = 'jsMath_'+id;
  722:     for (var i in styles) {div.style[i]= styles[i]}
  723:     if (!jsMath.document.body.hasChildNodes) {jsMath.document.body.appendChild(div)}
  724:       else {jsMath.document.body.insertBefore(div,jsMath.document.body.firstChild)}
  725:     return div;
  726:   },
  727:   
  728:   /*
  729:    *  Source a jsMath JavaScript file (only load any given file once)
  730:    */
  731:   Script: function (file,show) {
  732:     if (this.loaded[file]) {return} else {this.loaded[file] = 1}
  733:     if (!file.match('^([a-zA-Z]+:/?)?/')) {file = jsMath.root + file}
  734:     jsMath.Script.Load(file,show);
  735:   },
  736:   
  737:   /*
  738:    *  Use a hidden <DIV> for measuring the BBoxes of things
  739:    */
  740:   Hidden: function () {
  741:     jsMath.hidden = this.DIV("Hidden",{
  742:       visibility: 'hidden', position:"absolute",
  743:       top:0, left:0, border:0, padding:0, margin:0
  744:     });
  745:     jsMath.hiddenTop = jsMath.hidden;
  746:     return;
  747:   },
  748: 
  749:   /*
  750:    *  Find the root URL for the jsMath files (so we can load
  751:    *  the other .js and .gif files)
  752:    */
  753:   Source: function () {
  754:     if (jsMath.Autoload && jsMath.Autoload.root) {
  755:       jsMath.root = jsMath.Autoload.root;
  756:     } else {
  757:       jsMath.root = '';
  758:       var script = jsMath.document.getElementsByTagName('script');
  759:       if (script) {
  760:         for (var i = 0; i < script.length; i++) {
  761:           var src = script[i].src;
  762:           if (src && src.match('(^|/)jsMath.js$')) {
  763:             jsMath.root = src.replace(/jsMath.js$/,'');
  764:             if (jsMath.root.charAt(0) == '/') {
  765:               jsMath.root = jsMath.document.location.protocol + '//'
  766:                           + jsMath.document.location.host + jsMath.root;
  767:             } else if (!jsMath.root.match(/^[a-z]+:/i)) {
  768: 	      src = new String(jsMath.document.location);
  769: 	      jsMath.root = src.replace(new RegExp('[^/]*$'),'') + jsMath.root;
  770: 	      while (jsMath.root.match('/[^/]*/\\.\\./')) {
  771: 	        jsMath.root = jsMath.root.replace(new RegExp('/[^/]*/\\.\\./'),'/');
  772: 	      }
  773: 	    }
  774:             i = script.length;
  775:           }
  776:         }
  777:       }
  778:     }
  779:     jsMath.Img.root = jsMath.root + "fonts/";
  780:     jsMath.blank = jsMath.root + "blank.gif";
  781:     this.Domain();
  782:   },
  783:   
  784:   /*
  785:    *  Find the most restricted common domain for the main
  786:    *  page and jsMath.  Report an error if jsMath is outside
  787:    *  the domain of the calling page.
  788:    */
  789:   Domain: function () {
  790:     try {jsMath.document.domain} catch (err) {return}
  791:     var jsDomain = ''; var pageDomain = jsMath.document.domain;
  792:     if (jsMath.root.match('://([^/]*)/')) {jsDomain = RegExp.$1}
  793:     jsDomain = jsDomain.replace(/:\d+$/,'');
  794:     if (jsDomain == "" || jsDomain == pageDomain) return;
  795:     //
  796:     // MSIE on the Mac can't change jsMath.document.domain and 'try' won't
  797:     //   catch the error (Grrr!), so exit for them.
  798:     //
  799:     if (navigator.appName == 'Microsoft Internet Explorer' &&
  800:         navigator.platform == 'MacPPC' && navigator.onLine &&
  801:         navigator.userProfile && jsMath.document.all) return;
  802:     jsDomain = jsDomain.split(/\./); pageDomain = pageDomain.split(/\./);
  803:     if (jsDomain.length < 2 || pageDomain.length < 2 ||
  804:         jsDomain[jsDomain.length-1] != pageDomain[pageDomain.length-1] ||
  805:         jsDomain[jsDomain.length-2] != pageDomain[pageDomain.length-2]) {
  806:       this.DomainWarning();
  807:       return;
  808:     }
  809:     var domain = jsDomain[jsDomain.length-2] + '.' + jsDomain[jsDomain.length-1];
  810:     for (var i = 3; i <= jsDomain.length && i <= pageDomain.length; i++) {
  811:       if (jsDomain[jsDomain.length-i] != pageDomain[pageDomain.length-i]) break;
  812:       domain = jsDomain[jsDomain.length-i] + '.' + domain;
  813:     }
  814:     jsMath.document.domain = domain;
  815:     this.domainChanged = 1;
  816:   },
  817: 
  818:   DomainWarning: function () {
  819:     alert("In order for jsMath to be able to load the additional "
  820:         + "components that it may need, the jsMath.js file must be "
  821:         + "loaded from a server in the same domain as the page that "
  822:         + "contains it.  Because that is not the case for this page, "
  823:         + "the mathematics displayed here may not appear correctly.");
  824:   },
  825:   
  826:   /*
  827:    *  Initialize a font's encoding array
  828:    */
  829:   EncodeFont: function (name) {
  830:     var font = jsMath.TeX[name];
  831:     if (font[0].c != null) return;
  832:     for (var k = 0; k < 128; k++) {
  833:       var data = font[k]; font[k] = data[3];
  834:       if (font[k] == null) {font[k] = {}};
  835:       font[k].w = data[0]; font[k].h = data[1];
  836:       if (data[2] != null) {font[k].d = data[2]}
  837:       font[k].c = jsMath.TeX.encoding[k];
  838:     }
  839:   },
  840:   
  841:   /*
  842:    *  Initialize the encodings for all fonts
  843:    */
  844:   Fonts: function () {
  845:     for (var i = 0; i < jsMath.TeX.fam.length; i++) {
  846:       var name = jsMath.TeX.fam[i];
  847:       if (name) {this.EncodeFont(name)}
  848:     }
  849:   },
  850:   
  851:   /*
  852:    *  Look up the default height and depth for a TeX font
  853:    *  and set the skewchar
  854:    */
  855:   TeXfont: function (name) {
  856:     var font = jsMath.TeX[name]; if (font == null) return;
  857:     var WH = jsMath.EmBoxFor('<span class="'+name+'">'+font[65].c+'</span>');
  858:     font.hd = WH.h; font.dh = .05;
  859:     font.d = jsMath.EmBoxFor('<span class="'+name+'">'+ font[65].c +
  860:       jsMath.HTML.Rule(1,font.hd) + '</span>').h - font.hd;
  861:     font.h = font.hd - font.d;
  862:     if (name == 'cmmi10') {font.skewchar = 0177} 
  863:     else if (name == 'cmsy10') {font.skewchar = 060}
  864:   },
  865: 
  866:   /*
  867:    *  Init all the TeX fonts
  868:    */
  869:   TeXfonts: function () {
  870:     for (var i = 0; i < jsMath.TeX.fam.length; i++) 
  871:       {if (jsMath.TeX.fam[i]) {this.TeXfont(jsMath.TeX.fam[i])}}
  872:   },
  873: 
  874:   /*
  875:    *  Compute font parameters for various sizes
  876:    */
  877:   Sizes: function () {
  878:     jsMath.TeXparams = [];
  879:     for (var j=0; j < jsMath.sizes.length; j++) {jsMath.TeXparams[j] = {}}
  880:     for (var i in jsMath.TeX) {
  881:       if (typeof(jsMath.TeX[i]) != 'object') {
  882:         for (var j=0; j < jsMath.sizes.length; j++) {
  883:           jsMath.TeXparams[j][i] = jsMath.sizes[j]*jsMath.TeX[i]/100;
  884:         }
  885:       }
  886:     }
  887:   },
  888: 
  889:   /*
  890:    *  Send the style definitions to the browser (these may be adjusted
  891:    *  by the browser-specific code)
  892:    */
  893:   Styles: function (styles) {
  894:     if (!styles) {
  895:       styles = jsMath.styles;
  896:       styles['.typeset .scale'] = 'font-size:'+jsMath.Controls.cookie.scale+'%';
  897:       this.stylesReady = 1;
  898:     }
  899:     jsMath.Script.Push(this,'AddStyleSheet',styles);
  900:     if (jsMath.Browser.styleChangeDelay) {jsMath.Script.Push(jsMath.Script,'Delay',1)}
  901:   },
  902:   
  903:   AddStyleSheet: function (styles) {
  904:     var head = jsMath.document.getElementsByTagName('head')[0];
  905:     var string = ''; for (var id in styles) {string += id + ' {'+styles[id]+"}\n"}
  906:     if (jsMath.document.createStyleSheet) {// check for MSIE
  907:       head.insertAdjacentHTML('beforeEnd',
  908:           '<span style="display:none">x</span>'  // MSIE needs this for some reason
  909:           + '<style type="text/css">'+string+'</style>');
  910:     } else {
  911:       var style = jsMath.document.createElement('style'); style.type = "text/css";
  912:       style.appendChild(jsMath.document.createTextNode(string));
  913:       head.appendChild(style);
  914:     }
  915:   },
  916: 
  917:   /*
  918:    *  Do the initialization that requires the <body> to be in place.
  919:    */
  920:   Body: function () {
  921:     if (this.inited) return;
  922: 
  923:     this.inited = -1;
  924: 
  925:     jsMath.Setup.Hidden(); this.inited = -2;
  926:     jsMath.Browser.Init(); this.inited = -3;
  927: 
  928:     // blank screen if necessary
  929:     if (jsMath.Controls.cookie.blank) {jsMath.Message.Blank()}; this.inited = -4;
  930: 
  931:     jsMath.Setup.Styles(); this.inited = -5;
  932:     jsMath.Controls.Init(); this.inited = -6;
  933:     
  934:     // do user-specific initialization
  935:     jsMath.Script.Push(jsMath.Setup,'User','pre-font'); this.inited = -7;
  936: 
  937:     // make sure browser-specific loads are done before this
  938:     jsMath.Script.Push(jsMath.Font,'Check');
  939:     if (jsMath.Font.register.length)
  940:       {jsMath.Script.Push(jsMath.Font,'LoadRegistered')}
  941:     
  942:     this.inited = 1;
  943:   },
  944:   
  945:   /*
  946:    *  Web page author can override this to do initialization
  947:    *  that must be done before the font check is performed, or
  948:    *  at other times (as indicated by the value of the parameter).
  949:    */
  950:   User: function (when) {}
  951:   
  952: };
  953: 
  954: jsMath.Update = {
  955: 
  956:   /*
  957:    *  Update specific parameters for a limited number of font entries
  958:    */
  959:   TeXfonts: function (change) {
  960:     for (var font in change) {
  961:       for (var code in change[font]) {
  962:         for (var id in change[font][code]) {
  963:           jsMath.TeX[font][code][id] = change[font][code][id];
  964:         }
  965:       }
  966:     }
  967:   },
  968:   
  969:   /*
  970:    *  Update the character code for every character in a list
  971:    *  of fonts
  972:    */
  973:   TeXfontCodes: function (change) {
  974:     for (var font in change) {
  975:       for (var i = 0; i < change[font].length; i++) {
  976:         jsMath.TeX[font][i].c = change[font][i];
  977:       }
  978:     }
  979:   }
  980:   
  981: };
  982: 
  983: /***************************************************************************/
  984: 
  985: /*
  986:  *  Implement browser-specific checks
  987:  */
  988: 
  989: jsMath.Browser = {
  990: 
  991:   allowAbsolute: 1,           // tells if browser can nest absolutely positioned
  992:                               //   SPANs inside relative SPANs
  993:   allowAbsoluteDelim: 0,      // OK to use absolute placement for building delims?
  994:   separateSkips: 0,           // MSIE doesn't do negative left margins, and
  995:                               //   Netscape doesn't combine skips well
  996: 
  997:   valignBug: 0,               // Konqueror doesn't nest vertical-align
  998:   operaHiddenFix: '',         // for Opera to fix bug with math in tables
  999:   msieCenterBugFix: '',       // for MSIE centering bug with image fonts
 1000:   msieInlineBlockFix: '',     // for MSIE alignment bug in non-quirks mode
 1001:   msieSpaceFix: '',           // for MSIE to avoid dropping empty spans
 1002:   imgScale: 1,                // MSI scales images for 120dpi screens, so compensate
 1003: 
 1004:   renameOK: 1,                // tells if brower will find a tag whose name
 1005:                               //   has been set via setAttributes
 1006:   styleChangeDelay: 0,        // true if style changes need a delay in order
 1007:                               //   for them to be available
 1008: 
 1009:   delay: 1,                   // delay for asynchronous math processing
 1010:   
 1011:   version: 0,                 // browser version number (when needed)
 1012: 
 1013:   /*
 1014:    *  Determine if the "top" of a <SPAN> is always at the same height
 1015:    *  or varies with the height of the rest of the line (MSIE).
 1016:    */
 1017:   TestSpanHeight: function () {
 1018:     jsMath.hidden.innerHTML = '<span><span style="'+this.block+';height:2em;width:1px"></span></span>';
 1019:     var span = jsMath.hidden.firstChild;
 1020:     var img  = span.firstChild;
 1021:     this.spanHeightVaries = (span.offsetHeight >= img.offsetHeight && span.offsetHeight > 0);
 1022:     this.spanHeightTooBig = (span.offsetHeight > img.offsetHeight);
 1023:     jsMath.hidden.innerHTML = '';
 1024:   },
 1025:   
 1026:   /*
 1027:    *  Determine if an inline-block with 0 width is OK or not
 1028:    *  and decide whether to use spans or images for spacing
 1029:    */
 1030:   TestInlineBlock: function () {
 1031:     this.block = "display:-moz-inline-box";
 1032:     this.hasInlineBlock = jsMath.BBoxFor('<span style="'+this.block+';width:10px;height:5px"></span>').w > 0;
 1033:     if (this.hasInlineBlock) {
 1034:       jsMath.styles['.typeset .blank']  = jsMath.styles['.typeset .blank'].replace(/display:inline-block/,this.block);
 1035:       jsMath.styles['.typeset .spacer'] = jsMath.styles['.typeset .spacer'].replace(/display:inline-block/,'');
 1036:     } else {
 1037:       this.block = "display:inline-block";
 1038:       this.hasInlineBlock = jsMath.BBoxFor('<span style="'+this.block+';width:10px;height:5px"></span>').w > 0;
 1039:       if (!this.hasInlineBlock) return;
 1040:     }
 1041:     this.block += ';overflow:hidden';
 1042:     var h = jsMath.BBoxFor('x').h;
 1043:     this.mozInlineBlockBug = jsMath.BBoxFor(
 1044:        '<span style="'+this.block+';height:'+h+'px;width:1px"></span>x'+
 1045:        '<span style="'+this.block+';height:'+h+'px;width:1px;vertical-align:-'+h+'px"></span>').h > 2*h;
 1046:     this.widthAddsBorder = jsMath.BBoxFor('<span style="'+this.block+
 1047:         ';overflow:hidden;height:1px;width:10px;border-left:10px solid"></span>').w > 10;
 1048:     this.msieBorderBug =
 1049:       jsMath.BBoxFor('<span style="'+this.block+';height:'+h+'px;width:1px"></span>x').h !=
 1050:       jsMath.BBoxFor('<span style="'+this.block+';height:'+h+'px;width:1px;border-left:1px solid"></span>x').h;
 1051:     this.blankWidthBug = this.msieBorderBug ||
 1052:       jsMath.BBoxFor('<span style="'+this.block+';height:2em;width:0px"></span>').h == 0;
 1053:   },
 1054:   
 1055:   /*
 1056:    *  Determine if the NAME attribute of a tag can be changed
 1057:    *  using the setAttribute function, and then be properly
 1058:    *  returned by getElementByName.
 1059:    */
 1060:   TestRenameOK: function () {
 1061:     jsMath.hidden.innerHTML = '<span></span>';
 1062:     var test = jsMath.hidden.firstChild;
 1063:     test.setAttribute('name','jsMath_test');
 1064:     this.renameOK = (jsMath.document.getElementsByName('jsMath_test').length > 0);
 1065:     jsMath.hidden.innerHTML = '';
 1066:   },
 1067:   
 1068:   /*
 1069:    *  See if style changes occur immediately, or if we need to delay
 1070:    *  in order to let them take effect.
 1071:    */
 1072:   TestStyleChange: function () {
 1073:     jsMath.hidden.innerHTML = '<span ID="jsMath_test">x</span>';
 1074:     var span = jsMath.hidden.firstChild;
 1075:     var w = span.offsetWidth;
 1076:     jsMath.Setup.AddStyleSheet({'#jsMath_test': 'font-size:200%'});
 1077:     this.styleChangeDelay = (span.offsetWidth == w);
 1078:     jsMath.hidden.innerHTML = '';
 1079:   },
 1080:   
 1081:   /*
 1082:    *  Perform a version check on a standard version string
 1083:    */
 1084:   VersionAtLeast: function (v) {
 1085:     var bv = new String(this.version).split('.');
 1086:     v = new String(v).split('.'); if (v[1] == null) {v[1] = '0'}
 1087:     return bv[0] > v[0] || (bv[0] == v[0] && bv[1] >= v[1]);
 1088:   },
 1089: 
 1090:   /*
 1091:    *  Test for browser characteristics, and adjust things
 1092:    *  to overcome specific browser bugs
 1093:    */
 1094:   Init: function () {
 1095:     jsMath.browser = 'unknown';
 1096:     this.TestInlineBlock();
 1097:     this.TestSpanHeight();
 1098:     this.TestRenameOK();
 1099:     this.TestStyleChange();
 1100: 
 1101:     this.MSIE();
 1102:     this.Mozilla();
 1103:     this.Opera();
 1104:     this.OmniWeb();
 1105:     this.Safari();
 1106:     this.Konqueror();
 1107:     
 1108:     //
 1109:     // Change some routines depending on the browser
 1110:     // 
 1111:     if (this.allowAbsoluteDelim) {
 1112:       jsMath.Box.DelimExtend = jsMath.Box.DelimExtendAbsolute;
 1113:       jsMath.Box.Layout = jsMath.Box.LayoutAbsolute;
 1114:     } else {
 1115:       jsMath.Box.DelimExtend = jsMath.Box.DelimExtendRelative;
 1116:       jsMath.Box.Layout = jsMath.Box.LayoutRelative;
 1117:     }
 1118:     
 1119:     if (this.separateSkips) {
 1120:       jsMath.HTML.Place = jsMath.HTML.PlaceSeparateSkips;
 1121:       jsMath.Typeset.prototype.Place = jsMath.Typeset.prototype.PlaceSeparateSkips;
 1122:     }
 1123:   },
 1124:   
 1125:   //
 1126:   //  Handle bug-filled Internet Explorer
 1127:   //
 1128:   MSIE: function () {
 1129:     if (this.spanHeightVaries && !this.spanHeightTooBig) {
 1130:       jsMath.browser = 'MSIE';
 1131:       if (navigator.platform == 'Win32') {
 1132:         this.allowAbsoluteDelim = 1; this.separateSkips = 1;
 1133:         this.buttonCheck = 1; this.msieBlankBug = 1;
 1134:         this.msieDivWidthBug = 1; this.msiePositionFixedBug = 1;
 1135:         this.msieIntegralBug = 1; this.waitForImages = 1;
 1136:         this.msieAlphaBug = 1; this.alphaPrintBug = 1;
 1137:         this.msieCenterBugFix = 'position:relative; ';
 1138:         this.msieInlineBlockFix = ' display:inline-block;';
 1139: 	this.msieSpaceFix = '<span style="display:inline-block"></span>';
 1140:         jsMath.Macro('joinrel','\\mathrel{\\kern-5mu}'),
 1141:         jsMath.styles['.typeset .arial'] = "font-family: 'Arial unicode MS'";
 1142:         // MSIE doesn't implement fixed positioning, so use absolute
 1143:         jsMath.styles['#jsMath_message'] =
 1144:               jsMath.styles['#jsMath_message'].replace(/position:fixed/,"position:absolute").replace(/width:auto/,"");
 1145:         jsMath.styles['#jsMath_panel'] =
 1146:               jsMath.styles['#jsMath_panel'].replace(/position:fixed/,"position:absolute").replace(/width:auto/,"");
 1147:         jsMath.styles['#jsMath_button'] = 'width:1px; '
 1148:             + jsMath.styles['#jsMath_button'].replace(/position:fixed/,"position:absolute").replace(/width:auto/,"");
 1149:         jsMath.window.onscroll = jsMath.Controls.MoveButton;
 1150:         // MSIE needs this NOT to be inline-block
 1151:         jsMath.styles['.typeset .spacer'] =
 1152:               jsMath.styles['.typeset .spacer'].replace(/display:inline-block/,'');
 1153:         // MSIE will rescale images if the DPIs differ
 1154:         if (screen.deviceXDPI && screen.logicalXDPI 
 1155:              && screen.deviceXDPI != screen.logicalXDPI) {
 1156:           this.imgScale *= screen.logicalXDPI/screen.deviceXDPI;
 1157:           jsMath.Controls.cookie.alpha = 0;
 1158:         }
 1159:         // Handle bug with getting width of italic text
 1160:         this.italicString = '<i>x</i>';
 1161:         jsMath.EmBoxFor = jsMath.EmBoxForItalics;
 1162:       } else if (navigator.platform == 'MacPPC') {
 1163:         this.msieAbsoluteBug = 1; this.msieButtonBug = 1;
 1164:         this.msieDivWidthBug = 1; this.msieBlankBug = 1;
 1165:         jsMath.Setup.Script('jsMath-msie-mac.js');
 1166:         jsMath.Parser.prototype.macros.angle = ['Replace','ord','<font face="Symbol">&#x8B;</font>','normal'];
 1167:         jsMath.styles['#jsMath_panel']  = 'width:42em; ' + jsMath.styles['#jsMath_panel'].replace(/width:auto/,"");
 1168:         jsMath.Controls.cookie.printwarn = 0; // MSIE/Mac doesn't handle '@media screen'
 1169:       }
 1170:       jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}');
 1171:     }
 1172:   },
 1173: 
 1174:   //
 1175:   //  Handle Netscape/Mozilla (any flavor)
 1176:   //
 1177:   Mozilla: function () {
 1178:     if (jsMath.hidden.ATTRIBUTE_NODE) {
 1179:       jsMath.browser = 'Mozilla';
 1180:       if (navigator.platform == 'Win32') {this.alphaPrintBug = 1}
 1181:       this.allowAbsoluteDelim = 1;
 1182:       jsMath.styles['#jsMath_button'] = jsMath.styles['#jsMath_button'].replace(/cursor:hand/,'cursor:pointer');
 1183:       jsMath.styles['#jsMath_noFont .link'] = jsMath.styles['#jsMath_noFont .link'].replace(/cursor:hand/,'cursor:pointer');
 1184:       jsMath.Macro('not','\\mathrel{\\rlap{\\kern3mu/}}');
 1185:       if (navigator.vendor == 'Firefox') {
 1186:         this.version = navigator.vendorSub;
 1187:       } else if (navigator.userAgent.match(' Firefox/([0-9.]+)( |$)')) {
 1188:         this.version = RegExp.$1;
 1189:       }
 1190:     }
 1191:   },
 1192:   
 1193:   //
 1194:   //  Handle OmniWeb
 1195:   //
 1196:   OmniWeb: function () {
 1197:     if (navigator.accentColorName) {
 1198:       jsMath.browser = 'OmniWeb';
 1199:       this.allowAbsolute = this.hasInlineBlock;
 1200:       this.allowAbsoluteDelim = this.allowAbsolute;
 1201:       this.valignBug = !this.allowAbsolute;
 1202:       this.buttonCheck = 1; this.textNodeBug = 1;
 1203:       jsMath.noChangeGlobal = 1; // OmniWeb craches on GoGlobal
 1204:       if (!this.hasInlineBlock) {jsMath.Setup.Script('jsMath-old-browsers.js')}
 1205:     }
 1206:   },
 1207:     
 1208:   //
 1209:   //  Handle Opera
 1210:   //
 1211:   Opera: function () {
 1212:     if (this.spanHeightTooBig) {
 1213:       jsMath.browser = 'Opera';
 1214:       var isOld = navigator.userAgent.match("Opera 7");
 1215:       this.allowAbsolute = 0;
 1216:       this.delay = 10;
 1217:       this.operaHiddenFix = '[Processing]';
 1218:       if (isOld) {jsMath.Setup.Script('jsMath-old-browsers.js')}
 1219:     }
 1220:   },
 1221: 
 1222:   //
 1223:   //  Handle Safari
 1224:   //
 1225:   Safari: function () {
 1226:     if (navigator.appVersion.match(/Safari\//)) {
 1227:       jsMath.browser = 'Safari';
 1228:       var version = navigator.userAgent.match("Safari/([0-9]+)");
 1229:       version = (version)? version[1] : 400;
 1230:       for (var i = 0; i < jsMath.TeX.fam.length; i++) {
 1231:         if (jsMath.TeX.fam[i] && jsMath.TeX[jsMath.TeX.fam[i]])
 1232:           {jsMath.TeX[jsMath.TeX.fam[i]].dh = .1}
 1233:       }
 1234:       jsMath.TeX.axis_height += .05;
 1235:       jsMath.TeX.default_rule_thickness += .025;
 1236:       this.allowAbsoluteDelim = version >= 125;
 1237:       this.safariIFRAMEbug = version >= 312 && version < 412;
 1238:       this.safariButtonBug = version < 412;
 1239:       this.safariImgBug = 1; this.textNodeBug = 1;
 1240:       this.buttonCheck = 1;
 1241:       this.styleChangeDelay = 1;
 1242:     }
 1243:   },
 1244:   
 1245:   //
 1246:   //  Handle Konqueror
 1247:   //
 1248:   Konqueror: function () {
 1249:     if (navigator.product && navigator.product.match("Konqueror")) {
 1250:       jsMath.browser = 'Konqueror';
 1251:       this.allowAbsolute = 0;
 1252:       this.allowAbsoluteDelim = 0;
 1253:       if (navigator.userAgent.match(/Konqueror\/(\d+)\.(\d+)/)) {
 1254:         if (RegExp.$1 < 3 || (RegExp.$1 == 3 && RegExp.$2 < 3)) {
 1255:           this.separateSkips = 1;
 1256:           this.valignBug = 1;
 1257:           jsMath.Setup.Script('jsMath-old-browsers.js');
 1258:         }
 1259:       }
 1260:     }
 1261:   }
 1262: 
 1263: };
 1264: 
 1265: /***************************************************************************/
 1266: 
 1267: /*
 1268:  *  Implement font check and messages
 1269:  */
 1270: jsMath.Font = {
 1271:   
 1272:   fallback: "symbol", // the default fallback method
 1273:   register: [],       // list of fonts registered before jsMath.Init()
 1274: 
 1275:   // the HTML for the missing font message
 1276:   message:    
 1277:     '<b>No jsMath TeX fonts found</b> -- using image fonts instead.<br/>\n'
 1278:       + 'These may be slow and might not print well.<br/>\n'
 1279:       + 'Use the jsMath control panel to get additional information.',
 1280:       
 1281:   extra_message:
 1282:     'Extra TeX fonts not found: <b><span id="jsMath_ExtraFonts"></span></b><br/>'
 1283:       + 'Using image fonts instead.  This may be slow and might not print well.<br/>\n'
 1284:       + 'Use the jsMath control panel to get additional information.',
 1285: 
 1286:   print_message:
 1287:     'To print higher-resolution math symbols, click the<br/>\n'
 1288:        + '<b>Hi-res Fonts for Printing</b> button on the jsMath control panel.<br/>\n',
 1289: 
 1290:   alpha_message:
 1291:     'If the math symbols print as black boxes, turn off <b>image alpha channels</b><br/>\n'
 1292:        + 'using the <B>Options</B> pane of the jsMath control panel.<br/>\n',
 1293:   
 1294:   /*
 1295:    *  Look to see if a font is found.
 1296:    *  Check the character in a given position, and see if it is
 1297:    *  wider than the usual one in that position.
 1298:    */
 1299:   Test1: function (name,n,factor,prefix) {
 1300:     if (n == null) {n = 0x7C}; if (factor == null) {factor = 2}; if (prefix == null) {prefix = ''}
 1301:     var wh1 = jsMath.BBoxFor('<span style="font-family: '+prefix+name+', serif">'+jsMath.TeX[name][n].c+'</span>');
 1302:     var wh2 = jsMath.BBoxFor('<span style="font-family: serif">'+jsMath.TeX[name][n].c+'</span>');
 1303:     //alert([wh1.w,wh2.w,wh1.h,factor*wh2.w]);
 1304:     return (wh1.w > factor*wh2.w && wh1.h != 0);
 1305:   },
 1306: 
 1307:   Test2: function (name,n,factor,prefix) {
 1308:     if (n == null) {n = 0x7C}; if (factor == null) {factor = 2}; if (prefix == null) {prefix = ''}
 1309:     var wh1 = jsMath.BBoxFor('<span style="font-family: '+prefix+name+', serif">'+jsMath.TeX[name][n].c+'</span>');
 1310:     var wh2 = jsMath.BBoxFor('<span style="font-family: serif">'+jsMath.TeX[name][n].c+'</span>');
 1311:     //alert([wh2.w,wh1.w,wh1.h,factor*wh1.w]);
 1312:     return (wh2.w > factor*wh1.w && wh1.h != 0);
 1313:   },
 1314:   
 1315:   /*
 1316:    *  Check for the new jsMath versions of the fonts (blacker with
 1317:    *  different encoding) and if not found, look for old-style fonts.
 1318:    *  If they are found, load the BaKoMa encoding information.
 1319:    */
 1320:   CheckTeX: function () {
 1321:     var wh = jsMath.BBoxFor('<span style="font-family: jsMath-cmex10, serif">'+jsMath.TeX.cmex10[1].c+'</span>');
 1322:     jsMath.nofonts = ((wh.w*3 > wh.h || wh.h == 0) && !this.Test1('cmr10',null,null,'jsMath-'));
 1323:     if (jsMath.nofonts && (navigator.platform != "MacPPC" ||
 1324:         jsMath.browser != 'Mozilla' || !jsMath.Browser.VersionAtLeast(1.5))) {
 1325:       wh = jsMath.BBoxFor('<span style="font-family: cmex10, serif">'+jsMath.TeX.cmex10[1].c+'</span>');
 1326:       jsMath.nofonts = ((wh.w*3 > wh.h || wh.h == 0) && !this.Test1('cmr10'));
 1327:       if (!jsMath.nofonts) {jsMath.Setup.Script("jsMath-BaKoMa-fonts.js")}
 1328:     }
 1329:   },
 1330:   
 1331:   /*
 1332:    *  Check for the availability of TeX fonts.  We do this by looking at
 1333:    *  the width and height of a character in the cmex10 font.  The cmex10
 1334:    *  font has depth considerably greater than most characters' widths (the
 1335:    *  whole font has the depth of the character with greatest depth).  This
 1336:    *  is not the case for most fonts, so if we can access cmex10, the
 1337:    *  height of a character should be much bigger than the width.
 1338:    *  Otherwise, if we don't have cmex10, we'll get a character in another
 1339:    *  font with normal height and width.  In this case, we insert a message
 1340:    *  pointing the user to the jsMath site, and load one of the fallback
 1341:    *  definitions.
 1342:    *  
 1343:    */
 1344:   Check: function () {
 1345:     var cookie = jsMath.Controls.cookie;
 1346:     this.CheckTeX();
 1347:     if (jsMath.nofonts) {
 1348:       if (cookie.autofont || cookie.font == 'tex') {
 1349:         cookie.font = this.fallback;
 1350:         if (cookie.warn) {
 1351:           jsMath.nofontMessage = 1;
 1352:           cookie.warn = 0; jsMath.Controls.SetCookie(0);
 1353:           if (jsMath.window.NoFontMessage) {jsMath.window.NoFontMessage()}
 1354:                                else {this.Message(this.message)}
 1355:         }
 1356:       }
 1357:     } else {
 1358:       if (cookie.autofont) {cookie.font = 'tex'}
 1359:       if (cookie.font == 'tex') return;
 1360:     }
 1361:     if (jsMath.noImgFonts) {cookie.font = 'unicode'}
 1362:     if (cookie.font == 'unicode') {
 1363:       var platform = ({Win32: 'pc', MacPPC: 'mac'})[navigator.platform] || 'unix';
 1364:       jsMath.Setup.Script('jsMath-fallback-'+platform+'.js');
 1365:       jsMath.Box.TeXnonfallback = jsMath.Box.TeX;
 1366:       jsMath.Box.TeX = jsMath.Box.TeXfallback;
 1367:       return;
 1368:     }
 1369:     if (!cookie.print && cookie.printwarn) {
 1370:       this.PrintMessage(
 1371:         (jsMath.Browser.alphaPrintBug && jsMath.Controls.cookie.alpha) ?
 1372:           this.print_message + this.alpha_message : this.print_message);
 1373:     }
 1374:     if (jsMath.Browser.waitForImages) {
 1375:       jsMath.Script.Push(jsMath.Script,"WaitForImage",jsMath.blank);
 1376:     }
 1377:     if (cookie.font == 'symbol') {
 1378:       jsMath.Setup.Script('jsMath-fallback-symbols.js');
 1379:       jsMath.Box.TeXnonfallback = jsMath.Box.TeX;
 1380:       jsMath.Box.TeX = jsMath.Box.TeXfallback;
 1381:       return;
 1382:     }
 1383:     jsMath.Img.SetFont({
 1384:       cmr10:  ['all'], cmmi10: ['all'], cmsy10: ['all'],
 1385:       cmex10: ['all'], cmbx10: ['all'], cmti10: ['all']
 1386:     });
 1387:     jsMath.Img.LoadFont('cm-fonts');
 1388:   },
 1389: 
 1390:   /*
 1391:    *  The message for when no TeX fonts.  You can eliminate this message
 1392:    *  by including
 1393:    *  
 1394:    *      <script>jsMath = {Font: {Message: function () {}}}</script>
 1395:    *
 1396:    *  in your HTML file, before loading jsMath.js, if you want.  But this
 1397:    *  means the user may not know that he or she can get a better version
 1398:    *  of your page.
 1399:    */
 1400:   Message: function (message) {
 1401:     if (jsMath.Element("Warning")) return;
 1402:     var div = jsMath.Setup.DIV("Warning",{});
 1403:     div.innerHTML = 
 1404:       '<center><table><tr><td>'
 1405:       + '<div id="jsMath_noFont"><div class="message">' + message
 1406:       + '<div style="text-align:left"><span style="float:left; margin: 8px 0px 0px 20px">'
 1407:       + '<span onclick="jsMath.Controls.Panel()" title=" Open the jsMath Control Panel " class="link">jsMath Control Panel</span>'
 1408:       + '</span><span style="margin: 8px 20px 0px 0px; float:right">'
 1409:       + '<span onclick="jsMath.Font.HideMessage()" title=" Remove this font warning message " class="link">Hide this Message</span>'
 1410:       + '</span></div><div style="height:6px"></div><br clear="all"/></div></div>'
 1411:       + '<div style="width:22em; height:1px"></div>'
 1412:       + '</td></tr></table></center><hr/>';
 1413:   },
 1414:   
 1415:   HideMessage: function () {
 1416:     var message = jsMath.Element("Warning");
 1417:     if (message) {message.style.display = "none"}
 1418:   },
 1419:   
 1420:   PrintMessage: function (message) {
 1421:     if (jsMath.Element("PrintWarning")) return;
 1422:     var div = jsMath.Setup.DIV("PrintWarning",{});
 1423:     div.innerHTML = 
 1424:       '<center><table><tr><td>'
 1425:       + '<div class="message">' + message + '</div>'
 1426:       + '<div style="width:22em; height:1px"></div>'
 1427:       + '</td></tr></table></center><hr/>';
 1428:   },
 1429:   
 1430:   /*
 1431:    *  Register an extra font so jsMath knows about it
 1432:    */
 1433:   Register: function (data,force) {
 1434:     if (typeof(data) == 'string') {data = {name: data}}
 1435:     if (!jsMath.Setup.inited && !force) {
 1436:       this.register[this.register.length] = data;
 1437:       return;
 1438:     }
 1439:     var fontname = data.name; var name = fontname.replace(/10$/,'');
 1440:     var fontfam = jsMath.TeX.fam.length;
 1441:     if (data.prefix == null) {data.prefix = ""}
 1442:     if (!data.style) {data.style = "font-family: "+data.prefix+fontname+", serif"}
 1443:     if (!data.styles) {data.styles = {}}
 1444:     if (!data.macros) {data.macros = {}}
 1445:     /*
 1446:      *  Register font family
 1447:      */
 1448:     jsMath.TeX.fam[fontfam] = fontname;
 1449:     jsMath.TeX.famName[fontname] = fontfam;
 1450:     data.macros[name] = ['HandleFont',fontfam];
 1451:     jsMath.Add(jsMath.Parser.prototype.macros,data.macros);
 1452:     /*
 1453:      *  Set up styles
 1454:      */
 1455:     data.styles['.typeset .'+fontname] = data.style;
 1456:     jsMath.Setup.Styles(data.styles);
 1457:     if (jsMath.initialized) {jsMath.Script.Push(jsMath.Setup,'TeXfont',fontname)}
 1458:     /*
 1459:      *  Check for font and give message if missing
 1460:      */
 1461:     var hasTeXfont = !jsMath.nofonts &&
 1462:                       data.test(fontname,data.testChar,data.testFactor,data.prefix);
 1463:     if (hasTeXfont && jsMath.Controls.cookie.font == 'tex') {
 1464:       if (data.tex) {data.tex(fontname,fontfam,data)}
 1465:       return;
 1466:     }
 1467:     if (!hasTeXfont && jsMath.Controls.cookie.warn &&
 1468:         jsMath.Controls.cookie.font == 'tex' && !jsMath.nofonts) {
 1469:       if (!jsMath.Element("Warning")) this.Message(this.extra_message);
 1470:       var extra = jsMath.Element("ExtraFonts");
 1471:       if (extra) {
 1472:         if (extra.innerHTML != "") {extra.innerHTML += ','}
 1473:         extra.innerHTML += " " + data.prefix+fontname;
 1474:       }
 1475:     }
 1476:     if (jsMath.Controls.cookie.font == 'unicode') {
 1477:       if (data.fallback) {data.fallback(fontname,fontfam,data)}
 1478:       return;
 1479:     }
 1480:     //  Image fonts
 1481:     var font = {}; font[fontname] = ['all'];
 1482:     jsMath.Img.SetFont(font);
 1483:     jsMath.Img.LoadFont(fontname);
 1484:     if (jsMath.initialized) {
 1485:       jsMath.Script.Push(jsMath.Img,'Scale');
 1486:       jsMath.Script.Push(jsMath.Img,'UpdateFonts');
 1487:     }
 1488:   },
 1489:   /*
 1490:    *  If fonts are registered before jsMath.Init() is called, jsMath.em
 1491:    *  will not be available, so they need to be delayed.
 1492:    */
 1493:   LoadRegistered: function () {
 1494:     var i = 0;
 1495:     while (i < this.register.length) {this.Register(this.register[i++],1)}
 1496:     this.register = [];
 1497:   },
 1498: 
 1499:   /*
 1500:    *  Load a font
 1501:    */
 1502:   Load: function (name) {jsMath.Setup.Script(this.URL(name))},
 1503:   URL: function (name) {return jsMath.Img.root+name+'/def.js'}
 1504:   
 1505: };
 1506: 
 1507: /***************************************************************************/
 1508: 
 1509: /*
 1510:  *  Implements the jsMath control panel.
 1511:  *  Much of the code is in jsMath-controls.html, which is
 1512:  *  loaded into a hidden IFRAME on demand
 1513:  */
 1514: jsMath.Controls = {
 1515: 
 1516:   //  Data stored in the jsMath cookie
 1517:   cookie: {
 1518:     scale: 100,
 1519:     font: 'tex', autofont: 1, scaleImg: 0, alpha: 1,
 1520:     warn: 1, printwarn: 1, stayhires: 0,
 1521:     button: 1, progress: 1, asynch: 0, blank: 0,
 1522:     print: 0, keep: '0D', global: 'auto', hiddenGlobal: 1
 1523:   },
 1524:   
 1525:   cookiePath: '/',  // can also set cookieDomain
 1526:   noCookiePattern: /^(file|mk):$/,  // pattern for handling cookies locally
 1527:   
 1528:   
 1529:   /*
 1530:    *  Create the HTML needed for control panel
 1531:    */
 1532:   Init: function () {
 1533:     this.panel = jsMath.Setup.DIV("panel",{display:'none'});
 1534:     if (!jsMath.Browser.msieButtonBug) {this.Button()}
 1535:       else {setTimeout("jsMath.Controls.Button()",500)}
 1536:   },
 1537: 
 1538:   /*
 1539:    *  Load the control panel
 1540:    */
 1541:   Panel: function () {
 1542:     jsMath.Translate.Cancel();
 1543:     if (this.loaded) {this.Main()}
 1544:       else {jsMath.Script.delayedLoad(jsMath.root+"jsMath-controls.html")}
 1545:   },
 1546:   
 1547:   /*
 1548:    *  Create the control panel button
 1549:    */
 1550:   Button: function () {
 1551:     var button = jsMath.Setup.DIV("button",{});
 1552:     button.title = ' Open jsMath Control Panel ';
 1553:     button.innerHTML = 
 1554:       '<span onclick="jsMath.Controls.Panel()">jsMath</span>';
 1555:     if (!jsMath.Global.isLocal && !jsMath.noShowGlobal) {
 1556:       button.innerHTML +=
 1557:         '<span id="jsMath_global" title=" Open jsMath Global Panel " '
 1558:           + 'onclick="jsMath.Global.Show(1)">Global&nbsp;</span>';
 1559:     }
 1560:     if (button.offsetWidth < 30) {button.style.width = "auto"}
 1561:     if (!this.cookie.button) {button.style.display = "none"}
 1562:   },
 1563:   
 1564:  /*
 1565:   *  MSIE doesn't implement position:fixed, so redraw the button on scrolls.
 1566:   */
 1567:   MoveButton: function () {
 1568:     if (!this.button) {this.button = jsMath.Element("button")}
 1569:     this.button.style.visibility = "hidden";
 1570:     this.button.style.visibility = "visible";
 1571:   },
 1572: 
 1573:   /*
 1574:    *  Get the cookie data from the browser
 1575:    *  (for file: references, use url '?' syntax)
 1576:    */
 1577:   GetCookie: function () {
 1578:     // save the current cookie settings as the defaults
 1579:     if (this.defaults == null) {this.defaults = {}}
 1580:     jsMath.Add(this.defaults,this.cookie); this.userSet = {};
 1581:     // get the browser's cookie data
 1582:     var cookies = jsMath.document.cookie;
 1583:     if (jsMath.window.location.protocol.match(this.noCookiePattern)) {
 1584:       cookies = this.localGetCookie();
 1585:       this.isLocalCookie = 1;
 1586:     }
 1587:     if (cookies.match(/jsMath=([^;]+)/)) {
 1588:       var data = RegExp.$1.split(/,/);
 1589:       for (var i = 0; i < data.length; i++) {
 1590:         var x = data[i].match(/(.*):(.*)/);
 1591:         if (x[2].match(/^\d+$/)) {x[2] = 1*x[2]} // convert from string
 1592:         this.cookie[x[1]] = x[2];
 1593:         this.userSet[x[1]] = 1;
 1594:       }
 1595:     }
 1596:   },
 1597:   localGetCookie: function () {
 1598:     return unescape(jsMath.window.location.search.substr(1));
 1599:   },
 1600:   
 1601:   /*
 1602:    *  Save the cookie data in the browser
 1603:    *  (for file: urls, append data like CGI reference)
 1604:    */
 1605:   SetCookie: function (warn) {
 1606:     var cookie = [];
 1607:     for (var id in this.cookie) {
 1608:       if (this.defaults[id] == null || this.cookie[id] != this.defaults[id])
 1609:         {cookie[cookie.length] = id + ':' + this.cookie[id]}
 1610:     }
 1611:     cookie = cookie.join(',');
 1612:     if (this.isLocalCookie) {
 1613:       if (warn == 2) {return 'jsMath='+escape(cookie)}
 1614:       this.localSetCookie(cookie,warn);
 1615:     } else {
 1616:       if (cookie == '') {warn = 0}
 1617:       if (this.cookiePath) {cookie += '; path='+this.cookiePath}
 1618:       if (this.cookieDomain) {cookie += '; domain='+this.cookieDomain}
 1619:       if (this.cookie.keep != '0D') {
 1620:         var ms = {
 1621:           D: 1000*60*60*24,
 1622:           W: 1000*60*60*24*7,
 1623:           M: 1000*60*60*24*30,
 1624:           Y: 1000*60*60*24*365
 1625:         };
 1626:         var exp = new Date;
 1627:         exp.setTime(exp.getTime() +
 1628:             this.cookie.keep.substr(0,1) * ms[this.cookie.keep.substr(1,1)]);
 1629:         cookie += '; expires=' + exp.toGMTString();
 1630:       }
 1631:       if (cookie != '') {
 1632:         jsMath.document.cookie = 'jsMath='+cookie;
 1633:         var cookies = jsMath.document.cookie;
 1634:         if (warn && !cookies.match(/jsMath=/))
 1635:           {alert("Cookies must be enabled in order to save jsMath options")}
 1636:       }
 1637:     }
 1638:     return null;
 1639:   },
 1640:   localSetCookie: function (cookie,warn) {
 1641:     if (!warn) return;
 1642:     var href = String(jsMath.window.location).replace(/\?.*/,"");
 1643:     if (cookie != '') {href += '?jsMath=' + escape(cookie)}
 1644:     if (href != jsMath.window.location.href) {this.Reload(href)}
 1645:   },
 1646:   
 1647:   /*
 1648:    *  Reload the page (with the given URL)
 1649:    */
 1650:   Reload: function (url) {
 1651:     if (!this.loaded) return;
 1652:     this.loaded = 0;
 1653:     jsMath.Global.ClearCache();
 1654:     if (url) {jsMath.window.location.replace(url)}
 1655:         else {jsMath.window.location.reload()}
 1656:   }
 1657:   
 1658: };
 1659: 
 1660: /***************************************************************************/
 1661: 
 1662: /*
 1663:  *  Implements the actions for clicking and double-clicking
 1664:  *  on math formulas
 1665:  */
 1666: jsMath.Click = {
 1667:   
 1668:   /*
 1669:    *  Handle clicking on math to get control panel
 1670:    */
 1671:   CheckClick: function (event) {
 1672:     if (!event) {event = jsMath.window.event}
 1673:     if (event.altKey) jsMath.Controls.Panel();
 1674:   },
 1675:   
 1676:   /*
 1677:    *  Handle double-click for seeing TeX code
 1678:    */
 1679: 
 1680:   CheckDblClick: function (event) {
 1681:     if (!event) {event = jsMath.window.event}
 1682:     if (!jsMath.Click.DblClick) {
 1683:       jsMath.Extension.Require('double-click',1);
 1684:       // Firefox clears the event, so copy it
 1685:       var tmpEvent = event; event = {};
 1686:       for (var id in tmpEvent) {event[id] = tmpEvent[id]}
 1687:     }
 1688:     jsMath.Script.Push(jsMath.Click,'DblClick',[event,this.alt]);
 1689:   }
 1690:   
 1691: };
 1692: 
 1693: /***************************************************************************/
 1694: 
 1695: /*
 1696:  *  The TeX font information
 1697:  */
 1698: jsMath.TeX = {
 1699: 
 1700:   //
 1701:   //  The TeX font parameters
 1702:   //
 1703:   thinmuskip:   3/18,
 1704:   medmuskip:    4/18,
 1705:   thickmuskip:  5/18,
 1706: 
 1707:   x_height:    .430554,
 1708:   quad:        1,
 1709:   num1:        .676508,
 1710:   num2:        .393732,
 1711:   num3:        .44373,
 1712:   denom1:      .685951,
 1713:   denom2:      .344841,
 1714:   sup1:        .412892,
 1715:   sup2:        .362892,
 1716:   sup3:        .288888,
 1717:   sub1:        .15,
 1718:   sub2:        .247217,
 1719:   sup_drop:    .386108,
 1720:   sub_drop:    .05,
 1721:   delim1:     2.39,
 1722:   delim2:     1.0,
 1723:   axis_height: .25,
 1724:   default_rule_thickness: .06,
 1725:   big_op_spacing1:  .111111,
 1726:   big_op_spacing2:  .166666,
 1727:   big_op_spacing3:  .2,
 1728:   big_op_spacing4:  .6,
 1729:   big_op_spacing5:  .1,
 1730: 
 1731:   integer:          6553.6,     // conversion of em's to TeX internal integer
 1732:   scriptspace:         .05,
 1733:   nulldelimiterspace:  .12,
 1734:   delimiterfactor:     901,
 1735:   delimitershortfall:   .5,
 1736:   scale:                 1,     //  scaling factor for font dimensions
 1737:  
 1738:   //  The TeX math atom types (see Appendix G of the TeXbook)
 1739:   atom: ['ord', 'op', 'bin', 'rel', 'open', 'close', 'punct', 'ord'],
 1740: 
 1741:   //  The TeX font families
 1742:   fam: ['cmr10','cmmi10','cmsy10','cmex10','cmti10','','cmbx10',''],
 1743:   famName: {cmr10:0, cmmi10:1, cmsy10:2, cmex10:3, cmti10:4, cmbx10:6},
 1744: 
 1745:   //  Encoding used by jsMath fonts
 1746:   encoding: [
 1747:     '&#xC0;', '&#xC1;', '&#xC2;', '&#xC3;', '&#xC4;', '&#xC5;', '&#xC6;', '&#xC7;',
 1748:     '&#xC8;', '&#xC9;', '&#xCA;', '&#xCB;', '&#xCC;', '&#xCD;', '&#xCE;', '&#xCF;',
 1749: 
 1750:     '&#xB0;', '&#xD1;', '&#xD2;', '&#xD3;', '&#xD4;', '&#xD5;', '&#xD6;', '&#xB7;',
 1751:     '&#xD8;', '&#xD9;', '&#xDA;', '&#xDB;', '&#xDC;', '&#xB5;', '&#xB6;', '&#xDF;',
 1752: 
 1753:     '&#xEF;', '!', '&#x22;', '#', '$', '%', '&#x26;', '&#x27;',
 1754:     '(', ')', '*', '+', ',', '-', '.', '/',
 1755: 
 1756:     '0', '1', '2', '3', '4', '5', '6', '7',
 1757:     '8', '9', ':', ';', '&#x3C;', '=', '&#x3E;', '?',
 1758: 
 1759:     '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
 1760:     'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
 1761: 
 1762:     'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
 1763:     'X', 'Y', 'Z', '[', '&#x5C;', ']', '^', '_',
 1764: 
 1765:     '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
 1766:     'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
 1767: 
 1768:     'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
 1769:     'x', 'y', 'z', '{', '|', '}', '&#x7E;', '&#xFF;'
 1770:   ],
 1771: 
 1772:   /*
 1773:    *  The following are the TeX font mappings and metrics.  The metric
 1774:    *  information comes directly from the TeX .tfm files.  Browser-specific
 1775:    *  adjustments are made to these tables in the Browser.Init() routine
 1776:    */
 1777:   cmr10: [
 1778:     [0.625,0.683], [0.833,0.683], [0.778,0.683], [0.694,0.683],
 1779:     [0.667,0.683], [0.75,0.683], [0.722,0.683], [0.778,0.683],
 1780:     [0.722,0.683], [0.778,0.683], [0.722,0.683],
 1781:     [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}}],
 1782:     [0.556,0.694], [0.556,0.694], [0.833,0.694], [0.833,0.694],
 1783: 
 1784:     [0.278,0.431], [0.306,0.431,0.194], [0.5,0.694], [0.5,0.694],
 1785:     [0.5,0.628], [0.5,0.694], [0.5,0.568], [0.75,0.694],
 1786:     [0.444,0,0.17], [0.5,0.694], [0.722,0.431], [0.778,0.431],
 1787:     [0.5,0.528,0.0972], [0.903,0.683], [1.01,0.683], [0.778,0.732,0.0486],
 1788: 
 1789:     [0.278,0.431,0,{krn: {'108': -0.278, '76': -0.319}}],
 1790:     [0.278,0.694,0,{lig: {'96': 60}}],
 1791:     [0.5,0.694], [0.833,0.694,0.194], [0.5,0.75,0.0556],
 1792:     [0.833,0.75,0.0556], [0.778,0.694],
 1793:     [0.278,0.694,0,{krn: {'63': 0.111, '33': 0.111}, lig: {'39': 34}}],
 1794:     [0.389,0.75,0.25], [0.389,0.75,0.25], [0.5,0.75],
 1795:     [0.778,0.583,0.0833], [0.278,0.106,0.194],
 1796:     [0.333,0.431,0,{lig: {'45': 123}}],
 1797:     [0.278,0.106], [0.5,0.75,0.25],
 1798: 
 1799:     [0.5,0.644], [0.5,0.644], [0.5,0.644], [0.5,0.644],
 1800:     [0.5,0.644], [0.5,0.644], [0.5,0.644], [0.5,0.644],
 1801:     [0.5,0.644], [0.5,0.644], [0.278,0.431], [0.278,0.431,0.194],
 1802:     [0.278,0.5,0.194], [0.778,0.367,-0.133], [0.472,0.5,0.194],
 1803:     [0.472,0.694,0,{lig: {'96': 62}}],
 1804: 
 1805:     [0.778,0.694],
 1806:     [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}}],
 1807:     [0.708,0.683], [0.722,0.683],
 1808:     [0.764,0.683,0,{krn: {'88': -0.0278, '87': -0.0278, '65': -0.0278, '86': -0.0278, '89': -0.0278}}],
 1809:     [0.681,0.683],
 1810:     [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}}],
 1811:     [0.785,0.683], [0.75,0.683], [0.361,0.683,0,{krn: {'73': 0.0278}}],
 1812:     [0.514,0.683],
 1813:     [0.778,0.683,0,{krn: {'79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],
 1814:     [0.625,0.683,0,{krn: {'84': -0.0833, '89': -0.0833, '86': -0.111, '87': -0.111}}],
 1815:     [0.917,0.683], [0.75,0.683],
 1816:     [0.778,0.683,0,{krn: {'88': -0.0278, '87': -0.0278, '65': -0.0278, '86': -0.0278, '89': -0.0278}}],
 1817: 
 1818:     [0.681,0.683,0,{krn: {'65': -0.0833, '111': -0.0278, '101': -0.0278, '97': -0.0278, '46': -0.0833, '44': -0.0833}}],
 1819:     [0.778,0.683,0.194],
 1820:     [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}}],
 1821:     [0.556,0.683],
 1822:     [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}}],
 1823:     [0.75,0.683],
 1824:     [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}}],
 1825:     [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}}],
 1826:     [0.75,0.683,0,{krn: {'79': -0.0278, '67': -0.0278, '71': -0.0278, '81': -0.0278}}],
 1827:     [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}}],
 1828:     [0.611,0.683], [0.278,0.75,0.25], [0.5,0.694],
 1829:     [0.278,0.75,0.25], [0.5,0.694], [0.278,0.668],
 1830: 
 1831:     [0.278,0.694,0,{lig: {'96': 92}}],
 1832:     [0.5,0.431,0,{krn: {'118': -0.0278, '106': 0.0556, '121': -0.0278, '119': -0.0278}}],
 1833:     [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}}],
 1834:     [0.444,0.431,0,{krn: {'104': -0.0278, '107': -0.0278}}],
 1835:     [0.556,0.694], [0.444,0.431],
 1836:     [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}}],
 1837:     [0.5,0.431,0.194,{ic: 0.0139, krn: {'106': 0.0278}}],
 1838:     [0.556,0.694,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],
 1839:     [0.278,0.668], [0.306,0.668,0.194],
 1840:     [0.528,0.694,0,{krn: {'97': -0.0556, '101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],
 1841:     [0.278,0.694],
 1842:     [0.833,0.431,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],
 1843:     [0.556,0.431,0,{krn: {'116': -0.0278, '117': -0.0278, '98': -0.0278, '121': -0.0278, '118': -0.0278, '119': -0.0278}}],
 1844:     [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}}],
 1845: 
 1846:     [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}}],
 1847:     [0.528,0.431,0.194], [0.392,0.431], [0.394,0.431],
 1848:     [0.389,0.615,0,{krn: {'121': -0.0278, '119': -0.0278}}],
 1849:     [0.556,0.431,0,{krn: {'119': -0.0278}}],
 1850:     [0.528,0.431,0,{ic: 0.0139, krn: {'97': -0.0556, '101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],
 1851:     [0.722,0.431,0,{ic: 0.0139, krn: {'101': -0.0278, '97': -0.0278, '111': -0.0278, '99': -0.0278}}],
 1852:     [0.528,0.431],
 1853:     [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}}],
 1854:     [0.444,0.431], [0.5,0.431,0,{ic: 0.0278, lig: {'45': 124}}],
 1855:     [1,0.431,0,{ic: 0.0278}], [0.5,0.694], [0.5,0.668], [0.5,0.668]
 1856:   ],
 1857:   
 1858:   cmmi10: [
 1859:     [0.615,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],
 1860:     [0.833,0.683,0,{krn: {'127': 0.167}}],
 1861:     [0.763,0.683,0,{ic: 0.0278, krn: {'127': 0.0833}}],
 1862:     [0.694,0.683,0,{krn: {'127': 0.167}}],
 1863:     [0.742,0.683,0,{ic: 0.0757, krn: {'127': 0.0833}}],
 1864:     [0.831,0.683,0,{ic: 0.0812, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
 1865:     [0.78,0.683,0,{ic: 0.0576, krn: {'127': 0.0833}}],
 1866:     [0.583,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0556}}],
 1867:     [0.667,0.683,0,{krn: {'127': 0.0833}}],
 1868:     [0.612,0.683,0,{ic: 0.11, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
 1869:     [0.772,0.683,0,{ic: 0.0502, krn: {'127': 0.0833}}],
 1870:     [0.64,0.431,0,{ic: 0.0037, krn: {'127': 0.0278}}],
 1871:     [0.566,0.694,0.194,{ic: 0.0528, krn: {'127': 0.0833}}],
 1872:     [0.518,0.431,0.194,{ic: 0.0556}],
 1873:     [0.444,0.694,0,{ic: 0.0378, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0556}}],
 1874:     [0.406,0.431,0,{krn: {'127': 0.0556}}],
 1875: 
 1876:     [0.438,0.694,0.194,{ic: 0.0738, krn: {'127': 0.0833}}],
 1877:     [0.497,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0556}}],
 1878:     [0.469,0.694,0,{ic: 0.0278, krn: {'127': 0.0833}}],
 1879:     [0.354,0.431,0,{krn: {'127': 0.0556}}],
 1880:     [0.576,0.431], [0.583,0.694],
 1881:     [0.603,0.431,0.194,{krn: {'127': 0.0278}}],
 1882:     [0.494,0.431,0,{ic: 0.0637, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0278}}],
 1883:     [0.438,0.694,0.194,{ic: 0.046, krn: {'127': 0.111}}],
 1884:     [0.57,0.431,0,{ic: 0.0359}],
 1885:     [0.517,0.431,0.194,{krn: {'127': 0.0833}}],
 1886:     [0.571,0.431,0,{ic: 0.0359, krn: {'59': -0.0556, '58': -0.0556}}],
 1887:     [0.437,0.431,0,{ic: 0.113, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0278}}],
 1888:     [0.54,0.431,0,{ic: 0.0359, krn: {'127': 0.0278}}],
 1889:     [0.596,0.694,0.194,{krn: {'127': 0.0833}}],
 1890:     [0.626,0.431,0.194,{krn: {'127': 0.0556}}],
 1891: 
 1892:     [0.651,0.694,0.194,{ic: 0.0359, krn: {'127': 0.111}}],
 1893:     [0.622,0.431,0,{ic: 0.0359}],
 1894:     [0.466,0.431,0,{krn: {'127': 0.0833}}],
 1895:     [0.591,0.694,0,{krn: {'127': 0.0833}}],
 1896:     [0.828,0.431,0,{ic: 0.0278}],
 1897:     [0.517,0.431,0.194,{krn: {'127': 0.0833}}],
 1898:     [0.363,0.431,0.0972,{ic: 0.0799, krn: {'127': 0.0833}}],
 1899:     [0.654,0.431,0.194,{krn: {'127': 0.0833}}],
 1900:     [1,0.367,-0.133], [1,0.367,-0.133], [1,0.367,-0.133], [1,0.367,-0.133], 
 1901:     [0.278,0.464,-0.0363], [0.278,0.464,-0.0363], [0.5,0.465,-0.0347], [0.5,0.465,-0.0347],
 1902: 
 1903:     [0.5,0.431], [0.5,0.431], [0.5,0.431], [0.5,0.431,0.194],
 1904:     [0.5,0.431,0.194], [0.5,0.431,0.194], [0.5,0.644], [0.5,0.431,0.194],
 1905:     [0.5,0.644], [0.5,0.431,0.194], [0.278,0.106], [0.278,0.106,0.194],
 1906:     [0.778,0.539,0.0391],
 1907:     [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}}],
 1908:     [0.778,0.539,0.0391], [0.5,0.465,-0.0347],
 1909: 
 1910:     [0.531,0.694,0,{ic: 0.0556, krn: {'127': 0.0833}}],
 1911:     [0.75,0.683,0,{krn: {'127': 0.139}}],
 1912:     [0.759,0.683,0,{ic: 0.0502, krn: {'127': 0.0833}}],
 1913:     [0.715,0.683,0,{ic: 0.0715, krn: {'61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
 1914:     [0.828,0.683,0,{ic: 0.0278, krn: {'127': 0.0556}}],
 1915:     [0.738,0.683,0,{ic: 0.0576, krn: {'127': 0.0833}}],
 1916:     [0.643,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],
 1917:     [0.786,0.683,0,{krn: {'127': 0.0833}}],
 1918:     [0.831,0.683,0,{ic: 0.0812, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
 1919:     [0.44,0.683,0,{ic: 0.0785, krn: {'127': 0.111}}],
 1920:     [0.555,0.683,0,{ic: 0.0962, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.167}}],
 1921:     [0.849,0.683,0,{ic: 0.0715, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0556}}],
 1922:     [0.681,0.683,0,{krn: {'127': 0.0278}}],
 1923:     [0.97,0.683,0,{ic: 0.109, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
 1924:     [0.803,0.683,0,{ic: 0.109, krn: {'61': -0.0833, '61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
 1925:     [0.763,0.683,0,{ic: 0.0278, krn: {'127': 0.0833}}],
 1926: 
 1927:     [0.642,0.683,0,{ic: 0.139, krn: {'61': -0.0556, '59': -0.111, '58': -0.111, '127': 0.0833}}],
 1928:     [0.791,0.683,0.194,{krn: {'127': 0.0833}}],
 1929:     [0.759,0.683,0,{ic: 0.00773, krn: {'127': 0.0833}}],
 1930:     [0.613,0.683,0,{ic: 0.0576, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
 1931:     [0.584,0.683,0,{ic: 0.139, krn: {'61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
 1932:     [0.683,0.683,0,{ic: 0.109, krn: {'59': -0.111, '58': -0.111, '61': -0.0556, '127': 0.0278}}],
 1933:     [0.583,0.683,0,{ic: 0.222, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],
 1934:     [0.944,0.683,0,{ic: 0.139, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],
 1935:     [0.828,0.683,0,{ic: 0.0785, krn: {'61': -0.0833, '61': -0.0278, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
 1936:     [0.581,0.683,0,{ic: 0.222, krn: {'59': -0.167, '58': -0.167, '61': -0.111}}],
 1937:     [0.683,0.683,0,{ic: 0.0715, krn: {'61': -0.0556, '59': -0.0556, '58': -0.0556, '127': 0.0833}}],
 1938:     [0.389,0.75], [0.389,0.694,0.194], [0.389,0.694,0.194],
 1939:     [1,0.358,-0.142], [1,0.358,-0.142],
 1940: 
 1941:     [0.417,0.694,0,{krn: {'127': 0.111}}],
 1942:     [0.529,0.431], [0.429,0.694], [0.433,0.431,0,{krn: {'127': 0.0556}}],
 1943:     [0.52,0.694,0,{krn: {'89': 0.0556, '90': -0.0556, '106': -0.111, '102': -0.167, '127': 0.167}}],
 1944:     [0.466,0.431,0,{krn: {'127': 0.0556}}],
 1945:     [0.49,0.694,0.194,{ic: 0.108, krn: {'59': -0.0556, '58': -0.0556, '127': 0.167}}],
 1946:     [0.477,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0278}}],
 1947:     [0.576,0.694,0,{krn: {'127': -0.0278}}], [0.345,0.66],
 1948:     [0.412,0.66,0.194,{ic: 0.0572, krn: {'59': -0.0556, '58': -0.0556}}],
 1949:     [0.521,0.694,0,{ic: 0.0315}], [0.298,0.694,0,{ic: 0.0197, krn: {'127': 0.0833}}],
 1950:     [0.878,0.431], [0.6,0.431], [0.485,0.431,0,{krn: {'127': 0.0556}}],
 1951: 
 1952:     [0.503,0.431,0.194,{krn: {'127': 0.0833}}],
 1953:     [0.446,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0833}}],
 1954:     [0.451,0.431,0,{ic: 0.0278, krn: {'59': -0.0556, '58': -0.0556, '127': 0.0556}}],
 1955:     [0.469,0.431,0,{krn: {'127': 0.0556}}], [0.361,0.615,0,{krn: {'127': 0.0833}}],
 1956:     [0.572,0.431,0,{krn: {'127': 0.0278}}],
 1957:     [0.485,0.431,0,{ic: 0.0359, krn: {'127': 0.0278}}],
 1958:     [0.716,0.431,0,{ic: 0.0269, krn: {'127': 0.0833}}],
 1959:     [0.572,0.431,0,{krn: {'127': 0.0278}}],
 1960:     [0.49,0.431,0.194,{ic: 0.0359, krn: {'127': 0.0556}}],
 1961:     [0.465,0.431,0,{ic: 0.044, krn: {'127': 0.0556}}],
 1962:     [0.322,0.431,0,{krn: {'127': 0.0278}}],
 1963:     [0.384,0.431,0.194,{krn: {'127': 0.0833}}],
 1964:     [0.636,0.431,0.194,{krn: {'127': 0.111}}],
 1965:     [0.5,0.714,0,{ic: 0.154}], [0.278,0.694,0,{ic: 0.399}]
 1966:   ],
 1967: 
 1968:   cmsy10: [
 1969:     [0.778,0.583,0.0833], [0.278,0.444,-0.0556], [0.778,0.583,0.0833],
 1970:     [0.5,0.465,-0.0347], [0.778,0.583,0.0833], [0.5,0.444,-0.0556],
 1971:     [0.778,0.583,0.0833], [0.778,0.583,0.0833], [0.778,0.583,0.0833],
 1972:     [0.778,0.583,0.0833], [0.778,0.583,0.0833], [0.778,0.583,0.0833],
 1973:     [0.778,0.583,0.0833], [1,0.694,0.194], [0.5,0.444,-0.0556], [0.5,0.444,-0.0556],
 1974: 
 1975:     [0.778,0.464,-0.0363], [0.778,0.464,-0.0363], [0.778,0.636,0.136],
 1976:     [0.778,0.636,0.136], [0.778,0.636,0.136], [0.778,0.636,0.136],
 1977:     [0.778,0.636,0.136], [0.778,0.636,0.136], [0.778,0.367,-0.133],
 1978:     [0.778,0.483,-0.0169], [0.778,0.539,0.0391], [0.778,0.539,0.0391],
 1979:     [1,0.539,0.0391], [1,0.539,0.0391], [0.778,0.539,0.0391], [0.778,0.539,0.0391],
 1980: 
 1981:     [1,0.367,-0.133], [1,0.367,-0.133], [0.5,0.694,0.194], [0.5,0.694,0.194],
 1982:     [1,0.367,-0.133], [1,0.694,0.194], [1,0.694,0.194], [0.778,0.464,-0.0363],
 1983:     [1,0.367,-0.133], [1,0.367,-0.133], [0.611,0.694,0.194], [0.611,0.694,0.194],
 1984:     [1,0.367,-0.133], [1,0.694,0.194], [1,0.694,0.194], [0.778,0.431],
 1985: 
 1986:     [0.275,0.556], [1,0.431], [0.667,0.539,0.0391], [0.667,0.539,0.0391],
 1987:     [0.889,0.694,0.194], [0.889,0.694,0.194], [0,0.694,0.194], [0,0.367,-0.133],
 1988:     [0.556,0.694], [0.556,0.694], [0.667,0.431], [0.5,0.75,0.0556],
 1989:     [0.722,0.694], [0.722,0.694], [0.778,0.694], [0.778,0.694],
 1990: 
 1991:     [0.611,0.694], [0.798,0.683,0,{krn: {'48': 0.194}}],
 1992:     [0.657,0.683,0,{ic: 0.0304, krn: {'48': 0.139}}],
 1993:     [0.527,0.683,0,{ic: 0.0583, krn: {'48': 0.139}}],
 1994:     [0.771,0.683,0,{ic: 0.0278, krn: {'48': 0.0833}}],
 1995:     [0.528,0.683,0,{ic: 0.0894, krn: {'48': 0.111}}],
 1996:     [0.719,0.683,0,{ic: 0.0993, krn: {'48': 0.111}}],
 1997:     [0.595,0.683,0.0972,{ic: 0.0593, krn: {'48': 0.111}}],
 1998:     [0.845,0.683,0,{ic: 0.00965, krn: {'48': 0.111}}],
 1999:     [0.545,0.683,0,{ic: 0.0738, krn: {'48': 0.0278}}],
 2000:     [0.678,0.683,0.0972,{ic: 0.185, krn: {'48': 0.167}}],
 2001:     [0.762,0.683,0,{ic: 0.0144, krn: {'48': 0.0556}}],
 2002:     [0.69,0.683,0,{krn: {'48': 0.139}}], [1.2,0.683,0,{krn: {'48': 0.139}}],
 2003:     [0.82,0.683,0,{ic: 0.147, krn: {'48': 0.0833}}],
 2004:     [0.796,0.683,0,{ic: 0.0278, krn: {'48': 0.111}}],
 2005: 
 2006:     [0.696,0.683,0,{ic: 0.0822, krn: {'48': 0.0833}}],
 2007:     [0.817,0.683,0.0972,{krn: {'48': 0.111}}],
 2008:     [0.848,0.683,0,{krn: {'48': 0.0833}}],
 2009:     [0.606,0.683,0,{ic: 0.075, krn: {'48': 0.139}}],
 2010:     [0.545,0.683,0,{ic: 0.254, krn: {'48': 0.0278}}],
 2011:     [0.626,0.683,0,{ic: 0.0993, krn: {'48': 0.0833}}],
 2012:     [0.613,0.683,0,{ic: 0.0822, krn: {'48': 0.0278}}],
 2013:     [0.988,0.683,0,{ic: 0.0822, krn: {'48': 0.0833}}],
 2014:     [0.713,0.683,0,{ic: 0.146, krn: {'48': 0.139}}],
 2015:     [0.668,0.683,0.0972,{ic: 0.0822, krn: {'48': 0.0833}}],
 2016:     [0.725,0.683,0,{ic: 0.0794, krn: {'48': 0.139}}],
 2017:     [0.667,0.556], [0.667,0.556], [0.667,0.556], [0.667,0.556], [0.667,0.556],
 2018: 
 2019:     [0.611,0.694], [0.611,0.694], [0.444,0.75,0.25], [0.444,0.75,0.25],
 2020:     [0.444,0.75,0.25], [0.444,0.75,0.25], [0.5,0.75,0.25], [0.5,0.75,0.25],
 2021:     [0.389,0.75,0.25], [0.389,0.75,0.25], [0.278,0.75,0.25], [0.5,0.75,0.25],
 2022:     [0.5,0.75,0.25], [0.611,0.75,0.25], [0.5,0.75,0.25], [0.278,0.694,0.194],
 2023: 
 2024:     [0.833,0.04,0.96], [0.75,0.683], [0.833,0.683], [0.417,0.694,0.194,{ic: 0.111}],
 2025:     [0.667,0.556], [0.667,0.556], [0.778,0.636,0.136], [0.778,0.636,0.136],
 2026:     [0.444,0.694,0.194], [0.444,0.694,0.194], [0.444,0.694,0.194],
 2027:     [0.611,0.694,0.194], [0.778,0.694,0.13], [0.778,0.694,0.13],
 2028:     [0.778,0.694,0.13], [0.778,0.694,0.13]
 2029:   ],
 2030: 
 2031:   cmex10: [
 2032:     [0.458,0.04,1.16,{n: 16}], [0.458,0.04,1.16,{n: 17}],
 2033:     [0.417,0.04,1.16,{n: 104}], [0.417,0.04,1.16,{n: 105}],
 2034:     [0.472,0.04,1.16,{n: 106}], [0.472,0.04,1.16,{n: 107}],
 2035:     [0.472,0.04,1.16,{n: 108}], [0.472,0.04,1.16,{n: 109}],
 2036:     [0.583,0.04,1.16,{n: 110}], [0.583,0.04,1.16,{n: 111}],
 2037:     [0.472,0.04,1.16,{n: 68}], [0.472,0.04,1.16,{n: 69}],
 2038:     [0.333,0,0.6,{delim: {rep: 12}}], [0.556,0,0.6,{delim: {rep: 13}}],
 2039:     [0.578,0.04,1.16,{n: 46}], [0.578,0.04,1.16,{n: 47}],
 2040: 
 2041:     [0.597,0.04,1.76,{n: 18}], [0.597,0.04,1.76,{n: 19}],
 2042:     [0.736,0.04,2.36,{n: 32}], [0.736,0.04,2.36,{n: 33}],
 2043:     [0.528,0.04,2.36,{n: 34}], [0.528,0.04,2.36,{n: 35}],
 2044:     [0.583,0.04,2.36,{n: 36}], [0.583,0.04,2.36,{n: 37}],
 2045:     [0.583,0.04,2.36,{n: 38}], [0.583,0.04,2.36,{n: 39}],
 2046:     [0.75,0.04,2.36,{n: 40}], [0.75,0.04,2.36,{n: 41}],
 2047:     [0.75,0.04,2.36,{n: 42}], [0.75,0.04,2.36,{n: 43}],
 2048:     [1.04,0.04,2.36,{n: 44}], [1.04,0.04,2.36,{n: 45}],
 2049: 
 2050:     [0.792,0.04,2.96,{n: 48}], [0.792,0.04,2.96,{n: 49}],
 2051:     [0.583,0.04,2.96,{n: 50}], [0.583,0.04,2.96,{n: 51}],
 2052:     [0.639,0.04,2.96,{n: 52}], [0.639,0.04,2.96,{n: 53}],
 2053:     [0.639,0.04,2.96,{n: 54}], [0.639,0.04,2.96,{n: 55}],
 2054:     [0.806,0.04,2.96,{n: 56}], [0.806,0.04,2.96,{n: 57}],
 2055:     [0.806,0.04,2.96], [0.806,0.04,2.96],
 2056:     [1.28,0.04,2.96], [1.28,0.04,2.96],
 2057:     [0.811,0.04,1.76,{n: 30}], [0.811,0.04,1.76,{n: 31}],
 2058: 
 2059:     [0.875,0.04,1.76,{delim: {top: 48, bot: 64, rep: 66}}],
 2060:     [0.875,0.04,1.76,{delim: {top: 49, bot: 65, rep: 67}}],
 2061:     [0.667,0.04,1.76,{delim: {top: 50, bot: 52, rep: 54}}],
 2062:     [0.667,0.04,1.76,{delim: {top: 51, bot: 53, rep: 55}}],
 2063:     [0.667,0.04,1.76,{delim: {bot: 52, rep: 54}}],
 2064:     [0.667,0.04,1.76,{delim: {bot: 53, rep: 55}}],
 2065:     [0.667,0,0.6,{delim: {top: 50, rep: 54}}],
 2066:     [0.667,0,0.6,{delim: {top: 51, rep: 55}}],
 2067:     [0.889,0,0.9,{delim: {top: 56, mid: 60, bot: 58, rep: 62}}],
 2068:     [0.889,0,0.9,{delim: {top: 57, mid: 61, bot: 59, rep: 62}}],
 2069:     [0.889,0,0.9,{delim: {top: 56, bot: 58, rep: 62}}],
 2070:     [0.889,0,0.9,{delim: {top: 57, bot: 59, rep: 62}}],
 2071:     [0.889,0,1.8,{delim: {rep: 63}}],
 2072:     [0.889,0,1.8,{delim: {rep: 119}}],
 2073:     [0.889,0,0.3,{delim: {rep: 62}}],
 2074:     [0.667,0,0.6,{delim: {top: 120, bot: 121, rep: 63}}],
 2075: 
 2076:     [0.875,0.04,1.76,{delim: {top: 56, bot: 59, rep: 62}}],
 2077:     [0.875,0.04,1.76,{delim: {top: 57, bot: 58, rep: 62}}],
 2078:     [0.875,0,0.6,{delim: {rep: 66}}], [0.875,0,0.6,{delim: {rep: 67}}],
 2079:     [0.611,0.04,1.76,{n: 28}], [0.611,0.04,1.76,{n: 29}],
 2080:     [0.833,0,1,{n: 71}], [1.11,0.1,1.5], [0.472,0,1.11,{ic: 0.194, n: 73}],
 2081:     [0.556,0,2.22,{ic: 0.444}], [1.11,0,1,{n: 75}], [1.51,0.1,1.5],
 2082:     [1.11,0,1,{n: 77}], [1.51,0.1,1.5], [1.11,0,1,{n: 79}], [1.51,0.1,1.5],
 2083: 
 2084:     [1.06,0,1,{n: 88}], [0.944,0,1,{n: 89}], [0.472,0,1.11,{ic: 0.194, n: 90}],
 2085:     [0.833,0,1,{n: 91}], [0.833,0,1,{n: 92}], [0.833,0,1,{n: 93}],
 2086:     [0.833,0,1,{n: 94}], [0.833,0,1,{n: 95}], [1.44,0.1,1.5],
 2087:     [1.28,0.1,1.5], [0.556,0,2.22,{ic: 0.444}], [1.11,0.1,1.5],
 2088:     [1.11,0.1,1.5], [1.11,0.1,1.5], [1.11,0.1,1.5], [1.11,0.1,1.5],
 2089: 
 2090:     [0.944,0,1,{n: 97}], [1.28,0.1,1.5], [0.556,0.722,0,{n: 99}],
 2091:     [1,0.75,0,{n: 100}], [1.44,0.75], [0.556,0.722,0,{n: 102}],
 2092:     [1,0.75,0,{n: 103}], [1.44,0.75], [0.472,0.04,1.76,{n: 20}],
 2093:     [0.472,0.04,1.76,{n: 21}], [0.528,0.04,1.76,{n: 22}],
 2094:     [0.528,0.04,1.76,{n: 23}], [0.528,0.04,1.76,{n: 24}],
 2095:     [0.528,0.04,1.76,{n: 25}], [0.667,0.04,1.76,{n: 26}],
 2096:     [0.667,0.04,1.76,{n: 27}],
 2097: 
 2098:     [1,0.04,1.16,{n: 113}], [1,0.04,1.76,{n: 114}], [1,0.04,2.36,{n: 115}],
 2099:     [1,0.04,2.96,{n: 116}], [1.06,0,1.8,{delim: {top: 118, bot: 116, rep: 117}}],
 2100:     [1.06,0,0.6], [1.06,0.04,0.56],
 2101:     [0.778,0,0.6,{delim: {top: 126, bot: 127, rep: 119}}],
 2102:     [0.667,0,0.6,{delim: {top: 120, rep: 63}}],
 2103:     [0.667,0,0.6,{delim: {bot: 121, rep: 63}}],
 2104:     [0.45,0.12], [0.45,0.12], [0.45,0.12], [0.45,0.12],
 2105:     [0.778,0,0.6,{delim: {top: 126, rep: 119}}],
 2106:     [0.778,0,0.6,{delim: {bot: 127, rep: 119}}]
 2107:   ],
 2108:   
 2109:   cmti10: [
 2110:     [0.627,0.683,0,{ic: 0.133}], [0.818,0.683], [0.767,0.683,0,{ic: 0.094}],
 2111:     [0.692,0.683], [0.664,0.683,0,{ic: 0.153}], [0.743,0.683,0,{ic: 0.164}],
 2112:     [0.716,0.683,0,{ic: 0.12}], [0.767,0.683,0,{ic: 0.111}],
 2113:     [0.716,0.683,0,{ic: 0.0599}], [0.767,0.683,0,{ic: 0.111}],
 2114:     [0.716,0.683,0,{ic: 0.103}],
 2115:     [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}}],
 2116:     [0.562,0.694,0.194,{ic: 0.103}], [0.588,0.694,0.194,{ic: 0.103}],
 2117:     [0.882,0.694,0.194,{ic: 0.103}], [0.894,0.694,0.194,{ic: 0.103}],
 2118: 
 2119:     [0.307,0.431,0,{ic: 0.0767}], [0.332,0.431,0.194,{ic: 0.0374}],
 2120:     [0.511,0.694], [0.511,0.694,0,{ic: 0.0969}], [0.511,0.628,0,{ic: 0.083}],
 2121:     [0.511,0.694,0,{ic: 0.108}], [0.511,0.562,0,{ic: 0.103}], [0.831,0.694],
 2122:     [0.46,0,0.17], [0.537,0.694,0.194,{ic: 0.105}], [0.716,0.431,0,{ic: 0.0751}],
 2123:     [0.716,0.431,0,{ic: 0.0751}], [0.511,0.528,0.0972,{ic: 0.0919}],
 2124:     [0.883,0.683,0,{ic: 0.12}], [0.985,0.683,0,{ic: 0.12}],
 2125:     [0.767,0.732,0.0486,{ic: 0.094}],
 2126: 
 2127:     [0.256,0.431,0,{krn: {'108': -0.256, '76': -0.321}}],
 2128:     [0.307,0.694,0,{ic: 0.124, lig: {'96': 60}}],
 2129:     [0.514,0.694,0,{ic: 0.0696}], [0.818,0.694,0.194,{ic: 0.0662}],
 2130:     [0.769,0.694], [0.818,0.75,0.0556,{ic: 0.136}],
 2131:     [0.767,0.694,0,{ic: 0.0969}],
 2132:     [0.307,0.694,0,{ic: 0.124, krn: {'63': 0.102, '33': 0.102}, lig: {'39': 34}}],
 2133:     [0.409,0.75,0.25,{ic: 0.162}], [0.409,0.75,0.25,{ic: 0.0369}],
 2134:     [0.511,0.75,0,{ic: 0.149}], [0.767,0.562,0.0567,{ic: 0.0369}],
 2135:     [0.307,0.106,0.194], [0.358,0.431,0,{ic: 0.0283, lig: {'45': 123}}],
 2136:     [0.307,0.106], [0.511,0.75,0.25,{ic: 0.162}],
 2137: 
 2138:     [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
 2139:     [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
 2140:     [0.511,0.644,0.194,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
 2141:     [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0.194,{ic: 0.136}],
 2142:     [0.511,0.644,0,{ic: 0.136}], [0.511,0.644,0,{ic: 0.136}],
 2143:     [0.307,0.431,0,{ic: 0.0582}], [0.307,0.431,0.194,{ic: 0.0582}],
 2144:     [0.307,0.5,0.194,{ic: 0.0756}], [0.767,0.367,-0.133,{ic: 0.0662}],
 2145:     [0.511,0.5,0.194], [0.511,0.694,0,{ic: 0.122, lig: {'96': 62}}],
 2146: 
 2147:     [0.767,0.694,0,{ic: 0.096}],
 2148:     [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}}],
 2149:     [0.704,0.683,0,{ic: 0.103}], [0.716,0.683,0,{ic: 0.145}],
 2150:     [0.755,0.683,0,{ic: 0.094, krn: {'88': -0.0256, '87': -0.0256, '65': -0.0256, '86': -0.0256, '89': -0.0256}}],
 2151:     [0.678,0.683,0,{ic: 0.12}],
 2152:     [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}}],
 2153:     [0.774,0.683,0,{ic: 0.0872}], [0.743,0.683,0,{ic: 0.164}],
 2154:     [0.386,0.683,0,{ic: 0.158}], [0.525,0.683,0,{ic: 0.14}],
 2155:     [0.769,0.683,0,{ic: 0.145, krn: {'79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],
 2156:     [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}}],
 2157:     [0.897,0.683,0,{ic: 0.164}], [0.743,0.683,0,{ic: 0.164}],
 2158:     [0.767,0.683,0,{ic: 0.094, krn: {'88': -0.0256, '87': -0.0256, '65': -0.0256, '86': -0.0256, '89': -0.0256}}],
 2159: 
 2160:     [0.678,0.683,0,{ic: 0.103, krn: {'65': -0.0767}}],
 2161:     [0.767,0.683,0.194,{ic: 0.094}],
 2162:     [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}}],
 2163:     [0.562,0.683,0,{ic: 0.12}],
 2164:     [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}}],
 2165:     [0.743,0.683,0,{ic: 0.164}],
 2166:     [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}}],
 2167:     [0.999,0.683,0,{ic: 0.184, krn: {'65': -0.0767}}],
 2168:     [0.743,0.683,0,{ic: 0.158, krn: {'79': -0.0256, '67': -0.0256, '71': -0.0256, '81': -0.0256}}],
 2169:     [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}}],
 2170:     [0.613,0.683,0,{ic: 0.145}], [0.307,0.75,0.25,{ic: 0.188}],
 2171:     [0.514,0.694,0,{ic: 0.169}], [0.307,0.75,0.25,{ic: 0.105}],
 2172:     [0.511,0.694,0,{ic: 0.0665}], [0.307,0.668,0,{ic: 0.118}],
 2173: 
 2174:     [0.307,0.694,0,{ic: 0.124, lig: {'96': 92}}], [0.511,0.431,0,{ic: 0.0767}],
 2175:     [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}}],
 2176:     [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}}],
 2177:     [0.511,0.694,0,{ic: 0.103, krn: {'108': 0.0511}}],
 2178:     [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}}],
 2179:     [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}}],
 2180:     [0.46,0.431,0.194,{ic: 0.0885}], [0.511,0.694,0,{ic: 0.0767}],
 2181:     [0.307,0.655,0,{ic: 0.102}], [0.307,0.655,0.194,{ic: 0.145}],
 2182:     [0.46,0.694,0,{ic: 0.108}], [0.256,0.694,0,{ic: 0.103, krn: {'108': 0.0511}}],
 2183:     [0.818,0.431,0,{ic: 0.0767}], [0.562,0.431,0,{ic: 0.0767, krn: {'39': -0.102}}],
 2184:     [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}}],
 2185: 
 2186:     [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}}],
 2187:     [0.46,0.431,0.194,{ic: 0.0885}],
 2188:     [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}}],
 2189:     [0.409,0.431,0,{ic: 0.0821}], [0.332,0.615,0,{ic: 0.0949}],
 2190:     [0.537,0.431,0,{ic: 0.0767}], [0.46,0.431,0,{ic: 0.108}],
 2191:     [0.664,0.431,0,{ic: 0.108, krn: {'108': 0.0511}}],
 2192:     [0.464,0.431,0,{ic: 0.12}], [0.486,0.431,0.194,{ic: 0.0885}],
 2193:     [0.409,0.431,0,{ic: 0.123}], [0.511,0.431,0,{ic: 0.0921, lig: {'45': 124}}],
 2194:     [1.02,0.431,0,{ic: 0.0921}], [0.511,0.694,0,{ic: 0.122}],
 2195:     [0.511,0.668,0,{ic: 0.116}], [0.511,0.668,0,{ic: 0.105}]
 2196:   ],
 2197:   
 2198:   cmbx10: [
 2199:     [0.692,0.686], [0.958,0.686], [0.894,0.686], [0.806,0.686],
 2200:     [0.767,0.686], [0.9,0.686], [0.831,0.686], [0.894,0.686],
 2201:     [0.831,0.686], [0.894,0.686], [0.831,0.686],
 2202:     [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}}],
 2203:     [0.639,0.694], [0.639,0.694], [0.958,0.694], [0.958,0.694],
 2204: 
 2205:     [0.319,0.444], [0.351,0.444,0.194], [0.575,0.694], [0.575,0.694],
 2206:     [0.575,0.632], [0.575,0.694], [0.575,0.596], [0.869,0.694],
 2207:     [0.511,0,0.17], [0.597,0.694], [0.831,0.444], [0.894,0.444],
 2208:     [0.575,0.542,0.0972], [1.04,0.686], [1.17,0.686], [0.894,0.735,0.0486],
 2209: 
 2210:     [0.319,0.444,0,{krn: {'108': -0.319, '76': -0.378}}],
 2211:     [0.35,0.694,0,{lig: {'96': 60}}], [0.603,0.694], [0.958,0.694,0.194],
 2212:     [0.575,0.75,0.0556], [0.958,0.75,0.0556], [0.894,0.694],
 2213:     [0.319,0.694,0,{krn: {'63': 0.128, '33': 0.128}, lig: {'39': 34}}],
 2214:     [0.447,0.75,0.25], [0.447,0.75,0.25], [0.575,0.75], [0.894,0.633,0.133],
 2215:     [0.319,0.156,0.194], [0.383,0.444,0,{lig: {'45': 123}}],
 2216:     [0.319,0.156], [0.575,0.75,0.25],
 2217: 
 2218:     [0.575,0.644], [0.575,0.644], [0.575,0.644], [0.575,0.644],
 2219:     [0.575,0.644], [0.575,0.644], [0.575,0.644], [0.575,0.644],
 2220:     [0.575,0.644], [0.575,0.644], [0.319,0.444], [0.319,0.444,0.194],
 2221:     [0.35,0.5,0.194], [0.894,0.391,-0.109], [0.543,0.5,0.194],
 2222:     [0.543,0.694,0,{lig: {'96': 62}}],
 2223: 
 2224:     [0.894,0.694],
 2225:     [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}}],
 2226:     [0.818,0.686], [0.831,0.686],
 2227:     [0.882,0.686,0,{krn: {'88': -0.0319, '87': -0.0319, '65': -0.0319, '86': -0.0319, '89': -0.0319}}],
 2228:     [0.756,0.686],
 2229:     [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}}],
 2230:     [0.904,0.686], [0.9,0.686], [0.436,0.686,0,{krn: {'73': 0.0319}}],
 2231:     [0.594,0.686],
 2232:     [0.901,0.686,0,{krn: {'79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],
 2233:     [0.692,0.686,0,{krn: {'84': -0.0958, '89': -0.0958, '86': -0.128, '87': -0.128}}],
 2234:     [1.09,0.686], [0.9,0.686],
 2235:     [0.864,0.686,0,{krn: {'88': -0.0319, '87': -0.0319, '65': -0.0319, '86': -0.0319, '89': -0.0319}}],
 2236: 
 2237:     [0.786,0.686,0,{krn: {'65': -0.0958, '111': -0.0319, '101': -0.0319, '97': -0.0319, '46': -0.0958, '44': -0.0958}}],
 2238:     [0.864,0.686,0.194],
 2239:     [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}}],
 2240:     [0.639,0.686],
 2241:     [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}}],
 2242:     [0.885,0.686],
 2243:     [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}}],
 2244:     [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}}],
 2245:     [0.869,0.686,0,{krn: {'79': -0.0319, '67': -0.0319, '71': -0.0319, '81': -0.0319}}],
 2246:     [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}}],
 2247:     [0.703,0.686], [0.319,0.75,0.25], [0.603,0.694], [0.319,0.75,0.25],
 2248:     [0.575,0.694], [0.319,0.694],
 2249: 
 2250:     [0.319,0.694,0,{lig: {'96': 92}}],
 2251:     [0.559,0.444,0,{krn: {'118': -0.0319, '106': 0.0639, '121': -0.0319, '119': -0.0319}}],
 2252:     [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}}],
 2253:     [0.511,0.444,0,{krn: {'104': -0.0319, '107': -0.0319}}],
 2254:     [0.639,0.694], [0.527,0.444],
 2255:     [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}}],
 2256:     [0.575,0.444,0.194,{ic: 0.016, krn: {'106': 0.0319}}],
 2257:     [0.639,0.694,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],
 2258:     [0.319,0.694], [0.351,0.694,0.194],
 2259:     [0.607,0.694,0,{krn: {'97': -0.0639, '101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],
 2260:     [0.319,0.694],
 2261:     [0.958,0.444,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],
 2262:     [0.639,0.444,0,{krn: {'116': -0.0319, '117': -0.0319, '98': -0.0319, '121': -0.0319, '118': -0.0319, '119': -0.0319}}],
 2263:     [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}}],
 2264: 
 2265:     [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}}],
 2266:     [0.607,0.444,0.194], [0.474,0.444], [0.454,0.444],
 2267:     [0.447,0.635,0,{krn: {'121': -0.0319, '119': -0.0319}}],
 2268:     [0.639,0.444,0,{krn: {'119': -0.0319}}],
 2269:     [0.607,0.444,0,{ic: 0.016, krn: {'97': -0.0639, '101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],
 2270:     [0.831,0.444,0,{ic: 0.016, krn: {'101': -0.0319, '97': -0.0319, '111': -0.0319, '99': -0.0319}}],
 2271:     [0.607,0.444],
 2272:     [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}}],
 2273:     [0.511,0.444], [0.575,0.444,0,{ic: 0.0319, lig: {'45': 124}}],
 2274:     [1.15,0.444,0,{ic: 0.0319}], [0.575,0.694], [0.575,0.694], [0.575,0.694]
 2275:   ]
 2276: };
 2277: 
 2278: /***************************************************************************/
 2279: 
 2280: /*
 2281:  *  Implement image-based fonts for fallback method
 2282:  */
 2283: jsMath.Img = {
 2284:   
 2285:   // font sizes available
 2286:   fonts: [50, 60, 70, 85, 100, 120, 144, 173, 207, 249, 298, 358, 430],
 2287:     
 2288:   // em widths for the various font size directories
 2289:   w: {'50': 6.9, '60': 8.3, '70': 9.7, '85': 11.8, '100': 13.9,
 2290:       '120': 16.7, '144': 20.0, '173': 24.0, '207': 28.8, '249': 34.6,
 2291:       '298': 41.4, '358': 49.8, '430': 59.8},
 2292:         
 2293:   best: 4,     // index of best font size in the fonts list    
 2294:   update: {},  // fonts to update (see UpdateFonts below)
 2295:   factor: 1,   // factor by which to shrink images (for better printing)
 2296:   loaded: 0,   // image fonts are loaded
 2297: 
 2298:   // add characters to be drawn using images
 2299:   SetFont: function (change) {
 2300:     for (var font in change) {
 2301:       if (!this.update[font]) {this.update[font] = []}
 2302:       this.update[font] = this.update[font].concat(change[font]);
 2303:     }
 2304:   },
 2305: 
 2306:   /*
 2307:    *  Called by the exta-font definition files to add an image font
 2308:    *  into the mix
 2309:    */
 2310:   AddFont: function (size,def) {
 2311:     if (!jsMath.Img[size]) {jsMath.Img[size] = {}};
 2312:     jsMath.Add(jsMath.Img[size],def);
 2313:   },
 2314:     
 2315:   /*
 2316:    *  Update font(s) to use image data rather than native fonts
 2317:    *  It looks in the jsMath.Img.update array to find the names
 2318:    *  of the fonts to udpate, and the arrays of character codes
 2319:    *  to set (or 'all' to change every character);
 2320:    */
 2321:   UpdateFonts: function () {
 2322:     var change = this.update; if (!this.loaded) return;
 2323:     var best = this[jsMath.Img.fonts[this.best]];
 2324:     for (var font in change) {
 2325:       for (var i = 0; i < change[font].length; i++) {
 2326:         var c = change[font][i];
 2327:         if (c == 'all') {for (c in jsMath.TeX[font]) {jsMath.TeX[font][c].img = {}}}
 2328:           else {jsMath.TeX[font][c].img = {}}
 2329:       }
 2330:     }
 2331:     this.update = {};
 2332:   },
 2333:   
 2334:   /*
 2335:    *  Find the font size that best fits our current font
 2336:    *  (this is the directory name for the img files used
 2337:    *  in some fallback modes).
 2338:    */
 2339:   BestSize: function () {
 2340:     var w = jsMath.em * this.factor;
 2341:     var m = this.w[this.fonts[0]];
 2342:     for (var i = 1; i < this.fonts.length; i++) {
 2343:       if (w < (this.w[this.fonts[i]] + 2*m) / 3) {return i-1}
 2344:       m = this.w[this.fonts[i]];
 2345:     }
 2346:     return i-1;
 2347:   },
 2348: 
 2349:   /*
 2350:    *  Get the scaling factor for the image fonts
 2351:    */
 2352:   Scale: function () {
 2353:     if (!this.loaded) return;
 2354:     this.best = this.BestSize();
 2355:     this.em = jsMath.Img.w[this.fonts[this.best]];
 2356:     this.scale = (jsMath.em/this.em);
 2357:     if (Math.abs(this.scale - 1) < .12) {this.scale = 1}
 2358:   },
 2359: 
 2360:   /*
 2361:    *  Get URL to directory for given font and size, based on the
 2362:    *  user's alpha/plain setting
 2363:    */
 2364:   URL: function (name,size,C) {
 2365:     var type = (jsMath.Controls.cookie.alpha) ? '/alpha/': '/plain/';
 2366:     if (C == null) {C = "def.js"} else {C = 'char'+C+'.png'}
 2367:     if (size != "") {size += '/'}
 2368:     return this.root+name+type+size+C;
 2369:   },
 2370: 
 2371:   /*
 2372:    *  Laod the data for an image font
 2373:    */
 2374:   LoadFont: function (name) {
 2375:     if (!this.loaded) this.Init();
 2376:     jsMath.Setup.Script(this.URL(name,""));
 2377:   },
 2378:   
 2379:   /*
 2380:    *  Setup for print mode, and create the hex code table
 2381:    */
 2382:   Init: function () {
 2383:     if (jsMath.Controls.cookie.print || jsMath.Controls.cookie.stayhires) {
 2384:       jsMath.Controls.cookie.print = jsMath.Controls.cookie.stayhires;
 2385:       this.factor *= 3;
 2386:       if (!jsMath.Controls.isLocalCookie || !jsMath.Global.isLocal) {jsMath.Controls.SetCookie(0)}
 2387:       if (jsMath.Browser.alphaPrintBug) {jsMath.Controls.cookie.alpha = 0}
 2388:     }
 2389:     var codes = '0123456789ABCDEF';
 2390:     this.HexCode = [];
 2391:     for (var i = 0; i < 128; i++) {
 2392:       var h = Math.floor(i/16); var l = i - 16*h;
 2393:       this.HexCode[i] = codes.charAt(h)+codes.charAt(l);
 2394:     }
 2395:     this.loaded = 1;
 2396:   }
 2397:   
 2398: };
 2399: 
 2400: /***************************************************************************/
 2401: 
 2402: /*
 2403:  *  jsMath.HTML handles creation of most of the HTML needed for
 2404:  *  presenting mathematics in HTML pages.
 2405:  */
 2406: 
 2407: jsMath.HTML = {
 2408:   
 2409:   /*
 2410:    *  Produce a string version of a measurement in ems,
 2411:    *  showing only a limited number of digits, and 
 2412:    *  using 0 when the value is near zero.
 2413:    */
 2414:   Em: function (m) {
 2415:     var n = 5; if (m < 0) {n++}
 2416:     if (Math.abs(m) < .000001) {m = 0}
 2417:     var s = String(m); s = s.replace(/(\.\d\d\d).+/,'$1');
 2418:     return s+'em'
 2419:   },
 2420: 
 2421:   /*
 2422:    *  Create a horizontal space of width w
 2423:    */
 2424:   Spacer: function (w) {
 2425:     if (w == 0) {return ''};
 2426:     return jsMath.Browser.msieSpaceFix+'<span class="spacer" style="margin-left:'+this.Em(w)+'"></span>';
 2427:   },
 2428:   
 2429:   /*
 2430:    *  Create a blank rectangle of the given size
 2431:    *  If the height is small, it is converted to pixels so that it
 2432:    *  will not disappear at small font sizes.
 2433:    */
 2434:   
 2435:   Blank: function (w,h,d,isRule) {
 2436:     var backspace = ''; var style = ''
 2437:     if (isRule) {
 2438:       style += 'border-left:'+this.Em(w)+' solid;';
 2439:       if (jsMath.Browser.widthAddsBorder) {w = 0};
 2440:     }
 2441:     if (w == 0) {
 2442:       if (jsMath.Browser.blankWidthBug) {
 2443:         style += 'width:1px;';
 2444:         backspace = '<span class="spacer" style="margin-right:-1px"></span>'
 2445:       }
 2446:     } else {style += 'width:'+this.Em(w)+';'}
 2447:     if (d == null) {d = 0}
 2448:     if (h) {
 2449:       var H = this.Em(h+d);
 2450:       if (isRule && h*jsMath.em < 1.5) {H = "1px"; h = 1/jsMath.em}
 2451:       style += 'height:'+H+';';
 2452:     }
 2453:     if (jsMath.Browser.mozInlineBlockBug) {d = -h}
 2454:     if (jsMath.Browser.msieBorderBug && !isRule) {d -= jsMath.d}
 2455:     if (d) {style += 'vertical-align:'+this.Em(-d)}
 2456:     return backspace+'<span class="blank" style="'+style+'"></span>';
 2457:   },
 2458: 
 2459:   /*
 2460:    *  Create a rule line for fractions, etc.
 2461:    */
 2462:   Rule: function (w,h) {
 2463:     if (h == null) {h = jsMath.TeX.default_rule_thickness}
 2464:     return this.Blank(w,h,0,1);
 2465:   },
 2466:   
 2467:   /*
 2468:    *  Add a <SPAN> tag to activate a specific CSS class
 2469:    */
 2470:   Class: function (tclass,html) {
 2471:     return '<span class="'+tclass+'">'+html+'</span>';
 2472:   },
 2473:   
 2474:   /*
 2475:    *  Use a <SPAN> to place some HTML at a specific position.
 2476:    *  (This can be replaced by the ones below to overcome
 2477:    *   some browser-specific bugs.)
 2478:    */
 2479:   Place: function (html,x,y) {
 2480:     if (Math.abs(x) < .0001) {x = 0}
 2481:     if (Math.abs(y) < .0001) {y = 0}
 2482:     if (x || y) {
 2483:       var span = '<span style="position: relative;';
 2484:       if (x) {span += ' margin-left:'+this.Em(x)+';'}
 2485:       if (y) {span += ' top:'+this.Em(-y)+';'}
 2486:       html = span + '">' + html + '</span>';
 2487:     }
 2488:     return html;
 2489:   },
 2490:   
 2491:   /*
 2492:    *  For MSIE on Windows, backspacing must be done in a separate
 2493:    *  <SPAN>, otherwise the contents will be clipped.  Netscape
 2494:    *  also doesn't combine vertical and horizontal spacing well.
 2495:    *  Here the x and y positioning are done in separate <SPAN> tags
 2496:    */
 2497:   PlaceSeparateSkips: function (html,x,y) {
 2498:     if (Math.abs(x) < .0001) {x = 0}
 2499:     if (Math.abs(y) < .0001) {y = 0}
 2500:     if (y) {html = '<span style="position: relative; top:'+this.Em(-y)+';'
 2501:                        + '">' + html + '</span>'}
 2502:     if (x) {html = this.Spacer(x) + html}
 2503:     return html;
 2504:   },
 2505:   
 2506:   /*
 2507:    *  Place a SPAN with absolute coordinates
 2508:    */
 2509:   PlaceAbsolute: function (html,x,y) {
 2510:     if (Math.abs(x) < .0001) {x = 0}
 2511:     if (Math.abs(y) < .0001) {y = 0}
 2512:     html = '<span style="position:absolute; left:'+this.Em(x)+'; '
 2513:               + 'top:'+this.Em(y)+';">' + html + '&nbsp;</span>';
 2514:               //  space normalizes line height in script styles
 2515:     return html;
 2516:   },
 2517: 
 2518:   Absolute: function(html,w,h,d,y,H) {
 2519:     if (y != "none") {
 2520:       if (Math.abs(y) < .0001) {y = 0}
 2521:       html = '<span style="position:absolute; '
 2522:                + 'top:'+jsMath.HTML.Em(y)+'; left:0em;">'
 2523:                + html + '&nbsp;' // space normalizes line height in script styles
 2524:              + '</span>';
 2525:     }
 2526:     if (d == "none") {d = 0}
 2527:     html += this.Blank(w,h-d,d);
 2528:     if (jsMath.Browser.msieAbsoluteBug) {           // for MSIE (Mac)
 2529:       html = '<span style="position:relative;">' + html + '</span>';
 2530:     }
 2531:     html =   '<span style="position:relative;'
 2532:            +     ' width: '+jsMath.HTML.Em(w)+';'   // for MSIE
 2533:            +     ' height: '+jsMath.HTML.Em(H)+';'  // for MSIE
 2534:            +     jsMath.Browser.msieInlineBlockFix  // for MSIE
 2535:            +     '">'
 2536:            +   html
 2537:            + '</span>';
 2538:     return html;
 2539:   }
 2540: 
 2541: };
 2542: 
 2543: 
 2544: /***************************************************************************/
 2545: 
 2546: /*
 2547:  *  jsMath.Box handles TeX's math boxes and jsMath's equivalent of hboxes.
 2548:  */
 2549: 
 2550: jsMath.Box = function (format,text,w,h,d) {
 2551:   if (d == null) {d = jsMath.d}
 2552:   this.type = 'typeset';
 2553:   this.w = w; this.h = h; this.d = d; this.bh = h; this.bd = d;
 2554:   this.x = 0; this.y = 0;
 2555:   this.html = text; this.format = format;
 2556: };
 2557: 
 2558: 
 2559: jsMath.Add(jsMath.Box,{
 2560:   
 2561:   defaultH: 0, // default height for characters with none specified
 2562: 
 2563:   /*
 2564:    *  An empty box
 2565:    */
 2566:   Null: new jsMath.Box('null','',0,0,0),
 2567: 
 2568:   /*
 2569:    *  A box containing only text whose class and style haven't been added
 2570:    *  yet (so that we can combine ones with the same styles).  It gets
 2571:    *  the text dimensions, if needed.  (In general, this has been
 2572:    *  replaced by TeX() below, but is still used in fallback mode.)
 2573:    */
 2574:   Text: function (text,tclass,style,size,a,d) {
 2575:     var html = jsMath.Typeset.AddClass(tclass,text);
 2576:         html = jsMath.Typeset.AddStyle(style,size,html);
 2577:     var BB = jsMath.EmBoxFor(html); var TeX = jsMath.Typeset.TeX(style,size);
 2578:     var bd = ((tclass == 'cmsy10' || tclass == 'cmex10')? BB.h-TeX.h: TeX.d*BB.h/TeX.hd);
 2579:     var box = new jsMath.Box('text',text,BB.w,BB.h-bd,bd);
 2580:     box.style = style; box.size = size; box.tclass = tclass;
 2581:     if (d != null) {box.d = d*TeX.scale} else {box.d = 0}
 2582:     if (a == null || a == 1) {box.h = .9*TeX.M_height}
 2583:       else {box.h = 1.1*TeX.x_height + TeX.scale*a}
 2584:     return box;
 2585:   },
 2586: 
 2587:   /*
 2588:    *  Produce a box containing a given TeX character from a given font.
 2589:    *  The box is a text box (like the ones above), so that characters from
 2590:    *  the same font can be combined.
 2591:    */
 2592:   TeX: function (C,font,style,size) {
 2593:     var c = jsMath.TeX[font][C];
 2594:     if (c.d == null) {c.d = 0}; if (c.h == null) {c.h = 0}
 2595:     if (c.img != null && c.c != '') this.TeXIMG(font,C,jsMath.Typeset.StyleSize(style,size));
 2596:     var scale = jsMath.Typeset.TeX(style,size).scale;
 2597:     var h = c.h + jsMath.TeX[font].dh
 2598:     var box = new jsMath.Box('text',c.c,c.w*scale,h*scale,c.d*scale);
 2599:     box.style = style; box.size = size;
 2600:     if (c.tclass) {
 2601:       box.tclass = c.tclass;
 2602:       if (c.img) {box.bh = c.img.bh; box.bd = c.img.bd}
 2603:             else {box.bh = scale*jsMath.h; box.bd = scale*jsMath.d}
 2604:     } else {
 2605:       box.tclass = font;
 2606:       box.bh = scale*jsMath.TeX[font].h;
 2607:       box.bd = scale*jsMath.TeX[font].d;
 2608:       if (jsMath.Browser.msieFontBug && box.html.match(/&#/)) {
 2609:         // hack to avoid font changing back to the default
 2610:         // font when a unicode reference is not followed
 2611:         // by a letter or number
 2612:         box.html += '<span style="display:none">x</span>';
 2613:       }
 2614:     }
 2615:     return box;
 2616:   },
 2617: 
 2618:   /*
 2619:    *  In fallback modes, handle the fact that we don't have the
 2620:    *  sizes of the characters precomputed
 2621:    */
 2622:   TeXfallback: function (C,font,style,size) {
 2623:     var c = jsMath.TeX[font][C]; if (!c.tclass) {c.tclass = font}
 2624:     if (c.img != null) {return this.TeXnonfallback(C,font,style,size)}
 2625:     if (c.h != null && c.a == null) {c.a = c.h-1.1*jsMath.TeX.x_height}
 2626:     var box = this.Text(c.c,c.tclass,style,size,c.a || 0,c.d || 0);
 2627:     var scale = jsMath.Typeset.TeX(style,size).scale;
 2628:     if (c.bh != null) {
 2629:       box.bh = c.bh*scale;
 2630:       box.bd = c.bd*scale;
 2631:     } else {
 2632:       var h = box.bd+box.bh;
 2633:       var html = jsMath.Typeset.AddClass(box.tclass,box.html);
 2634:           html = jsMath.Typeset.AddStyle(style,size,html);
 2635:       box.bd = jsMath.EmBoxFor(html+jsMath.HTML.Blank(1,h)).h - h;
 2636:       box.bh = h - box.bd;
 2637:       if (scale == 1) {c.bh = box.bh; c.bd = box.bd}
 2638:     }
 2639:     if (jsMath.msieFontBug && box.html.match(/&#/))
 2640:       {box.html += '<span style="display:none">x</span>'}
 2641:     return box;
 2642:   },
 2643: 
 2644:   /*
 2645:    *  Set the character's string to the appropriate image file
 2646:    */
 2647:   TeXIMG: function (font,C,size) {
 2648:     var c = jsMath.TeX[font][C];
 2649:     if (c.img.size != null && c.img.size == size &&
 2650:         c.img.best != null && c.img.best == jsMath.Img.best) return;
 2651:     var mustScale = (jsMath.Img.scale != 1);
 2652:     var id = jsMath.Img.best + size - 4;
 2653:     if (id < 0) {id = 0; mustScale = 1} else
 2654:     if (id >= jsMath.Img.fonts.length) {id = jsMath.Img.fonts.length-1; mustScale = 1}
 2655:     var imgFont = jsMath.Img[jsMath.Img.fonts[id]];
 2656:     var img = imgFont[font][C];
 2657:     var scale = 1/jsMath.Img.w[jsMath.Img.fonts[id]];
 2658:     if (id != jsMath.Img.best + size - 4) {
 2659:       if (c.w != null) {scale = c.w/img[0]} else {
 2660:         scale *= jsMath.Img.fonts[size]/jsMath.Img.fonts[4]
 2661:               *  jsMath.Img.fonts[jsMath.Img.best]/jsMath.Img.fonts[id];
 2662:       }
 2663:     }
 2664:     var w = img[0]*scale; var h = img[1]*scale; var d = -img[2]*scale; var v;
 2665:     var wadjust = (c.w == null || Math.abs(c.w-w) < .01)? "" : " margin-right:"+jsMath.HTML.Em(c.w-w)+';';
 2666:     var resize = ""; C = jsMath.Img.HexCode[C];
 2667:     if (!mustScale && !jsMath.Controls.cookie.scaleImg) {
 2668:       if (2*w < h || (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha))
 2669:          {resize = "height:"+(img[1]*jsMath.Browser.imgScale)+'px;'}
 2670:       resize += " width:"+(img[0]*jsMath.Browser.imgScale)+'px;'
 2671:       v = -img[2]+'px';
 2672:     } else {
 2673:       if (2*w < h || (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha))
 2674:          {resize = "height:"+jsMath.HTML.Em(h*jsMath.Browser.imgScale)+';'}
 2675:       resize += " width:"+jsMath.HTML.Em(w*jsMath.Browser.imgScale)+';'
 2676:       v = jsMath.HTML.Em(d);
 2677:     }
 2678:     var vadjust = (Math.abs(d) < .01 && !jsMath.Browser.valignBug)?
 2679:                          "": " vertical-align:"+v+';';
 2680:     var URL = jsMath.Img.URL(font,jsMath.Img.fonts[id],C);
 2681:     if (jsMath.Browser.msieAlphaBug && jsMath.Controls.cookie.alpha) {
 2682:       c.c = '<img src="'+jsMath.blank+'" '
 2683:                + 'style="'+jsMath.Browser.msieCenterBugFix
 2684:                + resize + vadjust + wadjust
 2685:                + ' filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' + "'"
 2686:                + URL + "', sizingMethod='scale'" + ');" />';
 2687:     } else {
 2688:       c.c = '<img src="'+URL+'" style="'+jsMath.Browser.msieCenterBugFix
 2689:                   + resize + vadjust + wadjust + '" />';
 2690:     }
 2691:     c.tclass = "normal";
 2692:     c.img.bh = h+d; c.img.bd = -d;
 2693:     c.img.size = size; c.img.best = jsMath.Img.best;
 2694:   },
 2695:   
 2696:   /*
 2697:    *  A box containing a spacer of a specific width
 2698:    */
 2699:   Space: function (w) {
 2700:     return new jsMath.Box('html',jsMath.HTML.Spacer(w),w,0,0);
 2701:   },
 2702: 
 2703:   /*
 2704:    *  A box containing a horizontal rule
 2705:    */
 2706:   Rule: function (w,h) {
 2707:     if (h == null) {h = jsMath.TeX.default_rule_thickness}
 2708:     var html = jsMath.HTML.Rule(w,h);
 2709:     return new jsMath.Box('html',html,w,h,0);
 2710:   },
 2711: 
 2712:   /*
 2713:    *  Get a character from a TeX font, and make sure that it has
 2714:    *  its metrics specified.
 2715:    */
 2716:   GetChar: function (code,font) {
 2717:     var c = jsMath.TeX[font][code];
 2718:     if (c.img != null) {this.TeXIMG(font,code,4)}
 2719:     if (c.tclass == null) {c.tclass = font}
 2720:     if (!c.computedW) {
 2721:       c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w;
 2722:       if (c.h == null) {c.h = jsMath.Box.defaultH}; if (c.d == null) {c.d = 0}
 2723:       c.computedW = 1;
 2724:     }
 2725:     return c;
 2726:   },
 2727:   
 2728:   /*
 2729:    *  Locate the TeX delimiter character that matches a given height.
 2730:    *  Return the character, font, style and actual height used.
 2731:    */
 2732:   DelimBestFit: function (H,c,font,style) {
 2733:     if (c == 0 && font == 0) return null;
 2734:     var C; var h; font = jsMath.TeX.fam[font];
 2735:     var isSS = (style.charAt(1) == 'S');
 2736:     var isS  = (style.charAt(0) == 'S');
 2737:     while (c != null) {
 2738:       C = jsMath.TeX[font][c];
 2739:       if (C.h == null) {C.h = jsMath.Box.defaultH}; if (C.d == null) {C.d = 0}
 2740:       h = C.h+C.d;
 2741:       if (C.delim) {return [c,font,'',H]}
 2742:       if (isSS && .5*h >= H) {return [c,font,'SS',.5*h]}
 2743:       if (isS  && .7*h >= H) {return [c,font,'S',.7*h]}
 2744:       if (h >= H || C.n == null) {return [c,font,'T',h]}
 2745:       c = C.n;
 2746:     }
 2747:     return null;
 2748:   },
 2749:   
 2750:   /*
 2751:    *  Create the HTML needed for a stretchable delimiter of a given height,
 2752:    *  either centered or not.  This version uses relative placement (i.e.,
 2753:    *  backspaces, not line-breaks).  This works with more browsers, but
 2754:    *  if the font size changes, the backspacing may not be right, so the
 2755:    *  delimiters may become jagged.
 2756:    */
 2757:   DelimExtendRelative: function (H,c,font,a,nocenter) {
 2758:     var C = jsMath.TeX[font][c];
 2759:     var top = this.GetChar(C.delim.top? C.delim.top: C.delim.rep,font);
 2760:     var rep = this.GetChar(C.delim.rep,font);
 2761:     var bot = this.GetChar(C.delim.bot? C.delim.bot: C.delim.rep,font);
 2762:     var ext = jsMath.Typeset.AddClass(rep.tclass,rep.c);
 2763:     var w = rep.w; var h = rep.h+rep.d
 2764:     var y; var dx;
 2765:     if (C.delim.mid) {// braces
 2766:       var mid = this.GetChar(C.delim.mid,font);
 2767:       var n = Math.ceil((H-(top.h+top.d)-(mid.h+mid.d)-(bot.h+bot.d))/(2*(rep.h+rep.d)));
 2768:       H = 2*n*(rep.h+rep.d) + (top.h+top.d) + (mid.h+mid.d) + (bot.h+bot.d);
 2769:       if (nocenter) {y = 0} else {y = H/2+a}; var Y = y;
 2770:       var html = jsMath.HTML.Place(jsMath.Typeset.AddClass(top.tclass,top.c),0,y-top.h)
 2771:                + jsMath.HTML.Place(jsMath.Typeset.AddClass(bot.tclass,bot.c),-(top.w+bot.w)/2,y-(H-bot.d))
 2772:                + jsMath.HTML.Place(jsMath.Typeset.AddClass(mid.tclass,mid.c),-(bot.w+mid.w)/2,y-(H+mid.h-mid.d)/2);
 2773:       dx = (w-mid.w)/2; if (Math.abs(dx) < .0001) {dx = 0}
 2774:       if (dx) {html += jsMath.HTML.Spacer(dx)}
 2775:       y -= top.h+top.d + rep.h;
 2776:       for (var i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}
 2777:       y -= H/2 - rep.h/2;
 2778:       for (var i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}
 2779:     } else {// everything else
 2780:       var n = Math.ceil((H - (top.h+top.d) - (bot.h+bot.d))/(rep.h+rep.d));
 2781:       // make sure two-headed arrows have an extender
 2782:       if (top.h+top.d < .9*(rep.h+rep.d)) {n = Math.max(1,n)}
 2783:       H = n*(rep.h+rep.d) + (top.h+top.d) + (bot.h+bot.d);
 2784:       if (nocenter) {y = 0} else {y = H/2+a}; var Y = y;
 2785:       var html = jsMath.HTML.Place(jsMath.Typeset.AddClass(top.tclass,top.c),0,y-top.h)
 2786:       dx = (w-top.w)/2; if (Math.abs(dx) < .0001) {dx = 0}
 2787:       if (dx) {html += jsMath.HTML.Spacer(dx)}
 2788:       y -= top.h+top.d + rep.h;
 2789:       for (var i = 0; i < n; i++) {html += jsMath.HTML.Place(ext,-w,y-i*h)}
 2790:       html += jsMath.HTML.Place(jsMath.Typeset.AddClass(bot.tclass,bot.c),-(w+bot.w)/2,Y-(H-bot.d));
 2791:     }
 2792:     if (nocenter) {h = top.h} else {h = H/2+a}
 2793:     var box = new jsMath.Box('html',html,rep.w,h,H-h);
 2794:     box.bh = jsMath.TeX[font].h; box.bd = jsMath.TeX[font].d;
 2795:     return box;
 2796:   },
 2797: 
 2798:   /*
 2799:    *  Create the HTML needed for a stretchable delimiter of a given height,
 2800:    *  either centered or not.  This version uses absolute placement (i.e.,
 2801:    *  line-breaks, not backspacing).  This gives more reliable results,
 2802:    *  but doesn't work with all browsers.
 2803:    */
 2804:   DelimExtendAbsolute: function (H,c,font,a,nocenter) {
 2805:     var Font = jsMath.TeX[font];
 2806:     var C = Font[c]; var html;
 2807:     var top = this.GetChar(C.delim.top? C.delim.top: C.delim.rep,font);
 2808:     var rep = this.GetChar(C.delim.rep,font);
 2809:     var bot = this.GetChar(C.delim.bot? C.delim.bot: C.delim.rep,font);
 2810:     
 2811:     if (C.delim.mid) {// braces
 2812:       var mid = this.GetChar(C.delim.mid,font);
 2813:       var n = Math.ceil((H-(top.h+top.d)-(mid.h+mid.d-.05)-(bot.h+bot.d-.05))/(2*(rep.h+rep.d-.05)));
 2814:       H = 2*n*(rep.h+rep.d-.05) + (top.h+top.d) + (mid.h+mid.d-.05) + (bot.h+bot.d-.05);
 2815:       
 2816:       html = jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(top.tclass,top.c),0,0);
 2817:       var h = rep.h+rep.d - .05; var y = top.d-.05 + rep.h;
 2818:       var ext = jsMath.Typeset.AddClass(font,rep.c)
 2819:       for (var i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}
 2820:       html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(mid.tclass,mid.c),0,y+n*h-rep.h+mid.h);
 2821:       y += n*h + mid.h+mid.d - .05;
 2822:       for (var i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}
 2823:       html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(bot.tclass,bot.c),0,y+n*h-rep.h+bot.h);
 2824:     } else {// all others
 2825:       var n = Math.ceil((H - (top.h+top.d) - (bot.h+bot.d-.05))/(rep.h+rep.d-.05));
 2826:       H = n*(rep.h+rep.d-.05) + (top.h+top.d) + (bot.h+bot.d-.05);
 2827: 
 2828:       html = jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(top.tclass,top.c),0,0);
 2829:       var h = rep.h+rep.d-.05; var y = top.d-.05 + rep.h;
 2830:       var ext = jsMath.Typeset.AddClass(rep.tclass,rep.c);
 2831:       for (var i = 0; i < n; i++) {html += jsMath.HTML.PlaceAbsolute(ext,0,y+i*h)}
 2832:       html += jsMath.HTML.PlaceAbsolute(jsMath.Typeset.AddClass(bot.tclass,bot.c),0,y+n*h-rep.h+bot.h);
 2833:     }
 2834:     
 2835:     var w = top.w;
 2836:     if (nocenter) {h = top.h; y = 0} else {h = H/2 + a; y = h - top.h}
 2837:     html = jsMath.HTML.Absolute(html,w,Font.h,"none",-y,top.h);
 2838:     var box = new jsMath.Box('html',html,rep.w,h,H-h);
 2839:     box.bh = jsMath.TeX[font].h; box.bd = jsMath.TeX[font].d;
 2840:     return box;
 2841:   },
 2842:   
 2843:   /*
 2844:    *  Get the HTML for a given delimiter of a given height.
 2845:    *  It will return either a single character, if one exists, or the
 2846:    *  more complex HTML needed for a stretchable delimiter.
 2847:    */
 2848:   Delimiter: function (H,delim,style,nocenter) {
 2849:     var size = 4;  //### pass this?
 2850:     var TeX = jsMath.Typeset.TeX(style,size);
 2851:     if (!delim) {return this.Space(TeX.nulldelimiterspace)}
 2852:     var CFSH = this.DelimBestFit(H,delim[2],delim[1],style);
 2853:     if (CFSH == null || CFSH[3] < H) 
 2854:       {CFSH = this.DelimBestFit(H,delim[4],delim[3],style)}
 2855:     if (CFSH == null) {return this.Space(TeX.nulldelimiterspace)}
 2856:     if (CFSH[2] == '')
 2857:       {return this.DelimExtend(H,CFSH[0],CFSH[1],TeX.axis_height,nocenter)}
 2858:     var box = jsMath.Box.TeX(CFSH[0],CFSH[1],CFSH[2],size).Styled();
 2859:     if (nocenter) {box.y = -jsMath.TeX[CFSH[1]].dh*TeX.scale}
 2860:       else {box.y = -((box.h+box.d)/2 - box.d - TeX.axis_height)}
 2861:     if (Math.abs(box.y) < .0001) {box.y = 0}
 2862:     if (box.y) {box = jsMath.Box.SetList([box],CFSH[2],size)}
 2863:     return box;
 2864:   },
 2865:   
 2866:   /*
 2867:    *  Get a character by its TeX charcode, and make sure its width
 2868:    *  is specified.
 2869:    */
 2870:   GetCharCode: function (code) {
 2871:     var font = jsMath.TeX.fam[code[0]];
 2872:     var Font = jsMath.TeX[font];
 2873:     var c = Font[code[1]];
 2874:     if (c.img != null) {this.TeXIMG(font,code[1],4)}
 2875:     if (c.w == null) {c.w = jsMath.EmBoxFor(jsMath.Typeset.AddClass(c.tclass,c.c)).w}
 2876:     if (c.font == null) {c.font = font}
 2877:     return c;
 2878:   },
 2879: 
 2880:   /*
 2881:    * Add the class to the html, and use the font if there isn't one
 2882:    * specified already
 2883:    */
 2884: 
 2885:   AddClass: function (tclass,html,font) {
 2886:     if (tclass == null) {tclass = font}
 2887:     return jsMath.Typeset.AddClass(tclass,html);
 2888:   },
 2889:   
 2890:   /*
 2891:    *  Create the HTML for an alignment (e.g., array or matrix)
 2892:    *  Since the widths are not really accurate (they are based on pixel
 2893:    *  widths not the sub-pixel widths of the actual characters), there
 2894:    *  is some drift involved.  We lay out the table column by column
 2895:    *  to help reduce the problem.
 2896:    *  
 2897:    *  ###  still need to allow users to specify row and column attributes,
 2898:    *       and do things like \span and \multispan  ###
 2899:    */
 2900:   LayoutRelative: function (size,table,align,cspacing,rspacing,vspace) {
 2901:     if (align == null) {align = []}
 2902:     if (cspacing == null) {cspacing = []}
 2903:     if (rspacing == null) {rspacing = []}
 2904:     
 2905:     // get row and column maximum dimensions
 2906:     var scale = jsMath.sizes[size]/100;
 2907:     var W = []; var H = []; var D = [];
 2908:     var unset = -1000; var bh = unset; var bd = unset;
 2909:     var i; var j; var row;
 2910:     for (i = 0; i < table.length; i++) {
 2911:       if (rspacing[i] == null) {rspacing[i] = 0}
 2912:       row = table[i]; H[i] = jsMath.h*scale; D[i] = jsMath.d*scale;
 2913:       for (j = 0; j < row.length; j++) {
 2914:         row[j] = row[j].Remeasured();
 2915:         if (row[j].h > H[i]) {H[i] = row[j].h}
 2916:         if (row[j].d > D[i]) {D[i] = row[j].d}
 2917:         if (j >= W.length) {W[j] = row[j].w}
 2918:         else if (row[j].w > W[j]) {W[j] = row[j].w}
 2919:         if (row[j].bh > bh) {bh = row[j].bh}
 2920:         if (row[j].bd > bd) {bd = row[j].bd}
 2921:       }
 2922:     }
 2923:     if (rspacing[table.length] == null) {rspacing[table.length] = 0}
 2924:     if (bh == unset) {bh = 0}; if (bd == unset) {bd = 0}
 2925: 
 2926:     // lay out the columns
 2927:     var HD = (jsMath.hd-.01)*scale;
 2928:     var dy = (vspace || 1) * scale/6;
 2929:     var html = ''; var pW = 0; var cW = 0;
 2930:     var w; var h; var y;
 2931:     var box; var mlist; var entry;
 2932:     for (j = 0; j < W.length; j++) {
 2933:       mlist = []; y = -H[0]-rspacing[0]; pW = 0;
 2934:       for (i = 0; i < table.length; i++) {
 2935:         entry = table[i][j];
 2936:         if (entry && entry.format != 'null') {
 2937:           if (align[j] == 'l') {w = 0} else
 2938:           if (align[j] == 'r') {w = W[j] - entry.w} else
 2939:             {w = (W[j] - entry.w)/2}
 2940:           entry.x = w - pW; pW = entry.w + w; entry.y = y;
 2941:           mlist[mlist.length] = entry;
 2942:         }
 2943:         if (i+1 < table.length) {y -= Math.max(HD,D[i]+H[i+1]) + dy + rspacing[i+1]}
 2944:       }
 2945:       if (cspacing[j] == null) cspacing[j] = scale;
 2946:       if (mlist.length > 0) {
 2947:         box = jsMath.Box.SetList(mlist,'T',size);
 2948:         html += jsMath.HTML.Place(box.html,cW,0);
 2949:         cW = W[j] - box.w + cspacing[j];
 2950:       } else {cW += cspacing[j]}
 2951:     }
 2952:     
 2953:     // get the full width and height
 2954:     w = -cspacing[W.length-1]; y = (H.length-1)*dy + rspacing[0];
 2955:     for (i = 0; i < W.length; i++) {w += W[i] + cspacing[i]}
 2956:     for (i = 0; i < H.length; i++) {y += Math.max(HD,H[i]+D[i]) + rspacing[i+1]}
 2957:     h = y/2 + jsMath.TeX.axis_height; var d = y-h;
 2958:     
 2959:     // adjust the final row width, and vcenter the table
 2960:     //   (add 1/6em at each side for the \,)
 2961:     html += jsMath.HTML.Spacer(cW-cspacing[W.length-1] + scale/6);
 2962:     html = jsMath.HTML.Place(html,scale/6,h);
 2963:     box = new jsMath.Box('html',html,w+scale/3,h,d);
 2964:     box.bh = bh; box.bd = bd;
 2965:     return box;
 2966:   },
 2967: 
 2968:   /*
 2969:    *  Create the HTML for an alignment (e.g., array or matrix)
 2970:    *  Use absolute position for elements in the array.
 2971:    *  
 2972:    *  ###  still need to allow users to specify row and column attributes,
 2973:    *       and do things like \span and \multispan  ###
 2974:    */
 2975:   LayoutAbsolute: function (size,table,align,cspacing,rspacing,vspace) {
 2976:     if (align == null) {align = []}
 2977:     if (cspacing == null) {cspacing = []}
 2978:     if (rspacing == null) {rspacing = []}
 2979:     
 2980:     // get row and column maximum dimensions
 2981:     var scale = jsMath.sizes[size]/100;
 2982:     var HD = (jsMath.hd-.01)*scale;
 2983:     var dy = (vspace || 1) * scale/6;
 2984:     var W = []; var H = []; var D = [];
 2985:     var w = 0; var h; var x; var y;
 2986:     var i; var j; var row;
 2987:     for (i = 0; i < table.length; i++) {
 2988:       if (rspacing[i] == null) {rspacing[i] = 0}
 2989:       row = table[i];
 2990:       H[i] = jsMath.h*scale; D[i] = jsMath.d*scale;
 2991:       for (j = 0; j < row.length; j++) {
 2992:         row[j] = row[j].Remeasured();
 2993:         if (row[j].h > H[i]) {H[i] = row[j].h}
 2994:         if (row[j].d > D[i]) {D[i] = row[j].d}
 2995:         if (j >= W.length) {W[j] = row[j].w}
 2996:         else if (row[j].w > W[j]) {W[j] = row[j].w}
 2997:       }
 2998:     }
 2999:     if (rspacing[table.length] == null) {rspacing[table.length] = 0}
 3000: 
 3001:     // get the height and depth of the centered table
 3002:     y = (H.length-1)*dy + rspacing[0];
 3003:     for (i = 0; i < H.length; i++) {y += Math.max(HD,H[i]+D[i]) + rspacing[i+1]}
 3004:     h = y/2 + jsMath.TeX.axis_height; var d = y - h;
 3005: 
 3006:     // lay out the columns
 3007:     var html = ''; var entry; w = scale/6;
 3008:     for (j = 0; j < W.length; j++) {
 3009:       y = H[0]-h + rspacing[0];
 3010:       for (i = 0; i < table.length; i++) {
 3011:         entry = table[i][j];
 3012:         if (entry && entry.format != 'null') {
 3013:           if (align[j] && align[j] == 'l') {x = 0} else
 3014:           if (align[j] && align[j] == 'r') {x = W[j] - entry.w} else
 3015:             {x = (W[j] - entry.w)/2}
 3016:           html += jsMath.HTML.PlaceAbsolute(entry.html,w+x,
 3017:                     y-Math.max(0,entry.bh-jsMath.h*scale));
 3018:         }
 3019:         if (i+1 < table.length) {y += Math.max(HD,D[i]+H[i+1]) + dy + rspacing[i+1]}
 3020:       }
 3021:       if (cspacing[j] == null) cspacing[j] = scale;
 3022:       w += W[j] + cspacing[j];
 3023:     }
 3024:     
 3025:     // get the full width
 3026:     w = -cspacing[W.length-1]+scale/3;
 3027:     for (i = 0; i < W.length; i++) {w += W[i] + cspacing[i]}
 3028: 
 3029:     html = jsMath.HTML.Spacer(scale/6)+html+jsMath.HTML.Spacer(scale/6);
 3030:     if (jsMath.Browser.spanHeightVaries) {y = h-jsMath.h} else {y = 0}
 3031:     html = jsMath.HTML.Absolute(html,w,h+d,d,y,H[0]);
 3032:     var box = new jsMath.Box('html',html,w+scale/3,h,d);
 3033:     return box;
 3034:   },
 3035: 
 3036:   /*
 3037:    *  Look for math within \hbox and other non-math text
 3038:    */
 3039:   InternalMath: function (text,size) {
 3040:     if (!text.match(/\$|\\\(/)) {return this.Text(text,'normal','T',size).Styled()}
 3041:     
 3042:     var i = 0; var k = 0; var c; var match = '';
 3043:     var mlist = []; var parse; var html; var box;
 3044:     while (i < text.length) {
 3045:       c = text.charAt(i++);
 3046:       if (c == '$') {
 3047:         if (match == '$') {
 3048:           parse = jsMath.Parse(text.slice(k,i-1),null,size);
 3049:           if (parse.error) {
 3050:             mlist[mlist.length] = this.Text(parse.error,'error','T',size,1,.2);
 3051:           } else {
 3052:             parse.Atomize();
 3053:             mlist[mlist.length] = parse.mlist.Typeset('T',size).Styled();
 3054:           }
 3055:           match = ''; k = i;
 3056:         } else {
 3057:           mlist[mlist.length] = this.Text(text.slice(k,i-1),'normal','T',size,1,.2);
 3058:           match = '$'; k = i;
 3059:         }
 3060:       } else if (c == '\\') {
 3061:         c = text.charAt(i++);
 3062:         if (c == '(' && match == '') {
 3063:           mlist[mlist.length] = this.Text(text.slice(k,i-2),'normal','T',size,1,.2);
 3064:           match = ')'; k = i;
 3065:         } else if (c == ')' && match == ')') {
 3066:           parse = jsMath.Parse(text.slice(k,i-2),null,size);
 3067:           if (parse.error) {
 3068:             mlist[mlist.length] = this.Text(parse.error,'error','T',size,1,.2);
 3069:           } else {
 3070:             parse.Atomize();
 3071:             mlist[mlist.length] = parse.mlist.Typeset('T',size).Styled();
 3072:           }
 3073:           match = ''; k = i;
 3074:         }
 3075:       }
 3076:     }
 3077:     mlist[mlist.length] = this.Text(text.slice(k),'normal','T',size,1,.2);
 3078:     return this.SetList(mlist,'T',size);
 3079:   },
 3080:   
 3081:   /*
 3082:    *  Convert an abitrary box to a typeset box.  I.e., make an
 3083:    *  HTML version of the contents of the box, at its desired (x,y)
 3084:    *  position.
 3085:    */
 3086:   Set: function (box,style,size,addstyle) {
 3087:     if (box && box.type) {
 3088:       if (box.type == 'typeset') {return box}
 3089:       if (box.type == 'mlist') {
 3090:         box.mlist.Atomize(style,size);
 3091:         return box.mlist.Typeset(style,size);
 3092:       }
 3093:       if (box.type == 'text') {
 3094:         box = this.Text(box.text,box.tclass,style,size,box.ascend||null,box.descend||null);
 3095:         if (addstyle != 0) {box.Styled()}
 3096:         return box;
 3097:       }
 3098:       box = this.TeX(box.c,box.font,style,size);
 3099:       if (addstyle != 0) {box.Styled()}
 3100:       return box;
 3101:     }
 3102:     return jsMath.Box.Null;
 3103:   },
 3104: 
 3105:   /*
 3106:    *  Convert a list of boxes to a single typeset box.  I.e., finalize
 3107:    *  the HTML for the list of boxes, properly spaced and positioned.
 3108:    */
 3109:   SetList: function (boxes,style,size) {
 3110:     var mlist = []; var box;
 3111:     for (var i = 0; i < boxes.length; i++) {
 3112:       box = boxes[i];
 3113:       if (box.type == 'typeset') {box = jsMath.mItem.Typeset(box)}
 3114:       mlist[mlist.length] = box;
 3115:     }
 3116:     var typeset = new jsMath.Typeset(mlist);
 3117:     return typeset.Typeset(style,size);
 3118:   }
 3119: 
 3120: });
 3121: 
 3122: 
 3123: jsMath.Package(jsMath.Box,{
 3124: 
 3125:   /*
 3126:    *  Add the class and style to a text box (i.e., finalize the
 3127:    *  unpositioned HTML for the box).
 3128:    */
 3129:   Styled: function () {
 3130:     if (this.format == 'text') {
 3131:       this.html = jsMath.Typeset.AddClass(this.tclass,this.html);
 3132:       this.html = jsMath.Typeset.AddStyle(this.style,this.size,this.html);
 3133:       delete this.tclass; delete this.style;
 3134:       this.format = 'html';
 3135:     }
 3136:     return this;
 3137:   },
 3138:   
 3139:   /*
 3140:    *  Recompute the box width to make it more accurate.
 3141:    */
 3142:   Remeasured: function () {
 3143:     if (this.w > 0) {this.w = jsMath.EmBoxFor(this.html).w}
 3144:     return this;
 3145:   }
 3146: 
 3147: });
 3148: 
 3149: 
 3150: /***************************************************************************/
 3151: 
 3152: /*
 3153:  *  mItems are the building blocks of mLists (math lists) used to
 3154:  *  store the information about a mathematical expression.  These are
 3155:  *  basically the items listed in the TeXbook in Appendix G (plus some
 3156:  *  minor extensions).
 3157:  */
 3158: jsMath.mItem = function (type,def) {
 3159:   this.type = type;
 3160:   jsMath.Add(this,def);
 3161: }
 3162: 
 3163: jsMath.Add(jsMath.mItem,{
 3164: 
 3165:   /*
 3166:    *  A general atom (given a nucleus for the atom)
 3167:    */
 3168:   Atom: function (type,nucleus) {
 3169:     return new jsMath.mItem(type,{atom: 1, nuc: nucleus});
 3170:   },
 3171: 
 3172:   /*
 3173:    *  An atom whose nucleus is a piece of text, in a given
 3174:    *  class, with a given additional height and depth
 3175:    */
 3176:   TextAtom: function (type,text,tclass,a,d) {
 3177:     var atom = new jsMath.mItem(type,{
 3178:       atom: 1,
 3179:       nuc: {
 3180:         type: 'text',
 3181:         text: text,
 3182:         tclass: tclass
 3183:       }
 3184:     });
 3185:     if (a != null) {atom.nuc.ascend = a}
 3186:     if (d != null) {atom.nuc.descend = d}
 3187:     return atom;
 3188:   },
 3189:   
 3190:   /*
 3191:    *  An atom whose nucleus is a TeX character in a specific font
 3192:    */
 3193:   TeXAtom: function (type,c,font) {
 3194:     return new jsMath.mItem(type,{
 3195:       atom: 1,
 3196:       nuc: {
 3197:         type: 'TeX',
 3198:         c: c,
 3199:         font: font
 3200:       }
 3201:     });
 3202:   },
 3203: 
 3204:   /*
 3205:    *  A generalized fraction atom, with given delimiters, rule
 3206:    *  thickness, and a numerator and denominator.
 3207:    */
 3208:   Fraction: function (name,num,den,thickness,left,right) {
 3209:     return new jsMath.mItem('fraction',{
 3210:       from: name, num: num, den: den,
 3211:       thickness: thickness, left: left, right: right
 3212:     });
 3213:   },
 3214: 
 3215:   /*
 3216:    *  An atom that inserts some glue
 3217:    */
 3218:   Space: function (w) {return new jsMath.mItem('space',{w: w})},
 3219: 
 3220:   /*
 3221:    *  An atom that contains a typeset box (like an hbox or vbox)
 3222:    */
 3223:   Typeset: function (box) {return new jsMath.mItem('ord',{atom:1, nuc: box})},
 3224:   
 3225:   /*
 3226:    *  An atom that contains some finished HTML (acts like a typeset box)
 3227:    */
 3228:   HTML: function (html) {return new jsMath.mItem('html',{html: html})}
 3229: 
 3230: });
 3231: 
 3232: /***************************************************************************/
 3233: 
 3234: /*
 3235:  *  mLists are lists of mItems, and encode the contents of
 3236:  *  mathematical expressions and sub-expressions.  They act as
 3237:  *  the expression "stack" as the mathematics is parsed, and
 3238:  *  contain some state information, like the position of the
 3239:  *  most recent open paren and \over command, and the current font.
 3240:  */
 3241: jsMath.mList = function (list,font,size,style) {
 3242:   if (list) {this.mlist = list} else {this.mlist = []}
 3243:   if (style == null) {style = 'T'}; if (size == null) {size = 4}
 3244:   this.data = {openI: null, overI: null, overF: null,
 3245:                font: font, size: size, style: style};
 3246:   this.init = {size: size, style: style};
 3247: }
 3248: 
 3249: jsMath.Package(jsMath.mList,{
 3250: 
 3251:   /*
 3252:    *  Add an mItem to the list
 3253:    */
 3254:   Add: function (box) {return (this.mlist[this.mlist.length] = box)},
 3255:   
 3256:   /*
 3257:    *  Get the i-th mItem from the list
 3258:    */
 3259:   Get: function (i) {return this.mlist[i]},
 3260:   
 3261:   /*
 3262:    *  Get the length of the list
 3263:    */
 3264:   Length: function() {return this.mlist.length},
 3265: 
 3266:   /*
 3267:    *  Get the tail mItem of the list
 3268:    */
 3269:   Last: function () {
 3270:     if (this.mlist.length == 0) {return null}
 3271:     return this.mlist[this.mlist.length-1]
 3272:   },
 3273: 
 3274:   /*
 3275:    *  Get a sublist of an mList
 3276:    */
 3277:   Range: function (i,j) {
 3278:     if (j == null) {j = this.mlist.length}
 3279:     return new jsMath.mList(this.mlist.slice(i,j+1));
 3280:   },
 3281: 
 3282:   /*
 3283:    *  Remove a range of mItems from the list.
 3284:    */
 3285:   Delete: function (i,j) {
 3286:     if (j == null) {j = i}
 3287:     if (this.mlist.splice) {this.mlist.splice(i,j-i+1)} else {
 3288:       var mlist = [];
 3289:       for (var k = 0; k < this.mlist.length; k++)
 3290:         {if (k < i || k > j) {mlist[mlist.length] = this.mlist[k]}}
 3291:       this.mlist = mlist;
 3292:     }
 3293:   },
 3294: 
 3295:   /*
 3296:    *  Add an open brace and maintain the stack information
 3297:    *  about the previous open brace so we can recover it
 3298:    *  when this one os closed.
 3299:    */
 3300:   Open: function (left) {
 3301:     var box = this.Add(new jsMath.mItem('boundary',{data: this.data}));
 3302:     var olddata = this.data;
 3303:     this.data = {}; for (var i in olddata) {this.data[i] = olddata[i]}
 3304:     delete this.data.overI; delete this.data.overF;
 3305:     this.data.openI = this.mlist.length-1;
 3306:     if (left != null) {box.left = left}
 3307:     return box;
 3308:   },
 3309: 
 3310:   /*
 3311:    *  Attempt to close a brace.  Recover the stack information
 3312:    *  about previous open braces and \over commands.  If there was an
 3313:    *  \over (or \above, etc) in this set of braces, create a fraction
 3314:    *  atom from the two halves, otherwise create an inner or ord
 3315:    *  from the contents of the braces.
 3316:    *  Remove the braced material from the list and add the newly
 3317:    *  created atom (the fraction, inner or ord).
 3318:    */
 3319:   Close: function (right) {
 3320:     if (right != null) {right = new jsMath.mItem('boundary',{right: right})}
 3321:     var atom; var open = this.data.openI;
 3322:     var over = this.data.overI; var from = this.data.overF;
 3323:     this.data  = this.mlist[open].data;
 3324:     if (over) {
 3325:       atom = jsMath.mItem.Fraction(from.name,
 3326:         {type: 'mlist', mlist: this.Range(open+1,over-1)},
 3327:         {type: 'mlist', mlist: this.Range(over)},
 3328:         from.thickness,from.left,from.right);
 3329:       if (right) {
 3330:         var mlist = new jsMath.mList([this.mlist[open],atom,right]);
 3331:         atom = jsMath.mItem.Atom('inner',{type: 'mlist', mlist: mlist});
 3332:       }
 3333:     } else {
 3334:       var openI = open+1; if (right) {this.Add(right); openI--}
 3335:       atom = jsMath.mItem.Atom((right)?'inner':'ord',
 3336:                   {type: 'mlist', mlist: this.Range(openI)});
 3337:     }
 3338:     this.Delete(open,this.Length());
 3339:     return this.Add(atom);
 3340:   },
 3341: 
 3342:   /*
 3343:    *  Create a generalized fraction from an mlist that
 3344:    *  contains an \over (or \above, etc).
 3345:    */
 3346:   Over: function () {
 3347:     var over = this.data.overI; var from = this.data.overF;
 3348:     var atom = jsMath.mItem.Fraction(from.name,
 3349:       {type: 'mlist', mlist: this.Range(open+1,over-1)},
 3350:       {type: 'mlist', mlist: this.Range(over)},
 3351:       from.thickness,from.left,from.right);
 3352:     this.mlist = [atom];
 3353:   },
 3354: 
 3355:   /*
 3356:    *  Take a raw mList (that has been produced by parsing some TeX
 3357:    *  expression), and perform the modifications outlined in
 3358:    *  Appendix G of the TeXbook.  
 3359:    */
 3360:   Atomize: function (style,size) {
 3361:     var mitem; var prev = '';
 3362:     this.style = style; this.size = size;
 3363:     for (var i = 0; i < this.mlist.length; i++) {
 3364:       mitem = this.mlist[i]; mitem.delta = 0;
 3365:       if (mitem.type == 'choice') 
 3366:         {this.mlist = this.Atomize.choice(this.style,mitem,i,this.mlist); i--}
 3367:       else if (this.Atomize[mitem.type]) {
 3368:         var f = this.Atomize[mitem.type]; // Opera needs separate name
 3369:         f(this.style,this.size,mitem,prev,this,i);
 3370:       }
 3371:       prev = mitem;
 3372:     }
 3373:     if (mitem && mitem.type == 'bin') {mitem.type = 'ord'}
 3374:     if (this.mlist.length >= 2 && mitem.type == 'boundary' &&
 3375:         this.mlist[0].type == 'boundary') {this.AddDelimiters(style,size)}
 3376:   },
 3377: 
 3378:   /*
 3379:    *  For a list that has boundary delimiters as its first and last
 3380:    *  entries, we replace the boundary atoms by open and close
 3381:    *  atoms whose nuclii are the specified delimiters properly sized
 3382:    *  for the contents of the list.  (Rule 19)
 3383:    */
 3384:   AddDelimiters: function(style,size) {
 3385:     var unset = -10000; var h = unset; var d = unset;
 3386:     for (var i = 0; i < this.mlist.length; i++) {
 3387:       var mitem = this.mlist[i];
 3388:       if (mitem.atom || mitem.type == 'box') {
 3389:         h = Math.max(h,mitem.nuc.h+mitem.nuc.y);
 3390:         d = Math.max(d,mitem.nuc.d-mitem.nuc.y);
 3391:       }
 3392:     }
 3393:     var TeX = jsMath.TeX; var a = jsMath.Typeset.TeX(style,size).axis_height;
 3394:     var delta = Math.max(h-a,d+a);
 3395:     var H =  Math.max(Math.floor(TeX.integer*delta/500)*TeX.delimiterfactor,
 3396:                       TeX.integer*(2*delta-TeX.delimitershortfall))/TeX.integer;
 3397:     var left = this.mlist[0]; var right = this.mlist[this.mlist.length-1];
 3398:     left.nuc = jsMath.Box.Delimiter(H,left.left,style);
 3399:     right.nuc = jsMath.Box.Delimiter(H,right.right,style);
 3400:     left.type = 'open'; left.atom = 1; delete left.left;
 3401:     right.type = 'close'; right.atom = 1; delete right.right;
 3402:   },
 3403:   
 3404:   /*
 3405:    *  Typeset a math list to produce final HTML for the list.
 3406:    */
 3407:   Typeset: function (style,size) {
 3408:     var typeset = new jsMath.Typeset(this.mlist);
 3409:     return typeset.Typeset(style,size);
 3410:   }
 3411: 
 3412: });
 3413: 
 3414: 
 3415: /*
 3416:  *  These routines implement the main rules given in Appendix G of the
 3417:  *  TeXbook
 3418:  */
 3419: 
 3420: jsMath.Add(jsMath.mList.prototype.Atomize,{
 3421: 
 3422:   /*
 3423:    *  Handle \displaystyle, \textstyle, etc.
 3424:    */
 3425:   style: function (style,size,mitem,prev,mlist) {
 3426:     mlist.style = mitem.style;
 3427:   },
 3428:   
 3429:   /*
 3430:    *  Handle \tiny, \small, etc.
 3431:    */
 3432:   size: function (style,size,mitem,prev,mlist) {
 3433:     mlist.size = mitem.size;
 3434:   },
 3435:   
 3436:   /*
 3437:    *  Create empty boxes of the proper sizes for the various
 3438:    *  phantom-type commands
 3439:    */
 3440:   phantom: function (style,size,mitem) {
 3441:     var box = mitem.nuc = jsMath.Box.Set(mitem.phantom,style,size);
 3442:     if (mitem.h) {box.Remeasured(); box.html = jsMath.HTML.Spacer(box.w)}
 3443:       else {box.html = '', box.w = 0}
 3444:     if (!mitem.v) {box.h = box.d = 0}
 3445:     box.bd = box.bh = 0;
 3446:     delete mitem.phantom;
 3447:     mitem.type = 'box';
 3448:   },
 3449:   
 3450:   /*
 3451:    *  Create a box of zero height and depth containing the
 3452:    *  contents of the atom
 3453:    */
 3454:   smash: function (style,size,mitem) {
 3455:     var box = mitem.nuc = jsMath.Box.Set(mitem.smash,style,size).Remeasured();
 3456:     box.h = box.d = box.bd = box.bh = 0;
 3457:     delete mitem.smash;
 3458:     mitem.type = 'box';
 3459:   },
 3460: 
 3461:   /*
 3462:    *  Move a box up or down vertically
 3463:    */
 3464:   raise: function (style,size,mitem) {
 3465:     mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size);
 3466:     var y = mitem.raise;
 3467:     mitem.nuc.html = jsMath.HTML.Place(mitem.nuc.html,0,y);
 3468:     mitem.nuc.h += y; mitem.nuc.d -= y;
 3469:     mitem.type = 'ord'; mitem.atom = 1;
 3470:   },
 3471: 
 3472:   /*
 3473:    *  Hide the size of a box so that it laps to the left or right, or
 3474:    *  up or down.
 3475:    */
 3476:   lap: function (style,size,mitem) {
 3477:     var box = jsMath.Box.Set(mitem.nuc,style,size).Remeasured();
 3478:     var mlist = [box];
 3479:     if (mitem.lap == 'llap') {box.x = -box.w} else
 3480:     if (mitem.lap == 'rlap') {mlist[1] = jsMath.mItem.Space(-box.w)} else
 3481:     if (mitem.lap == 'ulap') {box.y = box.d; box.h = box.d = 0} else
 3482:     if (mitem.lap == 'dlap') {box.y = -box.h; box.h = box.d = 0}
 3483:     mitem.nuc = jsMath.Box.SetList(mlist,style,size);
 3484:     if (mitem.lap == 'ulap' || mitem.lap == 'dlap') {mitem.nuc.h = mitem.nuc.d = 0}
 3485:     mitem.type = 'box'; delete mitem.atom;
 3486:   },
 3487: 
 3488:   /*
 3489:    *  Handle a Bin atom. (Rule 5)
 3490:    */
 3491:   bin: function (style,size,mitem,prev) {
 3492:     if (prev && prev.type) {
 3493:       var type  = prev.type;
 3494:       if (type == 'bin' || type == 'op' || type == 'rel' ||
 3495:           type == 'open' || type == 'punct' || type == '' ||
 3496:           (type == 'boundary' && prev.left != '')) {mitem.type = 'ord'}
 3497:     } else {mitem.type = 'ord'}
 3498:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3499:   },
 3500: 
 3501:   /*
 3502:    *  Handle a Rel atom.  (Rule 6)
 3503:    */
 3504:   rel: function (style,size,mitem,prev) {
 3505:     if (prev.type && prev.type == 'bin') {prev.type = 'ord'}
 3506:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3507:   },
 3508: 
 3509:   /*
 3510:    *  Handle a Close atom.  (Rule 6)
 3511:    */
 3512:   close: function (style,size,mitem,prev) {
 3513:     if (prev.type && prev.type == 'bin') {prev.type = 'ord'}
 3514:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3515:   },
 3516: 
 3517:   /*
 3518:    *  Handle a Punct atom.  (Rule 6)
 3519:    */
 3520:   punct: function (style,size,mitem,prev) {
 3521:     if (prev.type && prev.type == 'bin') {prev.type = 'ord'}
 3522:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3523:   },
 3524: 
 3525:   /*
 3526:    *  Handle an Open atom.  (Rule 7)
 3527:    */
 3528:   open: function (style,size,mitem) {
 3529:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3530:   },
 3531: 
 3532:   /*
 3533:    *  Handle an Inner atom.  (Rule 7)
 3534:    */
 3535:   inner: function (style,size,mitem) {
 3536:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3537:   },
 3538: 
 3539:   /*
 3540:    *  Handle a Vcent atom.  (Rule 8)
 3541:    */
 3542:   vcenter: function (style,size,mitem) {
 3543:     var box = jsMath.Box.Set(mitem.nuc,style,size);
 3544:     var TeX = jsMath.Typeset.TeX(style,size);
 3545:     box.y = TeX.axis_height - (box.h-box.d)/2;
 3546:     mitem.nuc = box; mitem.type = 'ord';
 3547:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3548:   },
 3549: 
 3550:   /*
 3551:    *  Handle an Over atom.  (Rule 9)
 3552:    */
 3553:   overline: function (style,size,mitem) {
 3554:     var TeX = jsMath.Typeset.TeX(style,size);
 3555:     var box = jsMath.Box.Set(mitem.nuc,jsMath.Typeset.PrimeStyle(style),size).Remeasured();
 3556:     var t = TeX.default_rule_thickness;
 3557:     var rule = jsMath.Box.Rule(box.w,t);
 3558:     rule.x = -rule.w; rule.y = box.h + 3*t;
 3559:     mitem.nuc = jsMath.Box.SetList([box,rule],style,size);
 3560:     mitem.nuc.h += t;
 3561:     mitem.type = 'ord';
 3562:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3563:   },
 3564: 
 3565:   /*
 3566:    *  Handle an Under atom.  (Rule 10)
 3567:    */
 3568:   underline: function (style,size,mitem) {
 3569:     var TeX = jsMath.Typeset.TeX(style,size);
 3570:     var box = jsMath.Box.Set(mitem.nuc,jsMath.Typeset.PrimeStyle(style),size).Remeasured();
 3571:     var t = TeX.default_rule_thickness;
 3572:     var rule = jsMath.Box.Rule(box.w,t);
 3573:     rule.x = -rule.w; rule.y = -box.d - 3*t - t;
 3574:     mitem.nuc = jsMath.Box.SetList([box,rule],style,size);
 3575:     mitem.nuc.d += t;
 3576:     mitem.type = 'ord';
 3577:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3578:   },
 3579: 
 3580:   /*
 3581:    *  Handle a Rad atom.  (Rule 11 plus stuff for \root..\of)
 3582:    */
 3583:   radical: function (style,size,mitem) {
 3584:     var TeX = jsMath.Typeset.TeX(style,size);
 3585:     var Cp = jsMath.Typeset.PrimeStyle(style);
 3586:     var box = jsMath.Box.Set(mitem.nuc,Cp,size).Remeasured();
 3587:     var t = TeX.default_rule_thickness;
 3588:     var p = t; if (style == 'D' || style == "D'") {p = TeX.x_height}
 3589:     var r = t + p/4; 
 3590:     var surd = jsMath.Box.Delimiter(box.h+box.d+r+t,[0,2,0x70,3,0x70],style,1);
 3591: //    if (surd.h > 0) {t = surd.h} // thickness of rule is height of surd character
 3592:     if (surd.d > box.h+box.d+r) {r = (r+surd.d-box.h-box.d)/2}
 3593:     surd.y = box.h+r;
 3594:     var rule = jsMath.Box.Rule(box.w,t);
 3595:     rule.y = surd.y-t/2; rule.h += 3*t/2; box.x = -box.w;
 3596:     var Cr = jsMath.Typeset.UpStyle(jsMath.Typeset.UpStyle(style));
 3597:     var root = jsMath.Box.Set(mitem.root || null,Cr,size).Remeasured();
 3598:     if (mitem.root) {
 3599:       root.y = .55*(box.h+box.d+3*t+r)-box.d;
 3600:       surd.x = Math.max(root.w-(11/18)*surd.w,0);
 3601:       rule.x = (7/18)*surd.w;
 3602:       root.x = -(root.w+rule.x);
 3603:     }
 3604:     mitem.nuc = jsMath.Box.SetList([surd,root,rule,box],style,size);
 3605:     mitem.type = 'ord';
 3606:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3607:   },
 3608: 
 3609:   /*
 3610:    *  Handle an Acc atom.  (Rule 12)
 3611:    */
 3612:   accent: function (style,size,mitem) {
 3613:     var TeX = jsMath.Typeset.TeX(style,size);
 3614:     var Cp = jsMath.Typeset.PrimeStyle(style);
 3615:     var box = jsMath.Box.Set(mitem.nuc,Cp,size);
 3616:     var u = box.w; var s; var Font;
 3617:     if (mitem.nuc.type == 'TeX') {
 3618:       Font = jsMath.TeX[mitem.nuc.font];
 3619:       if (Font[mitem.nuc.c].krn && Font.skewchar)
 3620:         {s = Font[mitem.nuc.c].krn[Font.skewchar]}
 3621:     }
 3622:     if (s == null) {s = 0}
 3623:     
 3624:     var c = mitem.accent[2];
 3625:     var font = jsMath.TeX.fam[mitem.accent[1]]; Font = jsMath.TeX[font];
 3626:     while (Font[c].n && Font[Font[c].n].w <= u) {c = Font[c].n}
 3627:     
 3628:     var delta = Math.min(box.h,TeX.x_height);
 3629:     if (mitem.nuc.type == 'TeX') {
 3630:       var nitem = jsMath.mItem.Atom('ord',mitem.nuc);
 3631:       nitem.sup = mitem.sup; nitem.sub = mitem.sub; nitem.delta = 0;
 3632:       jsMath.mList.prototype.Atomize.SupSub(style,size,nitem);
 3633:       delta += (nitem.nuc.h - box.h);
 3634:       box = mitem.nuc = nitem.nuc;
 3635:       delete mitem.sup; delete mitem.sub;
 3636:     }
 3637:     var acc = jsMath.Box.TeX(c,font,style,size);
 3638:     acc.y = box.h - delta; acc.x = -box.w + s + (u-acc.w)/2;
 3639:     if (Font[c].ic) {acc.x -= Font[c].ic * TeX.scale}
 3640: 
 3641:     mitem.nuc = jsMath.Box.SetList([box,acc],style,size);
 3642:     if (mitem.nuc.w != box.w) {
 3643:       var space = jsMath.mItem.Space(box.w-mitem.nuc.w);
 3644:       mitem.nuc = jsMath.Box.SetList([mitem.nuc,space],style,size);
 3645:     }
 3646:     mitem.type = 'ord';
 3647:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3648:   },
 3649: 
 3650:   /*
 3651:    *  Handle an Op atom.  (Rules 13 and 13a)
 3652:    */
 3653:   op: function (style,size,mitem) {
 3654:     var TeX = jsMath.Typeset.TeX(style,size); var box;
 3655:     mitem.delta = 0; var isD = (style.charAt(0) == 'D');
 3656:     if (mitem.limits == null && isD) {mitem.limits = 1}
 3657: 
 3658:     if (mitem.nuc.type == 'TeX') {
 3659:       var C = jsMath.TeX[mitem.nuc.font][mitem.nuc.c];
 3660:       if (isD && C.n) {mitem.nuc.c = C.n; C = jsMath.TeX[mitem.nuc.font][C.n]}
 3661:       box = jsMath.Box.Set(mitem.nuc,style,size);
 3662:       if (C.ic) {
 3663:         mitem.delta = C.ic * TeX.scale;
 3664:         if (mitem.limits || !mitem.sub || jsMath.Browser.msieIntegralBug) 
 3665:           {box = jsMath.Box.SetList([box,jsMath.mItem.Space(mitem.delta)],style,size)}
 3666:       }
 3667:       box.y = -((box.h+box.d)/2 - box.d - TeX.axis_height);
 3668:       if (Math.abs(box.y) < .0001) {box.y = 0}
 3669:     }
 3670: 
 3671:     if (!box) {box = jsMath.Box.Set(mitem.nuc,style,size).Remeasured()}
 3672:     if (mitem.limits) {
 3673:       var W = box.w; var x = box.w;
 3674:       var mlist = [box]; var dh = 0; var dd = 0;
 3675:       if (mitem.sup) {
 3676:         var sup = jsMath.Box.Set(mitem.sup,jsMath.Typeset.UpStyle(style),size).Remeasured();
 3677:         sup.x = ((box.w-sup.w)/2 + mitem.delta/2) - x; dh = TeX.big_op_spacing5;
 3678:         W = Math.max(W,sup.w); x += sup.x + sup.w;
 3679:         sup.y = box.h+sup.d + box.y +
 3680:                     Math.max(TeX.big_op_spacing1,TeX.big_op_spacing3-sup.d);
 3681:         mlist[mlist.length] = sup; delete mitem.sup;
 3682:       }
 3683:       if (mitem.sub) {
 3684:         var sub = jsMath.Box.Set(mitem.sub,jsMath.Typeset.DownStyle(style),size).Remeasured();
 3685:         sub.x = ((box.w-sub.w)/2 - mitem.delta/2) - x; dd = TeX.big_op_spacing5;
 3686:         W = Math.max(W,sub.w); x += sub.x + sub.w;
 3687:         sub.y = -box.d-sub.h + box.y -
 3688:                    Math.max(TeX.big_op_spacing2,TeX.big_op_spacing4-sub.h);
 3689:         mlist[mlist.length] = sub; delete mitem.sub;
 3690:       }
 3691:       if (W > box.w) {box.x = (W-box.w)/2; x += box.x}
 3692:       if (x < W) {mlist[mlist.length] = jsMath.mItem.Space(W-x)}
 3693:       mitem.nuc = jsMath.Box.SetList(mlist,style,size);
 3694:       mitem.nuc.h += dh; mitem.nuc.d += dd;
 3695:     } else {
 3696:       if (jsMath.Browser.msieIntegralBug && mitem.sub && C && C.ic) 
 3697:         {mitem.nuc = jsMath.Box.SetList([box,jsMath.Box.Space(-C.ic*TeX.scale)],style,size)}
 3698:       else if (box.y) {mitem.nuc = jsMath.Box.SetList([box],style,size)}
 3699:       jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3700:     }
 3701:   },
 3702: 
 3703:   /*
 3704:    *  Handle an Ord atom.  (Rule 14)
 3705:    */
 3706:   ord: function (style,size,mitem,prev,mList,i) {
 3707:     if (mitem.nuc.type == 'TeX' && !mitem.sup && !mitem.sub) {
 3708:       var nitem = mList.mlist[i+1];
 3709:       if (nitem && nitem.atom && nitem.type &&
 3710:           (nitem.type == 'ord' || nitem.type == 'op' || nitem.type == 'bin' ||
 3711:            nitem.type == 'rel' || nitem.type == 'open' ||
 3712:            nitem.type == 'close' || nitem.type == 'punct')) {
 3713:         if (nitem.nuc.type == 'TeX' && nitem.nuc.font == mitem.nuc.font) {
 3714:           mitem.textsymbol = 1;
 3715:           var krn = jsMath.TeX[mitem.nuc.font][mitem.nuc.c].krn;
 3716:           krn *= jsMath.Typeset.TeX(style,size).scale;
 3717:           if (krn && krn[nitem.nuc.c]) {
 3718:             for (var k = mList.mlist.length-1; k > i; k--)
 3719:               {mList.mlist[k+1] = mList.mlist[k]}
 3720:             mList.mlist[i+1] = jsMath.mItem.Space(krn[nitem.nuc.c]);
 3721:           }
 3722:         }
 3723:       }
 3724:     }
 3725:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3726:   },
 3727: 
 3728:   /*
 3729:    *  Handle a generalized fraction.  (Rules 15 to 15e)
 3730:    */
 3731:   fraction: function (style,size,mitem) {
 3732:     var TeX = jsMath.Typeset.TeX(style,size); var t = 0;
 3733:     if (mitem.thickness != null) {t = mitem.thickness}
 3734:     else if (mitem.from.match(/over/)) {t = TeX.default_rule_thickness}
 3735:     var isD = (style.charAt(0) == 'D');
 3736:     var Cn = (style == 'D')? 'T': (style == "D'")? "T'": jsMath.Typeset.UpStyle(style);
 3737:     var Cd = (isD)? "T'": jsMath.Typeset.DownStyle(style);
 3738:     var num = jsMath.Box.Set(mitem.num,Cn,size).Remeasured();
 3739:     var den = jsMath.Box.Set(mitem.den,Cd,size).Remeasured();
 3740: 
 3741:     var u; var v; var w;
 3742:     var H = (isD)? TeX.delim1 : TeX.delim2;
 3743:     var mlist = [jsMath.Box.Delimiter(H,mitem.left,style)]
 3744:     var right = jsMath.Box.Delimiter(H,mitem.right,style);
 3745: 
 3746:     if (num.w < den.w) {
 3747:       num.x = (den.w-num.w)/2;
 3748:       den.x = -(num.w + num.x);
 3749:       w = den.w; mlist[1] = num; mlist[2] = den;
 3750:     } else {
 3751:       den.x = (num.w-den.w)/2;
 3752:       num.x = -(den.w + den.x);
 3753:       w = num.w; mlist[1] = den; mlist[2] = num;
 3754:     }
 3755:     if (isD) {u = TeX.num1; v = TeX.denom1} else {
 3756:       u = (t != 0)? TeX.num2: TeX.num3;
 3757:       v = TeX.denom2;
 3758:     }
 3759:     if (t == 0) {// atop
 3760:       var p = (isD)? 7*TeX.default_rule_thickness: 3*TeX.default_rule_thickness;
 3761:       var r = (u - num.d) - (den.h - v);
 3762:       if (r < p) {u += (p-r)/2; v += (p-r)/2}
 3763:     } else {// over
 3764:       var p = (isD)? 3*t: t; var a = TeX.axis_height;
 3765:       var r = (u-num.d)-(a+t/2); if (r < p) {u += p-r}
 3766:           r = (a-t/2)-(den.h-v); if (r < p) {v += p-r}
 3767:       var rule = jsMath.Box.Rule(w,t); rule.x = -w; rule.y = a - t/2;
 3768:       mlist[mlist.length] = rule;
 3769:     }
 3770:     num.y = u; den.y = -v;
 3771: 
 3772:     mlist[mlist.length] = right;
 3773:     mitem.nuc = jsMath.Box.SetList(mlist,style,size);
 3774:     mitem.type = 'ord'; mitem.atom = 1;
 3775:     delete mitem.num; delete mitem.den;
 3776:     jsMath.mList.prototype.Atomize.SupSub(style,size,mitem);
 3777:   },
 3778: 
 3779:   /*
 3780:    *  Add subscripts and superscripts.  (Rules 17-18f)
 3781:    */
 3782:   SupSub: function (style,size,mitem) {
 3783:     var TeX = jsMath.Typeset.TeX(style,size);
 3784:     var nuc = mitem.nuc;
 3785:     var box = mitem.nuc = jsMath.Box.Set(mitem.nuc,style,size,0);
 3786:     if (box.format == 'null') 
 3787:       {box = mitem.nuc = jsMath.Box.Text('','normal',style,size)}
 3788: 
 3789:     if (nuc.type == 'TeX') {
 3790:       if (!mitem.textsymbol) {
 3791:         var C = jsMath.TeX[nuc.font][nuc.c];
 3792:         if (C.ic) {
 3793:           mitem.delta = C.ic * TeX.scale;
 3794:           if (!mitem.sub) {
 3795:             box = mitem.nuc = jsMath.Box.SetList([box,jsMath.Box.Space(mitem.delta)],style,size);
 3796:             mitem.delta = 0;
 3797:           }
 3798:         }
 3799:       } else {mitem.delta = 0}
 3800:     }
 3801: 
 3802:     if (!mitem.sup && !mitem.sub) return;
 3803:     mitem.nuc.Styled();
 3804:     
 3805:     var Cd = jsMath.Typeset.DownStyle(style);
 3806:     var Cu = jsMath.Typeset.UpStyle(style);
 3807:     var q = jsMath.Typeset.TeX(Cu,size).sup_drop;
 3808:     var r = jsMath.Typeset.TeX(Cd,size).sub_drop;
 3809:     var u = 0; var v = 0; var p;
 3810:     if (nuc.type && nuc.type != 'text' && nuc.type != 'TeX' && nuc.type != 'null')
 3811:       {u = box.h - q; v = box.d + r}
 3812: 
 3813:     if (mitem.sub) {
 3814:       var sub = jsMath.Box.Set(mitem.sub,Cd,size);
 3815:       sub = jsMath.Box.SetList([sub,jsMath.mItem.Space(TeX.scriptspace)],style,size);
 3816:     }
 3817: 
 3818:     if (!mitem.sup) {
 3819:       sub.y = -Math.max(v,TeX.sub1,sub.h-(4/5)*jsMath.Typeset.TeX(Cd,size).x_height);
 3820:       mitem.nuc = jsMath.Box.SetList([box,sub],style,size).Styled(); delete mitem.sub;
 3821:       return;
 3822:     }
 3823: 
 3824:     var sup = jsMath.Box.Set(mitem.sup,Cu,size);
 3825:     sup = jsMath.Box.SetList([sup,jsMath.mItem.Space(TeX.scriptspace)],style,size);
 3826:     if (style == 'D') {p = TeX.sup1}
 3827:     else if (style.charAt(style.length-1) == "'") {p = TeX.sup3}
 3828:     else {p = TeX.sup2}
 3829:     u = Math.max(u,p,sup.d+jsMath.Typeset.TeX(Cu,size).x_height/4);
 3830: 
 3831:     if (!mitem.sub) {
 3832:       sup.y = u;
 3833:       mitem.nuc = jsMath.Box.SetList([box,sup],style,size); delete mitem.sup;
 3834:       return;
 3835:     }
 3836: 
 3837:     v = Math.max(v,jsMath.Typeset.TeX(Cd,size).sub2);
 3838:     var t = TeX.default_rule_thickness;
 3839:     if ((u-sup.d) - (sub.h -v) < 4*t) {
 3840:       v = 4*t + sub.h - (u-sup.d);
 3841:       p = (4/5)*TeX.x_height - (u-sup.d);
 3842:       if (p > 0) {u += p; v -= p}
 3843:     }
 3844:     sup.Remeasured(); sub.Remeasured();
 3845:     sup.y = u; sub.y = -v; sup.x = mitem.delta;
 3846:     if (sup.w+sup.x > sub.w)
 3847:       {sup.x -= sub.w; mitem.nuc = jsMath.Box.SetList([box,sub,sup],style,size)} else
 3848:       {sub.x -= (sup.w+sup.x); mitem.nuc = jsMath.Box.SetList([box,sup,sub],style,size)}
 3849: 
 3850:     delete mitem.sup; delete mitem.sub;
 3851:   }
 3852: 
 3853: });
 3854: 
 3855: 
 3856: /***************************************************************************/
 3857: 
 3858: /*
 3859:  *  The Typeset object handles most of the TeX-specific processing
 3860:  */
 3861: 
 3862: jsMath.Typeset = function (mlist) {
 3863:   this.type = 'typeset';
 3864:   this.mlist = mlist;
 3865: }
 3866: 
 3867: jsMath.Add(jsMath.Typeset,{
 3868: 
 3869:   /*
 3870:    *  The "C-uparrow" style table (TeXbook, p. 441)
 3871:    */
 3872:   upStyle: {
 3873:     D: "S", T: "S",  "D'": "S'", "T'": "S'",
 3874:     S: "SS",  SS: "SS",  "S'": "SS'", "SS'": "SS'"
 3875:   },
 3876: 
 3877:   /*
 3878:    *  The "C-downarrow" style table (TeXbook, p. 441)
 3879:    */
 3880:   downStyle: {
 3881:     D: "S'", T: "S'",  "D'": "S'", "T'": "S'",
 3882:     S: "SS'",  SS: "SS'",  "S'": "SS'", "SS'": "SS'"
 3883:   },
 3884: 
 3885:   /*
 3886:    *  Get the various styles given the current style
 3887:    *  (see TeXbook, p. 441)
 3888:    */
 3889:   UpStyle: function (style) {return this.upStyle[style]},
 3890:   DownStyle: function (style) {return this.downStyle[style]},
 3891:   PrimeStyle: function (style) {
 3892:     if (style.charAt(style.length-1) == "'") {return style}
 3893:     return style + "'"
 3894:   },
 3895: 
 3896:   /*
 3897:    *  A value scaled to the appropriate size for scripts
 3898:    */
 3899:   StyleValue: function (style,v) {
 3900:     if (style == "S" || style == "S'")   {return .7*v}
 3901:     if (style == "SS" || style == "SS'") {return .5*v}
 3902:     return v;
 3903:   },
 3904:   
 3905:   /*
 3906:    *  Return the size associated with a given style and size
 3907:    */
 3908:   StyleSize: function (style,size) {
 3909:     if      (style == "S" || style == "S'")   {size = Math.max(0,size-2)}
 3910:     else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}
 3911:     return size;
 3912:   },
 3913: 
 3914:   /*
 3915:    *  Return the font parameter table for the given style
 3916:    */
 3917:   TeX: function (style,size) {
 3918:     if      (style == "S" || style == "S'")   {size = Math.max(0,size-2)}
 3919:     else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}
 3920:     return jsMath.TeXparams[size];
 3921:   },
 3922: 
 3923: 
 3924:   /*
 3925:    *  Add the CSS class for the given TeX style
 3926:    */
 3927:   AddStyle: function (style,size,html) {
 3928:     if      (style == "S" || style == "S'")   {size = Math.max(0,size-2)}
 3929:     else if (style == "SS" || style == "SS'") {size = Math.max(0,size-4)}
 3930:     if (size != 4) {html = '<span class="size'+size+'">' + html + '</span>'}
 3931:     return html;
 3932:   },
 3933: 
 3934:   /*
 3935:    *  Add the font class, if needed
 3936:    */
 3937:   AddClass: function (tclass,html) {
 3938:     if (tclass != '' && tclass != 'normal') {html = jsMath.HTML.Class(tclass,html)}
 3939:     return html;
 3940:   }
 3941: 
 3942: });
 3943: 
 3944: 
 3945: jsMath.Package(jsMath.Typeset,{
 3946:   
 3947:   /*
 3948:    *  The spacing tables for inter-atom spacing
 3949:    *  (See rule 20, and Chapter 18, p 170)
 3950:    */
 3951:   DTsep: {
 3952:     ord: {op: 1, bin: 2, rel: 3, inner: 1},
 3953:     op:  {ord: 1, op: 1, rel: 3, inner: 1},
 3954:     bin: {ord: 2, op: 2, open: 2, inner: 2},
 3955:     rel: {ord: 3, op: 3, open: 3, inner: 3},
 3956:     open: {},
 3957:     close: {op: 1, bin:2, rel: 3, inner: 1},
 3958:     punct: {ord: 1, op: 1, rel: 1, open: 1, close: 1, punct: 1, inner: 1},
 3959:     inner: {ord: 1, op: 1, bin: 2, rel: 3, open: 1, punct: 1, inner: 1}
 3960:   },
 3961: 
 3962:   SSsep: {
 3963:     ord: {op: 1},
 3964:     op:  {ord: 1, op: 1},
 3965:     bin: {},
 3966:     rel: {},
 3967:     open: {},
 3968:     close: {op: 1},
 3969:     punct: {},
 3970:     inner: {op: 1}
 3971:   },
 3972: 
 3973:   /*
 3974:    *  The sizes used in the tables above
 3975:    */
 3976:   sepW: ['','thinmuskip','medmuskip','thickmuskip'],
 3977:   
 3978:   
 3979:   /*
 3980:    *  Find the amount of separation to use between two adjacent
 3981:    *  atoms in the given style
 3982:    */
 3983:   GetSeparation: function (l,r,style) {
 3984:     if (l && l.atom && r.atom) {
 3985:       var table = this.DTsep; if (style.charAt(0) == "S") {table = this.SSsep}
 3986:       var row = table[l.type];
 3987:       if (row && row[r.type] != null) {return jsMath.TeX[this.sepW[row[r.type]]]}
 3988:     }
 3989:     return 0;
 3990:   },
 3991: 
 3992:   /*
 3993:    *  Typeset an mlist (i.e., turn it into HTML).
 3994:    *  Here, text items of the same class and style are combined
 3995:    *  to reduce the number of <SPAN> tags used (though it is still
 3996:    *  huge).  Spaces are combined, when possible.
 3997:    *  ###  More needs to be done with that.  ###
 3998:    *  The width of the final box is recomputed at the end, since
 3999:    *  the final width is not necessarily the sum of the widths of
 4000:    *  the individual parts (widths are in pixels, but the browsers
 4001:    *  puts pieces together using sub-pixel accuracy).
 4002:    */
 4003:   Typeset: function (style,size) {
 4004:     this.style = style; this.size = size; var unset = -10000
 4005:     this.w = 0; this.h = unset; this.d = unset;
 4006:     this.bh = this.h; this.bd = this.d;
 4007:     this.tbuf = ''; this.tx = 0; this.tclass = '';
 4008:     this.cbuf = ''; this.hbuf = ''; this.hx = 0;
 4009:     var mitem = null; var prev; this.x = 0; this.dx = 0;
 4010: 
 4011:     for (var i = 0; i < this.mlist.length; i++) {
 4012:       prev = mitem; mitem = this.mlist[i];
 4013:       switch (mitem.type) {
 4014: 
 4015:         case 'size':
 4016:           this.FlushClassed();
 4017:           this.size = mitem.size;
 4018:           mitem = prev; // hide this from TeX
 4019:           break;
 4020: 
 4021:         case 'style':
 4022:           this.FlushClassed();
 4023:           if (this.style.charAt(this.style.length-1) == "'")
 4024:             {this.style = mitem.style + "'"} else {this.style = mitem.style}
 4025:           mitem = prev; // hide this from TeX
 4026:           break;
 4027: 
 4028:         case 'space':
 4029:           if (typeof(mitem.w) == 'object') {
 4030:             if (this.style.charAt(1) == 'S') {mitem.w = .5*mitem.w[0]/18}
 4031:             else if (this.style.charAt(0) == 'S') {mitem.w = .7*mitem.w[0]/18}
 4032:             else {mitem.w = mitem.w[0]/18}
 4033:           }
 4034:           this.dx += mitem.w-0; // mitem.w is sometimes a string?
 4035:           mitem = prev; // hide this from TeX
 4036:           break;
 4037:           
 4038:         case 'html':
 4039:           this.FlushClassed();
 4040:           if (this.hbuf == '') {this.hx = this.x}
 4041:           this.hbuf += mitem.html;
 4042:           mitem = prev; // hide this from TeX
 4043:           break;
 4044:           
 4045:         default:   // atom
 4046:           if (!mitem.atom && mitem.type != 'box') break;
 4047:           mitem.nuc.x += this.dx + this.GetSeparation(prev,mitem,this.style);
 4048:           if (mitem.nuc.y || mitem.nuc.x) mitem.nuc.Styled();
 4049:           this.dx = 0; this.x = this.x + this.w;
 4050:           this.w += mitem.nuc.w + mitem.nuc.x;
 4051:           if (mitem.nuc.format == 'text') {
 4052:             if (this.tclass != mitem.nuc.tclass && this.tclass != '') this.FlushText();
 4053:             if (this.tbuf == '' && this.cbuf == '') {this.tx = this.x}
 4054:             this.tbuf += mitem.nuc.html; this.tclass = mitem.nuc.tclass;
 4055:           } else  {
 4056:             this.FlushClassed();
 4057:             if (mitem.nuc.x || mitem.nuc.y) this.Place(mitem.nuc);
 4058:             if (this.hbuf == '') {this.hx = this.x}
 4059:             this.hbuf += mitem.nuc.html;
 4060:           }
 4061:           this.h = Math.max(this.h,mitem.nuc.h+mitem.nuc.y); this.bh = Math.max(this.bh,mitem.nuc.bh);
 4062:           this.d = Math.max(this.d,mitem.nuc.d-mitem.nuc.y); this.bd = Math.max(this.bd,mitem.nuc.bd);
 4063:           break;
 4064:       }
 4065:     }
 4066:     
 4067:     this.FlushClassed(); // make sure scaling is included
 4068:     if (this.dx) {this.hbuf += jsMath.HTML.Spacer(this.dx); this.w += this.dx}
 4069:     if (this.hbuf == '') {return jsMath.Box.Null}
 4070:     if (this.h == unset) {this.h = 0}
 4071:     if (this.d == unset) {this.d = 0}
 4072:     var box = new jsMath.Box('html',this.hbuf,this.w,this.h,this.d);
 4073:     box.bh = this.bh; box.bd = this.bd;
 4074:     return box;
 4075:   },
 4076: 
 4077:   /*
 4078:    *  Add the font to the buffered text and move it to the
 4079:    *  classed-text buffer.
 4080:    */
 4081:   FlushText: function () {
 4082:     if (this.tbuf == '') return;
 4083:     this.cbuf += jsMath.Typeset.AddClass(this.tclass,this.tbuf);
 4084:     this.tbuf = ''; this.tclass = '';
 4085:   },
 4086: 
 4087:   /*
 4088:    *  Add the script or scriptscript style to the text and
 4089:    *  move it to the HTML buffer
 4090:    */
 4091:   FlushClassed: function () {
 4092:     this.FlushText();
 4093:     if (this.cbuf == '') return;
 4094:     if (this.hbuf == '') {this.hx = this.tx}
 4095:     this.hbuf += jsMath.Typeset.AddStyle(this.style,this.size,this.cbuf);
 4096:     this.cbuf = '';
 4097:   },
 4098: 
 4099:   /*
 4100:    *  Add a <SPAN> to position an item's HTML, and
 4101:    *  adjust the item's height and depth.
 4102:    *  (This may be replaced buy one of the following browser-specific
 4103:    *   versions by Browser.Init().)
 4104:    */
 4105:   Place: function (item) {
 4106:     var html = '<span style="position: relative;';
 4107:     if (item.x) {html += ' margin-left:'+jsMath.HTML.Em(item.x)+';'}
 4108:     if (item.y) {html += ' top:'+jsMath.HTML.Em(-item.y)+';'}
 4109:     item.html = html + '">' + item.html + '</span>';
 4110:     item.h += item.y; item.d -= item.y;
 4111:     item.x = 0; item.y = 0;
 4112:   },
 4113:   
 4114:   /*
 4115:    *  For MSIE on Windows, backspacing must be done in a separate
 4116:    *  <SPAN>, otherwise the contents will be clipped.  Netscape
 4117:    *  also doesn't combine vertical and horizontal spacing well.
 4118:    *  Here, the horizontal and vertical spacing are done separately.
 4119:    */
 4120:   PlaceSeparateSkips: function (item) {
 4121:     if (item.y) {
 4122:       item.html = '<span style="position: relative; '
 4123:                      + 'top:'+jsMath.HTML.Em(-item.y)+';'
 4124:                      + '">' + item.html + '</span>'
 4125:     }
 4126:     if (item.x) {item.html = jsMath.HTML.Spacer(item.x) + item.html}
 4127:     item.h += item.y; item.d -= item.y;
 4128:     item.x = 0; item.y = 0;
 4129:   }
 4130:   
 4131: });
 4132: 
 4133: 
 4134: 
 4135: /***************************************************************************/
 4136: 
 4137: /*
 4138:  *  The Parse object handles the parsing of the TeX input string, and creates
 4139:  *  the mList to be typeset by the Typeset object above.
 4140:  */
 4141: 
 4142: jsMath.Parse = function (s,font,size,style) {
 4143:   var parse = new jsMath.Parser(s,font,size,style);
 4144:   parse.Parse();
 4145:   return parse;
 4146: }
 4147: 
 4148: jsMath.Parser = function (s,font,size,style) {
 4149:   this.string = s; this.i = 0;
 4150:   this.mlist = new jsMath.mList(null,font,size,style);
 4151: }
 4152: 
 4153: jsMath.Package(jsMath.Parser,{
 4154:   
 4155:   // special characters
 4156:   cmd:   '\\',
 4157:   open:  '{',
 4158:   close: '}',
 4159:   
 4160:   // patterns for letters and numbers
 4161:   letter:  /[a-z]/i,
 4162:   number:  /[0-9]/,
 4163:   //  pattern for macros to ^ and _ that should be read with arguments
 4164:   scriptargs: /^((math|text)..|mathcal|[hm]box)$/,
 4165:   
 4166:   //  the \mathchar definitions (see Appendix B of the TeXbook).
 4167:   mathchar: {
 4168:     '!': [5,0,0x21],
 4169:     '(': [4,0,0x28],
 4170:     ')': [5,0,0x29],
 4171:     '*': [2,2,0x03], // \ast
 4172:     '+': [2,0,0x2B],
 4173:     ',': [6,1,0x3B],
 4174:     '-': [2,2,0x00],
 4175:     '.': [0,1,0x3A],
 4176:     '/': [0,1,0x3D],
 4177:     ':': [3,0,0x3A],
 4178:     ';': [6,0,0x3B],
 4179:     '<': [3,1,0x3C],
 4180:     '=': [3,0,0x3D],
 4181:     '>': [3,1,0x3E],
 4182:     '?': [5,0,0x3F],
 4183:     '[': [4,0,0x5B],
 4184:     ']': [5,0,0x5D],
 4185: //  '{': [4,2,0x66],
 4186: //  '}': [5,2,0x67],
 4187:     '|': [0,2,0x6A]
 4188:   },
 4189: 
 4190:   //  handle special \catcode characters
 4191:   special: {
 4192:     '~':   'Tilde',
 4193:     '^':   'HandleSuperscript',
 4194:     '_':   'HandleSubscript',
 4195:     ' ':   'Space',
 4196:     '\01': 'Space',
 4197:     "\t":  'Space',
 4198:     "\r":  'Space',
 4199:     "\n":  'Space',
 4200:     "'":   'Prime',
 4201:     '%':   'HandleComment',
 4202:     '&':   'HandleEntry'
 4203:   },
 4204: 
 4205:   // the \mathchardef table (see Appendix B of the TeXbook).
 4206:   mathchardef: {
 4207:   // brace parts
 4208:     braceld:      [0,3,0x7A],
 4209:     bracerd:      [0,3,0x7B],
 4210:     bracelu:      [0,3,0x7C],
 4211:     braceru:      [0,3,0x7D],
 4212: 
 4213:   // Greek letters
 4214:     alpha:        [0,1,0x0B],
 4215:     beta:         [0,1,0x0C],
 4216:     gamma:        [0,1,0x0D],
 4217:     delta:        [0,1,0x0E],
 4218:     epsilon:      [0,1,0x0F],
 4219:     zeta:         [0,1,0x10],
 4220:     eta:          [0,1,0x11],
 4221:     theta:        [0,1,0x12],
 4222:     iota:         [0,1,0x13],
 4223:     kappa:        [0,1,0x14],
 4224:     lambda:       [0,1,0x15],
 4225:     mu:           [0,1,0x16],
 4226:     nu:           [0,1,0x17],
 4227:     xi:           [0,1,0x18],
 4228:     pi:           [0,1,0x19],
 4229:     rho:          [0,1,0x1A],
 4230:     sigma:        [0,1,0x1B],
 4231:     tau:          [0,1,0x1C],
 4232:     upsilon:      [0,1,0x1D],
 4233:     phi:          [0,1,0x1E],
 4234:     chi:          [0,1,0x1F],
 4235:     psi:          [0,1,0x20],
 4236:     omega:        [0,1,0x21],
 4237:     varepsilon:   [0,1,0x22],
 4238:     vartheta:     [0,1,0x23],
 4239:     varpi:        [0,1,0x24],
 4240:     varrho:       [0,1,0x25],
 4241:     varsigma:     [0,1,0x26],
 4242:     varphi:       [0,1,0x27],
 4243:     
 4244:     Gamma:        [7,0,0x00],
 4245:     Delta:        [7,0,0x01],
 4246:     Theta:        [7,0,0x02],
 4247:     Lambda:       [7,0,0x03],
 4248:     Xi:           [7,0,0x04],
 4249:     Pi:           [7,0,0x05],
 4250:     Sigma:        [7,0,0x06],
 4251:     Upsilon:      [7,0,0x07],
 4252:     Phi:          [7,0,0x08],
 4253:     Psi:          [7,0,0x09],
 4254:     Omega:        [7,0,0x0A],
 4255: 
 4256:   // Ord symbols
 4257:     aleph:        [0,2,0x40],
 4258:     imath:        [0,1,0x7B],
 4259:     jmath:        [0,1,0x7C],
 4260:     ell:          [0,1,0x60],
 4261:     wp:           [0,1,0x7D],
 4262:     Re:           [0,2,0x3C],
 4263:     Im:           [0,2,0x3D],
 4264:     partial:      [0,1,0x40],
 4265:     infty:        [0,2,0x31],
 4266:     prime:        [0,2,0x30],
 4267:     emptyset:     [0,2,0x3B],
 4268:     nabla:        [0,2,0x72],
 4269:     surd:         [1,2,0x70],
 4270:     top:          [0,2,0x3E],
 4271:     bot:          [0,2,0x3F],
 4272:     triangle:     [0,2,0x34],
 4273:     forall:       [0,2,0x38],
 4274:     exists:       [0,2,0x39],
 4275:     neg:          [0,2,0x3A],
 4276:     lnot:         [0,2,0x3A],
 4277:     flat:         [0,1,0x5B],
 4278:     natural:      [0,1,0x5C],
 4279:     sharp:        [0,1,0x5D],
 4280:     clubsuit:     [0,2,0x7C],
 4281:     diamondsuit:  [0,2,0x7D],
 4282:     heartsuit:    [0,2,0x7E],
 4283:     spadesuit:    [0,2,0x7F],
 4284: 
 4285:   // big ops
 4286:     coprod:      [1,3,0x60],
 4287:     bigvee:      [1,3,0x57],
 4288:     bigwedge:    [1,3,0x56],
 4289:     biguplus:    [1,3,0x55],
 4290:     bigcap:      [1,3,0x54],
 4291:     bigcup:      [1,3,0x53],
 4292:     intop:       [1,3,0x52], 
 4293:     prod:        [1,3,0x51],
 4294:     sum:         [1,3,0x50],
 4295:     bigotimes:   [1,3,0x4E],
 4296:     bigoplus:    [1,3,0x4C],
 4297:     bigodot:     [1,3,0x4A],
 4298:     ointop:      [1,3,0x48],
 4299:     bigsqcup:    [1,3,0x46],
 4300:     smallint:    [1,2,0x73],
 4301: 
 4302:   // binary operations
 4303:     triangleleft:      [2,1,0x2F],
 4304:     triangleright:     [2,1,0x2E],
 4305:     bigtriangleup:     [2,2,0x34],
 4306:     bigtriangledown:   [2,2,0x35],
 4307:     wedge:       [2,2,0x5E],
 4308:     land:        [2,2,0x5E],
 4309:     vee:         [2,2,0x5F],
 4310:     lor:         [2,2,0x5F],
 4311:     cap:         [2,2,0x5C],
 4312:     cup:         [2,2,0x5B],
 4313:     ddagger:     [2,2,0x7A],
 4314:     dagger:      [2,2,0x79],
 4315:     sqcap:       [2,2,0x75],
 4316:     sqcup:       [2,2,0x74],
 4317:     uplus:       [2,2,0x5D],
 4318:     amalg:       [2,2,0x71],
 4319:     diamond:     [2,2,0x05],
 4320:     bullet:      [2,2,0x0F],
 4321:     wr:          [2,2,0x6F],
 4322:     div:         [2,2,0x04],
 4323:     odot:        [2,2,0x0C],
 4324:     oslash:      [2,2,0x0B],
 4325:     otimes:      [2,2,0x0A],
 4326:     ominus:      [2,2,0x09],
 4327:     oplus:       [2,2,0x08],
 4328:     mp:          [2,2,0x07],
 4329:     pm:          [2,2,0x06],
 4330:     circ:        [2,2,0x0E],
 4331:     bigcirc:     [2,2,0x0D],
 4332:     setminus:    [2,2,0x6E], // for set difference A\setminus B
 4333:     cdot:        [2,2,0x01],
 4334:     ast:         [2,2,0x03],
 4335:     times:       [2,2,0x02],
 4336:     star:        [2,1,0x3F],
 4337: 
 4338:   // Relations
 4339:     propto:      [3,2,0x2F],
 4340:     sqsubseteq:  [3,2,0x76],
 4341:     sqsupseteq:  [3,2,0x77],
 4342:     parallel:    [3,2,0x6B],
 4343:     mid:         [3,2,0x6A],
 4344:     dashv:       [3,2,0x61],
 4345:     vdash:       [3,2,0x60],
 4346:     leq:         [3,2,0x14],
 4347:     le:          [3,2,0x14],
 4348:     geq:         [3,2,0x15],
 4349:     ge:          [3,2,0x15],
 4350:     succ:        [3,2,0x1F],
 4351:     prec:        [3,2,0x1E],
 4352:     approx:      [3,2,0x19],
 4353:     succeq:      [3,2,0x17],
 4354:     preceq:      [3,2,0x16],
 4355:     supset:      [3,2,0x1B],
 4356:     subset:      [3,2,0x1A],
 4357:     supseteq:    [3,2,0x13],
 4358:     subseteq:    [3,2,0x12],
 4359:     'in':        [3,2,0x32],
 4360:     ni:          [3,2,0x33],
 4361:     owns:        [3,2,0x33],
 4362:     gg:          [3,2,0x1D],
 4363:     ll:          [3,2,0x1C],
 4364:     not:         [3,2,0x36],
 4365:     sim:         [3,2,0x18],
 4366:     simeq:       [3,2,0x27],
 4367:     perp:        [3,2,0x3F],
 4368:     equiv:       [3,2,0x11],
 4369:     asymp:       [3,2,0x10],
 4370:     smile:       [3,1,0x5E],
 4371:     frown:       [3,1,0x5F],
 4372: 
 4373:   // Arrows
 4374:     Leftrightarrow:   [3,2,0x2C],
 4375:     Leftarrow:        [3,2,0x28],
 4376:     Rightarrow:       [3,2,0x29],
 4377:     leftrightarrow:   [3,2,0x24],
 4378:     leftarrow:        [3,2,0x20],
 4379:     gets:             [3,2,0x20],
 4380:     rightarrow:       [3,2,0x21],
 4381:     to:               [3,2,0x21],
 4382:     mapstochar:       [3,2,0x37],
 4383:     leftharpoonup:    [3,1,0x28],
 4384:     leftharpoondown:  [3,1,0x29],
 4385:     rightharpoonup:   [3,1,0x2A],
 4386:     rightharpoondown: [3,1,0x2B],
 4387:     nearrow:          [3,2,0x25],
 4388:     searrow:          [3,2,0x26],
 4389:     nwarrow:          [3,2,0x2D],
 4390:     swarrow:          [3,2,0x2E],
 4391: 
 4392:     hbarchar:   [0,0,0x16], // for \hbar
 4393:     lhook:      [3,1,0x2C],
 4394:     rhook:      [3,1,0x2D],
 4395: 
 4396:     ldotp:      [6,1,0x3A], // ldot as a punctuation mark
 4397:     cdotp:      [6,2,0x01], // cdot as a punctuation mark
 4398:     colon:      [6,0,0x3A], // colon as a punctuation mark
 4399: 
 4400:     '#':        [7,0,0x23],
 4401:     '$':        [7,0,0x24],
 4402:     '%':        [7,0,0x25],
 4403:     '&':        [7,0,0x26]
 4404:   },
 4405:   
 4406:   // The delimiter table (see Appendix B of the TeXbook)
 4407:   delimiter: {
 4408:     '(':                [0,0,0x28,3,0x00],
 4409:     ')':                [0,0,0x29,3,0x01],
 4410:     '[':                [0,0,0x5B,3,0x02],
 4411:     ']':                [0,0,0x5D,3,0x03],
 4412:     '<':                [0,2,0x68,3,0x0A],
 4413:     '>':                [0,2,0x69,3,0x0B],
 4414:     '/':                [0,0,0x2F,3,0x0E],
 4415:     '|':                [0,2,0x6A,3,0x0C],
 4416:     '.':                [0,0,0x00,0,0x00],
 4417:     '\\':               [0,2,0x6E,3,0x0F],
 4418:     '\\lmoustache':     [4,3,0x7A,3,0x40],  // top from (, bottom from )
 4419:     '\\rmoustache':     [5,3,0x7B,3,0x41],  // top from ), bottom from (
 4420:     '\\lgroup':         [4,6,0x28,3,0x3A],  // extensible ( with sharper tips
 4421:     '\\rgroup':         [5,6,0x29,3,0x3B],  // extensible ) with sharper tips
 4422:     '\\arrowvert':      [0,2,0x6A,3,0x3C],  // arrow without arrowheads
 4423:     '\\Arrowvert':      [0,2,0x6B,3,0x3D],  // double arrow without arrowheads
 4424: //  '\\bracevert':      [0,7,0x7C,3,0x3E],  // the vertical bar that extends braces
 4425:     '\\bracevert':      [0,2,0x6A,3,0x3E],  // we don't load tt, so use | instead
 4426:     '\\Vert':           [0,2,0x6B,3,0x0D],
 4427:     '\\|':              [0,2,0x6B,3,0x0D],
 4428:     '\\vert':           [0,2,0x6A,3,0x0C],
 4429:     '\\uparrow':        [3,2,0x22,3,0x78],
 4430:     '\\downarrow':      [3,2,0x23,3,0x79],
 4431:     '\\updownarrow':    [3,2,0x6C,3,0x3F],
 4432:     '\\Uparrow':        [3,2,0x2A,3,0x7E],
 4433:     '\\Downarrow':      [3,2,0x2B,3,0x7F],
 4434:     '\\Updownarrow':    [3,2,0x6D,3,0x77],
 4435:     '\\backslash':      [0,2,0x6E,3,0x0F],  // for double coset G\backslash H
 4436:     '\\rangle':         [5,2,0x69,3,0x0B],
 4437:     '\\langle':         [4,2,0x68,3,0x0A],
 4438:     '\\rbrace':         [5,2,0x67,3,0x09],
 4439:     '\\lbrace':         [4,2,0x66,3,0x08],
 4440:     '\\}':              [5,2,0x67,3,0x09],
 4441:     '\\{':              [4,2,0x66,3,0x08],
 4442:     '\\rceil':          [5,2,0x65,3,0x07],
 4443:     '\\lceil':          [4,2,0x64,3,0x06],
 4444:     '\\rfloor':         [5,2,0x63,3,0x05],
 4445:     '\\lfloor':         [4,2,0x62,3,0x04],
 4446:     '\\lbrack':         [0,0,0x5B,3,0x02],
 4447:     '\\rbrack':         [0,0,0x5D,3,0x03]
 4448:   },
 4449: 
 4450:   /*
 4451:    *  The basic macros for plain TeX.
 4452:    *
 4453:    *  When the control sequence on the left is called, the JavaScript
 4454:    *  funtion on the right is called, with the name of the control sequence
 4455:    *  as its first parameter (this way, the same function can be called by
 4456:    *  several different control sequences to do similar actions, and the
 4457:    *  function can still tell which TeX command was issued).  If the right
 4458:    *  is an array, the first entry is the routine to call, and the
 4459:    *  remaining entries in the array are parameters to pass to the function
 4460:    *  as the second parameter (they are in an array reference).
 4461:    *  
 4462:    *  Note:  TeX macros as defined by the user are discussed below.
 4463:    */
 4464:   macros: {
 4465:     displaystyle:      ['HandleStyle','D'],
 4466:     textstyle:         ['HandleStyle','T'],
 4467:     scriptstyle:       ['HandleStyle','S'],
 4468:     scriptscriptstyle: ['HandleStyle','SS'],
 4469:     
 4470:     rm:                ['HandleFont',0],
 4471:     mit:               ['HandleFont',1],
 4472:     oldstyle:          ['HandleFont',1],
 4473:     cal:               ['HandleFont',2],
 4474:     it:                ['HandleFont',4],
 4475:     bf:                ['HandleFont',6],
 4476:     
 4477:     font:              ['Extension','font'],
 4478:     
 4479:     left:              'HandleLeft',
 4480:     right:             'HandleRight',
 4481: 
 4482:     arcsin:       ['NamedOp',0],
 4483:     arccos:       ['NamedOp',0],
 4484:     arctan:       ['NamedOp',0],
 4485:     arg:          ['NamedOp',0],
 4486:     cos:          ['NamedOp',0],
 4487:     cosh:         ['NamedOp',0],
 4488:     cot:          ['NamedOp',0],
 4489:     coth:         ['NamedOp',0],
 4490:     csc:          ['NamedOp',0],
 4491:     deg:          ['NamedOp',0],
 4492:     det:           'NamedOp',
 4493:     dim:          ['NamedOp',0],
 4494:     exp:          ['NamedOp',0],
 4495:     gcd:           'NamedOp',
 4496:     hom:          ['NamedOp',0],
 4497:     inf:           'NamedOp',
 4498:     ker:          ['NamedOp',0],
 4499:     lg:           ['NamedOp',0],
 4500:     lim:           'NamedOp',
 4501:     liminf:       ['NamedOp',null,'lim<span style="margin-left: '+1/6+'em"></span>inf'],
 4502:     limsup:       ['NamedOp',null,'lim<span style="margin-left: '+1/6+'em"></span>sup'],
 4503:     ln:           ['NamedOp',0],
 4504:     log:          ['NamedOp',0],
 4505:     max:           'NamedOp',
 4506:     min:           'NamedOp',
 4507:     Pr:            'NamedOp',
 4508:     sec:          ['NamedOp',0],
 4509:     sin:          ['NamedOp',0],
 4510:     sinh:         ['NamedOp',0],
 4511:     sup:           'NamedOp',
 4512:     tan:          ['NamedOp',0],
 4513:     tanh:         ['NamedOp',0],
 4514: 
 4515:     vcenter:        ['HandleAtom','vcenter'],
 4516:     overline:       ['HandleAtom','overline'],
 4517:     underline:      ['HandleAtom','underline'],
 4518:     over:            'HandleOver',
 4519:     overwithdelims:  'HandleOver',
 4520:     atop:            'HandleOver',
 4521:     atopwithdelims:  'HandleOver',
 4522:     above:           'HandleOver',
 4523:     abovewithdelims: 'HandleOver',
 4524:     brace:           ['HandleOver','\\{','\\}'],
 4525:     brack:           ['HandleOver','[',']'],
 4526:     choose:          ['HandleOver','(',')'],
 4527:     
 4528:     overbrace:       ['Extension','leaders'],
 4529:     underbrace:      ['Extension','leaders'],
 4530:     overrightarrow:  ['Extension','leaders'],
 4531:     overleftarrow:   ['Extension','leaders'],
 4532:     overset:         ['Extension','underset-overset'],
 4533:     underset:        ['Extension','underset-overset'],
 4534: 
 4535:     llap:            'HandleLap',
 4536:     rlap:            'HandleLap',
 4537:     ulap:            'HandleLap',
 4538:     dlap:            'HandleLap',
 4539:     raise:           'RaiseLower',
 4540:     lower:           'RaiseLower',
 4541:     moveleft:        'MoveLeftRight',
 4542:     moveright:       'MoveLeftRight',
 4543: 
 4544:     frac:            'Frac',
 4545:     root:            'Root',
 4546:     sqrt:            'Sqrt',
 4547: 
 4548:     //  TeX substitution macros
 4549:     hbar:               ['Macro','\\hbarchar\\kern-.5em h'],
 4550:     ne:                 ['Macro','\\not='],
 4551:     neq:                ['Macro','\\not='],
 4552:     notin:              ['Macro','\\mathrel{\\rlap{\\kern2mu/}}\\in'],
 4553:     cong:               ['Macro','\\mathrel{\\lower2mu{\\mathrel{{\\rlap{=}\\raise6mu\\sim}}}}'],
 4554:     bmod:               ['Macro','\\mathbin{\\rm mod}'],
 4555:     pmod:               ['Macro','\\kern 18mu ({\\rm mod}\\,\\,#1)',1],
 4556:     'int':              ['Macro','\\intop\\nolimits'],
 4557:     oint:               ['Macro','\\ointop\\nolimits'],
 4558:     doteq:              ['Macro','\\buildrel\\textstyle.\\over='],
 4559:     ldots:              ['Macro','\\mathinner{\\ldotp\\ldotp\\ldotp}'],
 4560:     cdots:              ['Macro','\\mathinner{\\cdotp\\cdotp\\cdotp}'],
 4561:     vdots:              ['Macro','\\mathinner{\\rlap{\\raise8pt{.\\rule 0pt 6pt 0pt}}\\rlap{\\raise4pt{.}}.}'],
 4562:     ddots:              ['Macro','\\mathinner{\\kern1mu\\raise7pt{\\rule 0pt 7pt 0pt .}\\kern2mu\\raise4pt{.}\\kern2mu\\raise1pt{.}\\kern1mu}'],
 4563:     joinrel:            ['Macro','\\mathrel{\\kern-4mu}'],
 4564:     relbar:             ['Macro','\\mathrel{\\smash-}'], // \smash, because - has the same height as +
 4565:     Relbar:             ['Macro','\\mathrel='],
 4566:     bowtie:             ['Macro','\\mathrel\\triangleright\\joinrel\\mathrel\\triangleleft'],
 4567:     models:             ['Macro','\\mathrel|\\joinrel='],
 4568:     mapsto:             ['Macro','\\mapstochar\\rightarrow'],
 4569:     rightleftharpoons:  ['Macro','\\vcenter{\\mathrel{\\rlap{\\raise3mu{\\rightharpoonup}}}\\leftharpoondown}'],
 4570:     hookrightarrow:     ['Macro','\\lhook\\joinrel\\rightarrow'],
 4571:     hookleftarrow:      ['Macro','\\leftarrow\\joinrel\\rhook'],
 4572:     Longrightarrow:     ['Macro','\\Relbar\\joinrel\\Rightarrow'],
 4573:     longrightarrow:     ['Macro','\\relbar\\joinrel\\rightarrow'],
 4574:     longleftarrow:      ['Macro','\\leftarrow\\joinrel\\relbar'],
 4575:     Longleftarrow:      ['Macro','\\Leftarrow\\joinrel\\Relbar'],
 4576:     longmapsto:         ['Macro','\\mapstochar\\char{cmsy10}{0}\\joinrel\\rightarrow'],
 4577:     longleftrightarrow: ['Macro','\\leftarrow\\joinrel\\rightarrow'],
 4578:     Longleftrightarrow: ['Macro','\\Leftarrow\\joinrel\\Rightarrow'],
 4579:     iff:                ['Macro','\\;\\Longleftrightarrow\\;'],
 4580:     mathcal:            ['Macro','{\\cal #1}',1],
 4581:     mathrm:             ['Macro','{\\rm #1}',1],
 4582:     mathbf:             ['Macro','{\\bf #1}',1],
 4583:     mathbb:             ['Macro','{\\bf #1}',1],
 4584:     mathit:             ['Macro','{\\it #1}',1],
 4585:     textrm:             ['Macro','\\mathord{\\hbox{#1}}',1],
 4586:     textit:             ['Macro','\\mathord{\\class{textit}{\\hbox{#1}}}',1],
 4587:     textbf:             ['Macro','\\mathord{\\class{textbf}{\\hbox{#1}}}',1],
 4588: 
 4589:     TeX:                ['Macro','T\\kern-.1667em\\lower.5ex{E}\\kern-.125em X'],
 4590: 
 4591:     limits:       ['Limits',1],
 4592:     nolimits:     ['Limits',0],
 4593: 
 4594:     ',':          ['Spacer',1/6],
 4595:     ':':          ['Spacer',1/6],  // for LaTeX
 4596:     '>':          ['Spacer',2/9],
 4597:     ';':          ['Spacer',5/18],
 4598:     '!':          ['Spacer',-1/6],
 4599:     enspace:      ['Spacer',1/2],
 4600:     quad:         ['Spacer',1],
 4601:     qquad:        ['Spacer',2],
 4602:     thinspace:    ['Spacer',1/6],
 4603:     negthinspace: ['Spacer',-1/6],
 4604:     
 4605:     hskip:         'Hskip',
 4606:     kern:          'Hskip',
 4607:     rule:          ['Rule','colored'],
 4608:     space:         ['Rule','blank'],
 4609:     
 4610:     big:        ['MakeBig','ord',0.85],
 4611:     Big:        ['MakeBig','ord',1.15],
 4612:     bigg:       ['MakeBig','ord',1.45],
 4613:     Bigg:       ['MakeBig','ord',1.75],
 4614:     bigl:       ['MakeBig','open',0.85],
 4615:     Bigl:       ['MakeBig','open',1.15],
 4616:     biggl:      ['MakeBig','open',1.45],
 4617:     Biggl:      ['MakeBig','open',1.75],
 4618:     bigr:       ['MakeBig','close',0.85],
 4619:     Bigr:       ['MakeBig','close',1.15],
 4620:     biggr:      ['MakeBig','close',1.45],
 4621:     Biggr:      ['MakeBig','close',1.75],
 4622:     bigm:       ['MakeBig','rel',0.85],
 4623:     Bigm:       ['MakeBig','rel',1.15],
 4624:     biggm:      ['MakeBig','rel',1.45],
 4625:     Biggm:      ['MakeBig','rel',1.75],
 4626:     
 4627:     mathord:    ['HandleAtom','ord'],
 4628:     mathop:     ['HandleAtom','op'],
 4629:     mathopen:   ['HandleAtom','open'],
 4630:     mathclose:  ['HandleAtom','close'],
 4631:     mathbin:    ['HandleAtom','bin'],
 4632:     mathrel:    ['HandleAtom','rel'],
 4633:     mathpunct:  ['HandleAtom','punct'],
 4634:     mathinner:  ['HandleAtom','inner'],
 4635:     
 4636:     mathchoice: ['Extension','mathchoice'],
 4637:     buildrel:   'BuildRel',
 4638:     
 4639:     hbox:       'HBox',
 4640:     text:       'HBox',
 4641:     mbox:       'HBox',
 4642:     fbox:       ['Extension','fbox'],
 4643: 
 4644:     strut:      'Strut',
 4645:     mathstrut:  ['Macro','\\vphantom{(}'],
 4646:     phantom:    ['Phantom',1,1],
 4647:     vphantom:   ['Phantom',1,0],
 4648:     hphantom:   ['Phantom',0,1],
 4649:     smash:      'Smash',
 4650:     
 4651:     acute:      ['MathAccent', [7,0,0x13]],
 4652:     grave:      ['MathAccent', [7,0,0x12]],
 4653:     ddot:       ['MathAccent', [7,0,0x7F]],
 4654:     tilde:      ['MathAccent', [7,0,0x7E]],
 4655:     bar:        ['MathAccent', [7,0,0x16]],
 4656:     breve:      ['MathAccent', [7,0,0x15]],
 4657:     check:      ['MathAccent', [7,0,0x14]],
 4658:     hat:        ['MathAccent', [7,0,0x5E]],
 4659:     vec:        ['MathAccent', [0,1,0x7E]],
 4660:     dot:        ['MathAccent', [7,0,0x5F]],
 4661:     widetilde:  ['MathAccent', [0,3,0x65]],
 4662:     widehat:    ['MathAccent', [0,3,0x62]],
 4663: 
 4664:     '_':        ['Replace','ord','_','normal',-.4,.1],
 4665:     ' ':        ['Replace','ord','&nbsp;','normal'],
 4666:     angle:      ['Replace','ord','&#x2220;','normal'],
 4667:         
 4668:     matrix:     'Matrix',
 4669:     array:      'Matrix',  // ### still need to do alignment options ###
 4670:     pmatrix:    ['Matrix','(',')','c'],
 4671:     cases:      ['Matrix','\\{','.',['l','l'],null,2],
 4672:     eqalign:    ['Matrix',null,null,['r','l'],[5/18],3,'D'],
 4673:     displaylines: ['Matrix',null,null,['c'],null,3,'D'],
 4674:     cr:         'HandleRow',
 4675:     '\\':       'HandleRow',
 4676:     noalign:    'HandleNoAlign',
 4677:     eqalignno:  ['Matrix',null,null,['r','l','r'],[5/8,3],3,'D'],
 4678:     leqalignno: ['Matrix',null,null,['r','l','r'],[5/8,3],3,'D'],
 4679:     
 4680:     //  LaTeX
 4681:     begin:      'Begin',
 4682:     end:        'End',
 4683:     tiny:       ['HandleSize',0],
 4684:     Tiny:       ['HandleSize',1],  // non-standard
 4685:     scriptsize: ['HandleSize',2],
 4686:     small:      ['HandleSize',3],
 4687:     normalsize: ['HandleSize',4],
 4688:     large:      ['HandleSize',5],
 4689:     Large:      ['HandleSize',6],
 4690:     LARGE:      ['HandleSize',7],
 4691:     huge:       ['HandleSize',8],
 4692:     Huge:       ['HandleSize',9],
 4693:     dots:       ['Macro','\\ldots'],
 4694:     
 4695:     newcommand: ['Extension','newcommand'],
 4696:     def:        ['Extension','newcommand'],
 4697: 
 4698:     //  Extensions to TeX
 4699:     color:      ['Extension','HTML'],
 4700:     href:       ['Extension','HTML'],
 4701:     'class':    ['Extension','HTML'],
 4702:     style:      ['Extension','HTML'],
 4703:     cssId:      ['Extension','HTML'],
 4704:     unicode:    ['Extension','HTML'],
 4705:     bbox:       ['Extension','bbox'],
 4706:     
 4707:     require:    'Require',
 4708:     
 4709:     //  debugging and test routines
 4710:     'char':     'Char'
 4711:   },
 4712:   
 4713:   /*
 4714:    *  LaTeX environments
 4715:    */
 4716:   environments: {
 4717:     array:      'Array',
 4718:     matrix:     ['Array',null,null,'c'],
 4719:     pmatrix:    ['Array','(',')','c'],
 4720:     bmatrix:    ['Array','[',']','c'],
 4721:     Bmatrix:    ['Array','\\{','\\}','c'],
 4722:     vmatrix:    ['Array','\\vert','\\vert','c'],
 4723:     Vmatrix:    ['Array','\\Vert','\\Vert','c'],
 4724:     cases:      ['Array','\\{','.','ll',null,2],
 4725:     eqnarray:   ['Array',null,null,'rcl',[5/18,5/18],3,'D']
 4726:   },
 4727: 
 4728: 
 4729:   /***************************************************************************/
 4730: 
 4731:   /*
 4732:    *  Add special characters to list above.  (This makes it possible
 4733:    *  to define them in a variable that the user can change.)
 4734:    */
 4735:   AddSpecial: function (obj) {
 4736:     for (var id in obj) {
 4737:       jsMath.Parser.prototype.special[jsMath.Parser.prototype[id]] = obj[id];
 4738:     }
 4739:   },
 4740: 
 4741:   /*
 4742:    *  Throw an error
 4743:    */
 4744:   Error: function (s) {
 4745:     this.i = this.string.length;
 4746:     if (s.error) {this.error = s.error} else {
 4747:       if (!this.error) {this.error = s}
 4748:     }
 4749:   },
 4750: 
 4751:   /***************************************************************************/
 4752: 
 4753:   /*
 4754:    *  Check if the next character is a space
 4755:    */
 4756:   nextIsSpace: function () {
 4757:     return this.string.charAt(this.i) == ' ';
 4758:   },
 4759:   
 4760:   /*
 4761:    *  Trim spaces from a string
 4762:    */
 4763:   trimSpaces: function (text) {
 4764:     if (typeof(text) != 'string') {return text}
 4765:     return text.replace(/^\s+|\s+/g,'');
 4766:   },
 4767: 
 4768:   /*
 4769:    *  Parse a substring to get its mList, and return it.
 4770:    *  Check that no errors occured
 4771:    */
 4772:   Process: function (arg) {
 4773:     var data = this.mlist.data;
 4774:     arg = jsMath.Parse(arg,data.font,data.size,data.style);
 4775:       if (arg.error) {this.Error(arg); return null}
 4776:     if (arg.mlist.Length() == 0) {return null}
 4777:     if (arg.mlist.Length() == 1) {
 4778:       var atom = arg.mlist.Last();
 4779:       if (atom.atom && atom.type == 'ord' && atom.nuc &&
 4780:          !atom.sub && !atom.sup && (atom.nuc.type == 'text' || atom.nuc.type == 'TeX'))
 4781:              {return atom.nuc}
 4782:     }
 4783:     return {type: 'mlist', mlist: arg.mlist};
 4784:   },
 4785: 
 4786:   /*
 4787:    *  Get and return a control-sequence name from the TeX string
 4788:    */
 4789:   GetCommand: function () {
 4790:     var letter = /^([a-z]+|.) ?/i;
 4791:     var cmd = letter.exec(this.string.slice(this.i));
 4792:     if (cmd) {this.i += cmd[1].length; return cmd[1]}
 4793:     this.i++; return " ";
 4794:   },
 4795: 
 4796:   /*
 4797:    *  Get and return a TeX argument (either a single character or control sequence,
 4798:    *  or the contents of the next set of braces).
 4799:    */
 4800:   GetArgument: function (name,noneOK) {
 4801:     while (this.nextIsSpace()) {this.i++}
 4802:     if (this.i >= this.string.length) {if (!noneOK) this.Error("Missing argument for "+name); return null}
 4803:     if (this.string.charAt(this.i) == this.close) {if (!noneOK) this.Error("Extra close brace"); return null}
 4804:     if (this.string.charAt(this.i) == this.cmd) {this.i++; return this.cmd+this.GetCommand()}
 4805:     if (this.string.charAt(this.i) != this.open) {return this.string.charAt(this.i++)}
 4806:     var j = ++this.i; var pcount = 1; var c = '';
 4807:     while (this.i < this.string.length) {
 4808:       c = this.string.charAt(this.i++);
 4809:       if (c == this.cmd) {this.i++}
 4810:       else if (c == this.open) {pcount++}
 4811:       else if (c == this.close) {
 4812:         if (pcount == 0) {this.Error("Extra close brace"); return null}
 4813:         if (--pcount == 0) {return this.string.slice(j,this.i-1)}
 4814:       }
 4815:     }
 4816:     this.Error("Missing close brace");
 4817:     return null;
 4818:   },
 4819: 
 4820:   /*
 4821:    *  Get an argument and process it into an mList
 4822:    */
 4823:   ProcessArg: function (name) {
 4824:     var arg = this.GetArgument(name); if (this.error) {return null}
 4825:     return this.Process(arg);
 4826:   },
 4827:   
 4828:   /*
 4829:    *  Get and process an argument for a super- or subscript.
 4830:    *  (read extra args for \frac, \sqrt, \mathrm, etc.)
 4831:    *  This handles these macros as special cases, so is really
 4832:    *  rather a hack.  A more general method for indicating
 4833:    *  how to handle macros in scripts needs to be developed.
 4834:    */
 4835:   ProcessScriptArg: function (name) {
 4836:     var arg = this.GetArgument(name); if (this.error) {return null}
 4837:     if (arg.charAt(0) == this.cmd) {
 4838:       var csname = arg.substr(1);
 4839:       if (csname == "frac") {
 4840:         arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
 4841:         arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
 4842:       } else if (csname == "sqrt") {
 4843:         arg += '['+this.GetBrackets(csname)+']'; if (this.error) {return null}
 4844:         arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
 4845:       } else if (csname.match(this.scriptargs)) {
 4846:         arg += '{'+this.GetArgument(csname)+'}'; if (this.error) {return null}
 4847:       }
 4848:     }
 4849:     return this.Process(arg);
 4850:   },
 4851: 
 4852:   /*
 4853:    *  Get the name of a delimiter (check it in the delimiter list).
 4854:    */
 4855:   GetDelimiter: function (name) {
 4856:     while (this.nextIsSpace()) {this.i++}
 4857:     var c = this.string.charAt(this.i);
 4858:     if (this.i < this.string.length) {
 4859:       this.i++;
 4860:       if (c == this.cmd) {c = '\\'+this.GetCommand(name); if (this.error) return null}
 4861:       if (this.delimiter[c] != null) {return this.delimiter[c]}
 4862:     }
 4863:     this.Error("Missing or unrecognized delimiter for "+name);
 4864:     return null;
 4865:   },
 4866:   
 4867:   /*
 4868:    *  Get a dimension (including its units).
 4869:    *  Convert the dimen to em's, except for mu's, which must be
 4870:    *  converted when typeset.
 4871:    */
 4872:   GetDimen: function (name,nomu) {
 4873:     var rest; var advance = 0;
 4874:     if (this.nextIsSpace()) {this.i++}
 4875:     if (this.string.charAt(this.i) == '{') {
 4876:       rest = this.GetArgument(name);
 4877:     } else {
 4878:       rest = this.string.slice(this.i);
 4879:       advance = 1;
 4880:     }
 4881:     return this.ParseDimen(rest,name,advance,nomu);
 4882:   },
 4883:   
 4884:   ParseDimen: function (dimen,name,advance,nomu) {
 4885:     var match = dimen.match(/^\s*([-+]?(\.\d+|\d+(\.\d*)?))(pt|em|ex|mu|px)/);
 4886:     if (!match) {this.Error("Missing dimension or its units for "+name); return null}
 4887:     if (advance) {
 4888:       this.i += match[0].length;
 4889:       if (this.nextIsSpace()) {this.i++}
 4890:     }
 4891:     var d = match[1]-0;
 4892:     if (match[4] == 'px') {d /= jsMath.em}
 4893:     else if (match[4] == 'pt') {d /= 10}
 4894:     else if (match[4] == 'ex') {d *= jsMath.TeX.x_height}
 4895:     else if (match[4] == 'mu') {if (nomu) {d = d/18} else {d = [d,'mu']}}
 4896:     return d;
 4897:   },
 4898: 
 4899:   /*
 4900:    *  Get the next non-space character
 4901:    */
 4902:   GetNext: function () {
 4903:     while (this.nextIsSpace()) {this.i++}
 4904:     return this.string.charAt(this.i);
 4905:   },
 4906:   
 4907:   /*
 4908:    *  Get an optional LaTeX argument in brackets
 4909:    */
 4910:   GetBrackets: function (name) {
 4911:     var c = this.GetNext(); if (c != '[') return '';
 4912:     var start = ++this.i; var pcount = 0;
 4913:     while (this.i < this.string.length) {
 4914:       var c = this.string.charAt(this.i++);
 4915:       if (c == '{') {pcount++}
 4916:       else if (c == '}') {
 4917:         if (pcount == 0)
 4918:           {this.Error("Extra close brace while looking for ']'"); return null}
 4919:         pcount --;
 4920:       } else if (c == this.cmd) {
 4921:         this.i++;
 4922:       } else if (c == ']') {
 4923:         if (pcount == 0) {return this.string.slice(start,this.i-1)}
 4924:       }
 4925:     }
 4926:     this.Error("Couldn't find closing ']' for argument to "+this.cmd+name);
 4927:     return null;
 4928:   },
 4929:   
 4930:   /*
 4931:    *  Get everything up to the given control sequence name (token)
 4932:    */
 4933:   GetUpto: function (name,token) {
 4934:     while (this.nextIsSpace()) {this.i++}
 4935:     var start = this.i; var pcount = 0;
 4936:     while (this.i < this.string.length) {
 4937:       var c = this.string.charAt(this.i++);
 4938:       if (c == '{') {pcount++}
 4939:       else if (c == '}') {
 4940:         if (pcount == 0)
 4941:           {this.Error("Extra close brace while looking for "+this.cmd+token); return null}
 4942:         pcount --;
 4943:       } else if (c == this.cmd) {
 4944:         // really need separate counter for begin/end
 4945:         // and it should really be a stack (new pcount for each begin)
 4946:         if (this.string.slice(this.i,this.i+5) == "begin") {pcount++; this.i+=4}
 4947:         else if (this.string.slice(this.i,this.i+3) == "end") {
 4948:           if (pcount > 0) {pcount--; this.i += 2}
 4949:         }
 4950:         if (pcount == 0)  {
 4951:           if (this.string.slice(this.i,this.i+token.length) == token) {
 4952:             c = this.string.charAt(this.i+token.length);
 4953:             if (c.match(/[^a-z]/i) || !token.match(/[a-z]/i)) {
 4954:               var arg = this.string.slice(start,this.i-1);
 4955:               this.i += token.length;
 4956:               return arg;
 4957:             }
 4958:           }
 4959:         }
 4960:         this.i++;
 4961:       }
 4962:     }
 4963:     this.Error("Couldn't find "+this.cmd+token+" for "+name);
 4964:     return null;
 4965:   },
 4966: 
 4967:   /*
 4968:    *  Get a parameter delimited by a control sequence, and
 4969:    *  process it to get its mlist
 4970:    */
 4971:   ProcessUpto: function (name,token) {
 4972:     var arg = this.GetUpto(name,token); if (this.error) return null;
 4973:     return this.Process(arg);
 4974:   },
 4975: 
 4976:   /*
 4977:    *  Get everything up to \end{env}
 4978:    */
 4979:   GetEnd: function (env) {
 4980:     var body = ''; var name = '';
 4981:     while (name != env) {
 4982:       body += this.GetUpto('begin{'+env+'}','end'); if (this.error) return null;
 4983:       name = this.GetArgument(this.cmd+'end'); if (this.error) return null;
 4984:     }
 4985:     return body;
 4986:   },
 4987:   
 4988: 
 4989:   /***************************************************************************/
 4990: 
 4991: 
 4992:   /*
 4993:    *  Ignore spaces
 4994:    */
 4995:   Space: function () {},
 4996: 
 4997:   /*
 4998:    *  Collect together any primes and convert them to a superscript
 4999:    */
 5000:   Prime: function (c) {
 5001:     var base = this.mlist.Last();
 5002:     if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))
 5003:        {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
 5004:     if (base.sup) {this.Error("Prime causes double exponent: use braces to clarify"); return}
 5005:     var sup = '';
 5006:     while (c == "'") {sup += this.cmd+'prime'; c = this.GetNext(); if (c == "'") {this.i++}}
 5007:     base.sup = this.Process(sup);
 5008:     base.sup.isPrime = 1;
 5009:   },
 5010: 
 5011:   /*
 5012:    *  Raise or lower its parameter by a given amount
 5013:    *  @@@ Note that this is different from TeX, which requires an \hbox @@@
 5014:    *  ### make this work with mu's ###
 5015:    */
 5016:   RaiseLower: function (name) {
 5017:     var h = this.GetDimen(this.cmd+name,1); if (this.error) return;
 5018:     var box = this.ProcessScriptArg(this.cmd+name); if (this.error) return;
 5019:     if (name == 'lower') {h = -h}
 5020:     this.mlist.Add(new jsMath.mItem('raise',{nuc: box, raise: h}));
 5021:   },
 5022:   
 5023:   /*
 5024:    *  Shift an expression to the right or left
 5025:    *  @@@ Note that this is different from TeX, which requires a \vbox @@@
 5026:    *  ### make this work with mu's ###
 5027:    */
 5028:   MoveLeftRight: function (name) {
 5029:     var x = this.GetDimen(this.cmd+name,1); if (this.error) return;
 5030:     var box = this.ProcessArg(this.cmd+name); if (this.error) return;
 5031:     if (name == 'moveleft') {x = -x}
 5032:     this.mlist.Add(jsMath.mItem.Space(x));
 5033:     this.mlist.Add(jsMath.mItem.Atom('ord',box));
 5034:     this.mlist.Add(jsMath.mItem.Space(-x));
 5035:   },
 5036: 
 5037:   /*
 5038:    *  Load an extension if it has not already been loaded
 5039:    */
 5040:   Require: function (name) {
 5041:     var file = this.GetArgument(this.cmd+name); if (this.error) return;
 5042:     file = jsMath.Extension.URL(file);
 5043:     if (jsMath.Setup.loaded[file]) return;
 5044:     this.Extension(null,[file]);
 5045:   },
 5046:   
 5047:   /*
 5048:    *  Load an extension file and restart processing the math
 5049:    */
 5050:   Extension: function (name,data) {
 5051:     jsMath.Translate.restart = 1;
 5052:     if (name != null) {delete jsMath.Parser.prototype[data[1]||'macros'][name]}
 5053:     jsMath.Extension.Require(data[0],jsMath.Translate.asynchronous);
 5054:     throw "restart";
 5055:   },
 5056:   
 5057:   /*
 5058:    *  Implements \frac{num}{den}
 5059:    */
 5060:   Frac: function (name) {
 5061:     var num = this.ProcessArg(this.cmd+name); if (this.error) return;
 5062:     var den = this.ProcessArg(this.cmd+name); if (this.error) return;
 5063:     this.mlist.Add(jsMath.mItem.Fraction('over',num,den));
 5064:   },
 5065:   
 5066:   /*
 5067:    *  Implements \sqrt[n]{...}
 5068:    */
 5069:   Sqrt: function (name) {
 5070:     var n = this.GetBrackets(this.cmd+name); if (this.error) return;
 5071:     var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
 5072:     var box = jsMath.mItem.Atom('radical',arg);
 5073:     if (n != '') {box.root = this.Process(n); if (this.error) return}
 5074:     this.mlist.Add(box);
 5075:   },
 5076: 
 5077:   /*
 5078:    *  Implements \root...\of{...}
 5079:    */
 5080:   Root: function (name) {
 5081:     var n = this.ProcessUpto(this.cmd+name,'of'); if (this.error) return;
 5082:     var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
 5083:     var box = jsMath.mItem.Atom('radical',arg);
 5084:     box.root = n; this.mlist.Add(box);
 5085:   },
 5086:   
 5087: 
 5088:   /*
 5089:    *  Implements \buildrel...\over{...}
 5090:    */
 5091:   BuildRel: function (name) {
 5092:     var top = this.ProcessUpto(this.cmd+name,'over'); if (this.error) return;
 5093:     var bot = this.ProcessArg(this.cmd+name); if (this.error) return;
 5094:     var op = jsMath.mItem.Atom('op',bot);
 5095:     op.limits = 1; op.sup = top;
 5096:     this.mlist.Add(op);
 5097:   },
 5098: 
 5099:   /*
 5100:    *  Create a delimiter of the type and size specified in the parameters
 5101:    */
 5102:   MakeBig: function (name,data) {
 5103:     var type = data[0]; var h = data[1] * jsMath.p_height;
 5104:     var delim = this.GetDelimiter(this.cmd+name); if (this.error) return;
 5105:     this.mlist.Add(jsMath.mItem.Atom(type,jsMath.Box.Delimiter(h,delim,'T')));
 5106:   },
 5107:   
 5108:   /*
 5109:    *  Insert the specified character in the given font.
 5110:    *  (Try to load the font if it is not already available.)
 5111:    */
 5112:   Char: function (name) {
 5113:     var font = this.GetArgument(this.cmd+name); if (this.error) return;
 5114:     var n = this.GetArgument(this.cmd+name); if (this.error) return;
 5115:     if (!jsMath.TeX[font]) {
 5116:       jsMath.TeX[font] = [];
 5117:       this.Extension(null,[jsMath.Font.URL(font)]);
 5118:     } else {
 5119:       this.mlist.Add(jsMath.mItem.Typeset(jsMath.Box.TeX(n-0,font,'T',this.mlist.data.size)));
 5120:     }
 5121:   },
 5122:   
 5123:   /*
 5124:    *  Create an array or matrix.
 5125:    */
 5126:   Matrix: function (name,delim) {
 5127:     var data = this.mlist.data;
 5128:     var arg = this.GetArgument(this.cmd+name); if (this.error) return;
 5129:     var parse = new jsMath.Parser(arg+this.cmd+'\\',null,data.size,delim[5] || 'T');
 5130:     parse.matrix = name; parse.row = []; parse.table = []; parse.rspacing = [];
 5131:     parse.Parse(); if (parse.error) {this.Error(parse); return}
 5132:     parse.HandleRow(name,1);  // be sure the last row is recorded
 5133:     var box = jsMath.Box.Layout(data.size,parse.table,delim[2]||null,delim[3]||null,parse.rspacing,delim[4]||null);
 5134:     // Add parentheses, if needed
 5135:     if (delim[0] && delim[1]) {
 5136:       var left  = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[0]],'T');
 5137:       var right = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[1]],'T');
 5138:       box = jsMath.Box.SetList([left,box,right],data.style,data.size);
 5139:     }
 5140:     this.mlist.Add(jsMath.mItem.Atom((delim[0]? 'inner': 'ord'),box));
 5141:   },
 5142:   
 5143:   /*
 5144:    *  When we see an '&', try to add a matrix entry to the row data.
 5145:    *  (Use all the data in the current mList, and then clear it)
 5146:    */
 5147:   HandleEntry: function (name) {
 5148:     if (!this.matrix) 
 5149:       {this.Error(name+" can only appear in a matrix or array"); return}
 5150:     if (this.mlist.data.openI != null) {
 5151:       var open = this.mlist.Get(this.mlist.data.openI);
 5152:       if (open.left) {this.Error("Missing "+this.cmd+"right")}
 5153:         else {this.Error("Missing close brace")}
 5154:     }
 5155:     if (this.mlist.data.overI != null) {this.mlist.Over()}
 5156:     var data = this.mlist.data;
 5157:     this.mlist.Atomize(data.style,data.size);
 5158:     var box = this.mlist.Typeset(data.style,data.size);
 5159:     this.row[this.row.length] = box;
 5160:     this.mlist = new jsMath.mList(null,null,data.size,data.style); 
 5161:   },
 5162:   
 5163:   /*
 5164:    *  When we see a \cr or \\, try to add a row to the table
 5165:    */
 5166:   HandleRow: function (name,last) {
 5167:     var dimen;
 5168:     if (!this.matrix) {this.Error(this.cmd+name+" can only appear in a matrix or array"); return}
 5169:     if (name == "\\") {
 5170:       dimen = this.GetBrackets(this.cmd+name); if (this.error) return;
 5171:       if (dimen) {dimen = this.ParseDimen(dimen,this.cmd+name,0,1)}
 5172:     }
 5173:     this.HandleEntry(name);
 5174:     if (!last || this.row.length > 1 || this.row[0].format != 'null')
 5175:       {this.table[this.table.length] = this.row}
 5176:     if (dimen) {this.rspacing[this.table.length] = dimen}
 5177:     this.row = [];
 5178:   },
 5179:   
 5180:   /*
 5181:    *  Look for \vskip or \vspace in \noalign parameters
 5182:    */
 5183:   HandleNoAlign: function (name) {
 5184:     var arg = this.GetArgument(this.cmd+name); if (this.error) return;
 5185:     var skip = arg.replace(/^.*(vskip|vspace)([^a-z])/i,'$2');
 5186:     if (skip.length == arg.length) return;
 5187:     var d = this.ParseDimen(skip,this.cmd+RegExp.$1,0,1); if (this.error) return;
 5188:     this.rspacing[this.table.length] = (this.rspacing[this.table.length] || 0) + d;
 5189:   },
 5190:   
 5191:   /*
 5192:    *  LaTeX array environment
 5193:    */
 5194:   Array: function (name,delim) {
 5195:     var columns = delim[2]; var cspacing = delim[3];
 5196:     if (!columns) {
 5197:       columns = this.GetArgument(this.cmd+'begin{'+name+'}');
 5198:       if (this.error) return;
 5199:     }
 5200:     columns = columns.replace(/[^clr]/g,'');
 5201:     columns = columns.split('');
 5202:     var data = this.mlist.data; var style = delim[5] || 'T';
 5203:     var arg = this.GetEnd(name); if (this.error) return;
 5204:     var parse = new jsMath.Parser(arg+this.cmd+'\\',null,data.size,style);
 5205:     parse.matrix = name; parse.row = []; parse.table = []; parse.rspacing = [];
 5206:     parse.Parse(); if (parse.error) {this.Error(parse); return}
 5207:     parse.HandleRow(name,1);  // be sure the last row is recorded
 5208:     var box = jsMath.Box.Layout(data.size,parse.table,columns,cspacing,parse.rspacing,delim[4]);
 5209:     // Add parentheses, if needed
 5210:     if (delim[0] && delim[1]) {
 5211:       var left  = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[0]],'T');
 5212:       var right = jsMath.Box.Delimiter(box.h+box.d-jsMath.hd/4,this.delimiter[delim[1]],'T');
 5213:       box = jsMath.Box.SetList([left,box,right],data.style,data.size);
 5214:     }
 5215:     this.mlist.Add(jsMath.mItem.Atom((delim[0]? 'inner': 'ord'),box));
 5216:   },
 5217:   
 5218:   /*
 5219:    *  LaTeX \begin{env}
 5220:    */
 5221:   Begin: function (name) {
 5222:     var env = this.GetArgument(this.cmd+name); if (this.error) return;
 5223:     if (env.match(/[^a-z*]/i)) {this.Error('Invalid environment name "'+env+'"'); return}
 5224:     if (!this.environments[env]) {this.Error('Unknown environment "'+env+'"'); return}
 5225:     var cmd = this.environments[env];
 5226:     if (typeof(cmd) == "string") {cmd = [cmd]}
 5227:     this[cmd[0]](env,cmd.slice(1));
 5228:   },
 5229:   
 5230:   /*
 5231:    *  LaTeX \end{env}
 5232:    */
 5233:   End: function (name) {
 5234:     var env = this.GetArgument(this.cmd+name); if (this.error) return;
 5235:     this.Error(this.cmd+name+'{'+env+'} without matching '+this.cmd+'begin');
 5236:   },
 5237: 
 5238:   /*
 5239:    *  Add a fixed amount of horizontal space
 5240:    */
 5241:   Spacer: function (name,w) {
 5242:     this.mlist.Add(jsMath.mItem.Space(w-0));
 5243:   },
 5244:   
 5245:   /*
 5246:    *  Add horizontal space given by the argument
 5247:    */
 5248:   Hskip: function (name) {
 5249:     var w = this.GetDimen(this.cmd+name); if (this.error) return;
 5250:     this.mlist.Add(jsMath.mItem.Space(w));
 5251:   },
 5252: 
 5253:   /*
 5254:    *  Typeset the argument as plain text rather than math.
 5255:    */
 5256:   HBox: function (name) {
 5257:     var text = this.GetArgument(this.cmd+name); if (this.error) return;
 5258:     var box = jsMath.Box.InternalMath(text,this.mlist.data.size);
 5259:     this.mlist.Add(jsMath.mItem.Typeset(box));
 5260:   },
 5261:   
 5262:   /*
 5263:    *  Insert a rule of a particular width, height and depth
 5264:    *  This replaces \hrule and \vrule
 5265:    *  @@@ not a standard TeX command, and all three parameters must be given @@@
 5266:    */
 5267:   Rule: function (name,style) {
 5268:     var w = this.GetDimen(this.cmd+name,1); if (this.error) return;
 5269:     var h = this.GetDimen(this.cmd+name,1); if (this.error) return;
 5270:     var d = this.GetDimen(this.cmd+name,1); if (this.error) return;
 5271:     h += d; var html;
 5272:     if (h != 0) {h = Math.max(1.05/jsMath.em,h)}
 5273:     if (h == 0 || w == 0 || style == "blank")
 5274:       {html = jsMath.HTML.Blank(w,h)} else {html = jsMath.HTML.Rule(w,h)}
 5275:     if (d) {
 5276:       html = '<span style="vertical-align:'+jsMath.HTML.Em(-d)+'">'
 5277:            +  html + '</span>';
 5278:     }
 5279:     this.mlist.Add(jsMath.mItem.Typeset(new jsMath.Box('html',html,w,h-d,d)));
 5280:   },
 5281:   
 5282:   /*
 5283:    *  Inserts an empty box of a specific height and depth
 5284:    */
 5285:   Strut: function () {
 5286:     var size = this.mlist.data.size;
 5287:     var box = jsMath.Box.Text('','normal','T',size).Styled();
 5288:     box.bh = box.bd = 0; box.h = .8; box.d = .3; box.w = 0;
 5289:     this.mlist.Add(jsMath.mItem.Typeset(box));
 5290:   },
 5291:   
 5292:   /*
 5293:    *  Handles \phantom, \vphantom and \hphantom
 5294:    */
 5295:   Phantom: function (name,data) {
 5296:     var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
 5297:     this.mlist.Add(new jsMath.mItem('phantom',{phantom: arg, v: data[0], h: data[1]}));
 5298:   },
 5299:   
 5300:   /*
 5301:    *  Implements \smash
 5302:    */
 5303:   Smash: function (name,data) {
 5304:     var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
 5305:     this.mlist.Add(new jsMath.mItem('smash',{smash: arg}));
 5306:   },
 5307:   
 5308:   /*
 5309:    *  Puts an accent on the following argument
 5310:    */
 5311:   MathAccent: function (name,accent) {
 5312:     var c = this.ProcessArg(this.cmd+name); if (this.error) return;
 5313:     var atom = jsMath.mItem.Atom('accent',c); atom.accent = accent[0];
 5314:     this.mlist.Add(atom);
 5315:   },
 5316: 
 5317:   /*
 5318:    *  Handles functions and operators like sin, cos, sum, etc.
 5319:    */
 5320:   NamedOp: function (name,data) {
 5321:     var a = (name.match(/[^acegm-su-z]/)) ? 1: 0;
 5322:     var d = (name.match(/[gjpqy]/)) ? .2: 0;
 5323:     if (data[1]) {name = data[1]}
 5324:     var box = jsMath.mItem.TextAtom('op',name,'cmr10',a,d);
 5325:     if (data[0] != null) {box.limits = data[0]}
 5326:     this.mlist.Add(box);
 5327:   },
 5328: 
 5329:   /*
 5330:    *  Implements \limits
 5331:    */
 5332:   Limits: function (name,data) {
 5333:     var atom = this.mlist.Last();
 5334:     if (!atom || atom.type != 'op') 
 5335:       {this.Error(this.cmd+name+" is allowed only on operators"); return}
 5336:     atom.limits = data[0];
 5337:   },
 5338: 
 5339:   /*
 5340:    *  Implements macros like those created by \def.  The named control
 5341:    *  sequence is replaced by the string given as the first data value.
 5342:    *  If there is a second data value, this specifies how many arguments
 5343:    *  the macro uses, and in this case, those arguments are substituted
 5344:    *  for #1, #2, etc. within the replacement string.
 5345:    *  
 5346:    *  See the jsMath.Macro() command below for more details.
 5347:    *  The "newcommand" extension implements \newcommand and \def
 5348:    *  and are loaded automatically if needed.
 5349:    */
 5350:   Macro: function (name,data) {
 5351:     var text = data[0];
 5352:     if (data[1]) {
 5353:       var args = [];
 5354:       for (var i = 0; i < data[1]; i++)
 5355:         {args[args.length] = this.GetArgument(this.cmd+name); if (this.error) return}
 5356:       text = this.SubstituteArgs(args,text);
 5357:     }
 5358:     this.string = this.AddArgs(text,this.string.slice(this.i));
 5359:     this.i = 0;
 5360:   },
 5361:   
 5362:   /*
 5363:    *  Replace macro paramters with their values
 5364:    */
 5365:   SubstituteArgs: function (args,string) {
 5366:     var text = ''; var newstring = ''; var c; var i = 0;
 5367:     while (i < string.length) {
 5368:       c = string.charAt(i++);
 5369:       if (c == this.cmd) {text += c + string.charAt(i++)}
 5370:       else if (c == '#') {
 5371:         c = string.charAt(i++);
 5372:         if (c == "#") {text += c} else {
 5373:           if (!c.match(/[1-9]/) || c > args.length)
 5374:             {this.Error("Illegal macro parameter reference"); return null}
 5375:           newstring = this.AddArgs(this.AddArgs(newstring,text),args[c-1]);
 5376:           text = '';
 5377:         }
 5378:       } else {text += c}
 5379:     }
 5380:     return this.AddArgs(newstring,text);
 5381:   },
 5382:   
 5383:   /*
 5384:    *  Make sure that macros are followed by a space if their names
 5385:    *  could accidentally be continued into the following text.
 5386:    */
 5387:   AddArgs: function (s1,s2) {
 5388:     if (s2.match(/^[a-z]/i) && s1.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)) {s1 += ' '}
 5389:     return s1+s2;
 5390:   },
 5391:   
 5392:   /*
 5393:    *  Replace the control sequence with the given text
 5394:    */
 5395:   Replace: function (name,data) {
 5396:     this.mlist.Add(jsMath.mItem.TextAtom(data[0],data[1],data[2],data[3]));
 5397:   },
 5398:   
 5399:   /*
 5400:    *  Insert space for ~
 5401:    */
 5402:   Tilde: function (name) {
 5403:     this.mlist.Add(jsMath.mItem.TextAtom('ord','&nbsp;','normal'));
 5404:   },
 5405: 
 5406:   /*
 5407:    *  Implements \llap, \rlap, etc.
 5408:    */
 5409:   HandleLap: function (name) {
 5410:     var box = this.ProcessArg(); if (this.error) return;
 5411:     box = this.mlist.Add(new jsMath.mItem('lap',{nuc: box, lap: name}));
 5412:   },
 5413: 
 5414:   /*
 5415:    *  Adds the argument as a specific type of atom (for commands like
 5416:    *  \overline, etc.)
 5417:    */
 5418:   HandleAtom: function (name,data) {
 5419:     var arg = this.ProcessArg(this.cmd+name); if (this.error) return;
 5420:     this.mlist.Add(jsMath.mItem.Atom(data,arg));
 5421:   },
 5422: 
 5423: 
 5424:   /*
 5425:    *  Process the character associated with a specific \mathcharcode
 5426:    */
 5427:   HandleMathCode: function (name,code) {
 5428:     this.HandleTeXchar(code[0],code[1],code[2]);
 5429:   },
 5430:   
 5431:   /*
 5432:    *  Add a specific character from a TeX font (use the current
 5433:    *  font if the type is 7 (variable) or the font is not specified)
 5434:    *  Load the font if it is not already loaded.
 5435:    */
 5436:   HandleTeXchar: function (type,font,code) {
 5437:     if (type == 7 && this.mlist.data.font != null) {font = this.mlist.data.font}
 5438:     font = jsMath.TeX.fam[font];
 5439:     if (!jsMath.TeX[font]) {
 5440:       jsMath.TeX[font] = [];
 5441:       this.Extension(null,[jsMath.Font.URL(font)]);
 5442:     } else {
 5443:       this.mlist.Add(jsMath.mItem.TeXAtom(jsMath.TeX.atom[type],code,font));
 5444:     }
 5445:   },
 5446: 
 5447:   /*
 5448:    *  Add a TeX variable character or number
 5449:    */
 5450:   HandleVariable: function (c) {this.HandleTeXchar(7,1,c.charCodeAt(0))},
 5451:   HandleNumber: function (c) {this.HandleTeXchar(7,0,c.charCodeAt(0))},
 5452: 
 5453:   /*
 5454:    *  For unmapped characters, just add them in as normal
 5455:    *  (non-TeX) characters
 5456:    */
 5457:   HandleOther: function (c) {
 5458:     this.mlist.Add(jsMath.mItem.TextAtom('ord',c,'normal'));
 5459:   },
 5460:   
 5461:   /*
 5462:    *  Ignore comments in TeX data
 5463:    *  ### Some browsers remove the newlines, so this might cause
 5464:    *      extra stuff to be ignored; look into this ###
 5465:    */
 5466:   HandleComment: function () {
 5467:     var c;
 5468:     while (this.i < this.string.length) {
 5469:       c = this.string.charAt(this.i++);
 5470:       if (c == "\r" || c == "\n") return;
 5471:     }
 5472:   },
 5473: 
 5474:   /*
 5475:    *  Add a style change (e.g., \displaystyle, etc)
 5476:    */
 5477:   HandleStyle: function (name,style) {
 5478:     this.mlist.data.style = style[0];
 5479:     this.mlist.Add(new jsMath.mItem('style',{style: style[0]}));
 5480:   },
 5481:   
 5482:   /*
 5483:    *  Implements \small, \large, etc.
 5484:    */
 5485:   HandleSize: function (name,size) {
 5486:     this.mlist.data.size = size[0];
 5487:     this.mlist.Add(new jsMath.mItem('size',{size: size[0]}));
 5488:   },
 5489: 
 5490:   /*
 5491:    *  Set the current font (e.g., \rm, etc)
 5492:    */
 5493:   HandleFont: function (name,font) {
 5494:     this.mlist.data.font = font[0];
 5495:   },
 5496: 
 5497:   /*
 5498:    *  Look for and process a control sequence
 5499:    */
 5500:   HandleCS: function () {
 5501:     var cmd = this.GetCommand(); if (this.error) return;
 5502:     if (this.macros[cmd]) {
 5503:       var macro = this.macros[cmd];
 5504:       if (typeof(macro) == "string") {macro = [macro]}
 5505:       this[macro[0]](cmd,macro.slice(1)); return;
 5506:     }
 5507:     if (this.mathchardef[cmd]) {
 5508:       this.HandleMathCode(cmd,this.mathchardef[cmd]);
 5509:       return;
 5510:     }
 5511:     if (this.delimiter[this.cmd+cmd]) {
 5512:       this.HandleMathCode(cmd,this.delimiter[this.cmd+cmd].slice(0,3))
 5513:       return;
 5514:     }
 5515:     this.Error("Unknown control sequence '"+this.cmd+cmd+"'");
 5516:   },
 5517: 
 5518:   /*
 5519:    *  Process open and close braces
 5520:    */
 5521:   HandleOpen: function () {this.mlist.Open()},
 5522:   HandleClose: function () {
 5523:     if (this.mlist.data.openI == null) {this.Error("Extra close brace"); return}
 5524:     var open = this.mlist.Get(this.mlist.data.openI);
 5525:     if (!open || open.left == null) {this.mlist.Close()}
 5526:       else {this.Error("Extra close brace or missing "+this.cmd+"right"); return}
 5527:   },
 5528: 
 5529:   /*
 5530:    *  Implements \left
 5531:    */
 5532:   HandleLeft: function (name) {
 5533:     var left = this.GetDelimiter(this.cmd+name); if (this.error) return;
 5534:     this.mlist.Open(left);
 5535:   },
 5536: 
 5537:   /*
 5538:    *  Implements \right
 5539:    */
 5540:   HandleRight: function (name) {
 5541:     var right = this.GetDelimiter(this.cmd+name); if (this.error) return;
 5542:     var open = this.mlist.Get(this.mlist.data.openI);
 5543:     if (open && open.left != null) {this.mlist.Close(right)}
 5544:       else {this.Error("Extra open brace or missing "+this.cmd+"left");}
 5545:   },
 5546: 
 5547:   /*
 5548:    *  Implements generalized fractions (\over, \above, etc.)
 5549:    */
 5550:   HandleOver: function (name,data) {
 5551:     if (this.mlist.data.overI != null) 
 5552:       {this.Error('Ambiguous use of '+this.cmd+name); return}
 5553:     this.mlist.data.overI = this.mlist.Length();
 5554:     this.mlist.data.overF = {name: name};
 5555:     if (data.length > 0) {
 5556:       this.mlist.data.overF.left  = this.delimiter[data[0]];
 5557:       this.mlist.data.overF.right = this.delimiter[data[1]];
 5558:     } else if (name.match(/withdelims$/)) {
 5559:       this.mlist.data.overF.left  = this.GetDelimiter(this.cmd+name); if (this.error) return;
 5560:       this.mlist.data.overF.right = this.GetDelimiter(this.cmd+name); if (this.error) return;
 5561:     } else {
 5562:       this.mlist.data.overF.left  = null;
 5563:       this.mlist.data.overF.right = null;
 5564:     }
 5565:     if (name.match(/^above/)) {
 5566:       this.mlist.data.overF.thickness = this.GetDimen(this.cmd+name,1);
 5567:       if (this.error) return;
 5568:     } else {
 5569:       this.mlist.data.overF.thickness = null; 
 5570:     }
 5571:   },
 5572: 
 5573:   /*
 5574:    *  Add a superscript to the preceeding atom
 5575:    */
 5576:   HandleSuperscript: function () {
 5577:     var base = this.mlist.Last();
 5578:     if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))
 5579:        {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
 5580:     if (base.sup) {
 5581:       if (base.sup.isPrime) {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
 5582:         else {this.Error("Double exponent: use braces to clarify"); return}
 5583:     }
 5584:     base.sup = this.ProcessScriptArg('superscript'); if (this.error) return;
 5585:   },
 5586: 
 5587:   /*
 5588:    *  Add a subscript to the preceeding atom
 5589:    */
 5590:   HandleSubscript: function () {
 5591:     var base = this.mlist.Last();
 5592:     if (base == null || (!base.atom && base.type != 'box' && base.type != 'frac'))
 5593:        {base = this.mlist.Add(jsMath.mItem.Atom('ord',{type:null}))}
 5594:     if (base.sub) {this.Error("Double subscripts: use braces to clarify"); return}
 5595:     base.sub = this.ProcessScriptArg('subscript'); if (this.error) return;
 5596:   },
 5597: 
 5598:   /*
 5599:    *  Parse a TeX math string, handling macros, etc.
 5600:    */
 5601:   Parse: function () {
 5602:     var c;
 5603:     while (this.i < this.string.length) {
 5604:       c = this.string.charAt(this.i++);
 5605:       if (this.mathchar[c]) {this.HandleMathCode(c,this.mathchar[c])}
 5606:       else if (this.special[c]) {this[this.special[c]](c)}
 5607:       else if (this.letter.test(c)) {this.HandleVariable(c)}
 5608:       else if (this.number.test(c)) {this.HandleNumber(c)}
 5609:       else {this.HandleOther(c)}
 5610:     }
 5611:     if (this.mlist.data.openI != null) {
 5612:       var open = this.mlist.Get(this.mlist.data.openI);
 5613:       if (open.left) {this.Error("Missing "+this.cmd+"right")}
 5614:         else {this.Error("Missing close brace")}
 5615:     }
 5616:     if (this.mlist.data.overI != null) {this.mlist.Over()}
 5617:   },
 5618: 
 5619:   /*
 5620:    *  Perform the processing of Appendix G
 5621:    */
 5622:   Atomize: function () {
 5623:     var data = this.mlist.init;
 5624:     if (!this.error) this.mlist.Atomize(data.style,data.size)
 5625:   },
 5626: 
 5627:   /*
 5628:    *  Produce the final HTML.
 5629:    *  
 5630:    *  We have to wrap the HTML it appropriate <SPAN> tags to hide its
 5631:    *  actual dimensions when these don't match the TeX dimensions of the
 5632:    *  results.  We also include an image to force the results to take up
 5633:    *  the right amount of space.  The results may need to be vertically
 5634:    *  adjusted to make the baseline appear in the correct place.
 5635:    */
 5636:   Typeset: function () {
 5637:     var data = this.mlist.init;
 5638:     var box = this.typeset = this.mlist.Typeset(data.style,data.size);
 5639:     if (this.error) {return '<span class="error">'+this.error+'</span>'}
 5640:     if (box.format == 'null') {return ''};
 5641: 
 5642:     box.Styled().Remeasured(); var isSmall = 0; var isBig = 0;
 5643:     if (box.bh > box.h && box.bh > jsMath.h+.001) {isSmall = 1}
 5644:     if (box.bd > box.d && box.bd > jsMath.d+.001) {isSmall = 1}
 5645:     if (box.h > jsMath.h || box.d > jsMath.d) {isBig = 1}
 5646: 
 5647:     var html = box.html;
 5648:     if (isSmall) {// hide the extra size
 5649:       if (jsMath.Browser.allowAbsolute) {
 5650:         var y = 0;
 5651:         if (box.bh > jsMath.h+.001) {y = jsMath.h - box.bh}
 5652:         html = jsMath.HTML.Absolute(html,box.w,jsMath.h,0,y,jsMath.h);
 5653:       } else if (jsMath.Browser.valignBug) {
 5654:         // remove line height
 5655:         html = '<span style="line-height:'+jsMath.HTML.Em(jsMath.d)+';">'
 5656:              +    html + '</span>';
 5657:       } else {
 5658:         // remove line height and try to hide the depth
 5659:         var dy = jsMath.HTML.Em(Math.max(0,box.bd-jsMath.hd)/3);
 5660:         html = '<span style="line-height:'+jsMath.HTML.Em(jsMath.d)+';'
 5661:                + ' position:relative; top:'+dy+'; vertical-align:'+dy
 5662:                + '">' + html + '</span>';
 5663:       }
 5664:       isBig = 1;
 5665:     }
 5666:     if (isBig) {
 5667:       // add height and depth to the line
 5668:       //   (force a little extra to separate lines if needed)
 5669:       html += jsMath.HTML.Blank(0,box.h+.05,box.d+.05);
 5670:     }
 5671:     return '<nobr><span class="scale">'+html+'</span></nobr>';
 5672:   }
 5673: 
 5674: });
 5675: 
 5676: /*
 5677:  *  Make these characters special (and call the given routines)
 5678:  */
 5679: jsMath.Parser.prototype.AddSpecial({
 5680:   cmd:   'HandleCS',
 5681:   open:  'HandleOpen',
 5682:   close: 'HandleClose'
 5683: });
 5684: 
 5685: 
 5686: /*
 5687:  *  The web-page author can call jsMath.Macro to create additional
 5688:  *  TeX macros for use within his or her mathematics.  See the
 5689:  *  author's documentation for more details.
 5690:  */
 5691: 
 5692: jsMath.Add(jsMath,{
 5693:   Macro: function (name) {
 5694:     var macro = jsMath.Parser.prototype.macros;
 5695:     macro[name] = ['Macro'];
 5696:     for (var i = 1; i < arguments.length; i++) 
 5697:       {macro[name][macro[name].length] = arguments[i]}
 5698:   }
 5699: });
 5700: 
 5701: /*
 5702:  *  Use these commands to create macros that load
 5703:  *  JavaScript files and reprocess the mathematics when
 5704:  *  the file is loaded.  This lets you to have macros or
 5705:  *  LaTeX environments that autoload their own definitions
 5706:  *  only when they are needed, saving initial download time
 5707:  *  on pages where they are not used.  See the author's
 5708:  *  documentation for more details.
 5709:  *
 5710:  */
 5711: 
 5712: jsMath.Extension = {
 5713: 
 5714:   safeRequire: 1,   // disables access to files outside of jsMath/extensions
 5715:   
 5716:   Macro: function (name,file) {
 5717:     var macro = jsMath.Parser.prototype.macros;
 5718:     if (file == null) {file = name}
 5719:     macro[name] = ['Extension',file];
 5720:   },
 5721: 
 5722:   LaTeX: function (env,file) {
 5723:     var latex = jsMath.Parser.prototype.environments;
 5724:     latex[env] = ['Extension',file,'environments'];
 5725:   },
 5726: 
 5727:   Font: function (name,font) {
 5728:     if (font == null) {font = name + "10"}
 5729:     var macro = jsMath.Parser.prototype.macros;
 5730:     macro[name] = ['Extension',jsMath.Font.URL(font)];
 5731:   },
 5732:   
 5733:   MathChar: function (font,defs) {
 5734:     var fam = jsMath.TeX.famName[font];
 5735:     if (fam == null) {
 5736:       fam = jsMath.TeX.fam.length;
 5737:       jsMath.TeX.fam[fam] = font;
 5738:       jsMath.TeX.famName[font] = fam;
 5739:     }
 5740:     var mathchardef = jsMath.Parser.prototype.mathchardef;
 5741:     for (var c in defs) {mathchardef[c] = [defs[c][0],fam,defs[c][1]]}
 5742:   },
 5743: 
 5744:   Require: function (file,show) {
 5745:     if (this.safeRequire && (file.match(/\.\.\/|[^-a-z0-9.\/:_+=%~]/i) ||
 5746:          (file.match(/:/) && file.substr(0,jsMath.root.length) != jsMath.root))) {
 5747:       jsMath.Setup.loaded[file] = 1;
 5748:       return;
 5749:     }
 5750:     jsMath.Setup.Script(this.URL(file),show);
 5751:   },
 5752:   
 5753:   URL: function (file) {
 5754:     file = file.replace(/^\s+|\s+$/g,'');
 5755:     if (!file.match(/^([a-z]+:|\/|fonts|extensions\/)/i)) {file = 'extensions/'+file}
 5756:     if (!file.match(/\.js$/)) {file += '.js'}
 5757:     return file;
 5758:   }
 5759: }
 5760: 
 5761: 
 5762: /***************************************************************************/
 5763: 
 5764: /*
 5765:  *  These routines look through the web page for math elements to process.
 5766:  *  There are two main entry points you can call:
 5767:  *  
 5768:  *      <script> jsMath.Process() </script>
 5769:  *  or
 5770:  *      <script> jsMath.ProcessBeforeShowing() </script>
 5771:  *
 5772:  *  The first will process the page asynchronously (so the user can start
 5773:  *  reading the top of the file while jsMath is still processing the bottom)
 5774:  *  while the second does not update until all the mathematics is typeset.
 5775:  */
 5776: 
 5777: jsMath.Add(jsMath,{
 5778:   /*
 5779:    *  Call this at the bottom of your HTML page to have the
 5780:    *  mathematics typeset asynchronously.  This lets the user
 5781:    *  start reading the mathematics while the rest of the page
 5782:    *  is being processed.
 5783:    */
 5784:   Process: function (obj) {
 5785:     jsMath.Setup.Body();
 5786:     jsMath.Script.Push(jsMath.Translate,'Asynchronous',obj);
 5787:   },
 5788:   
 5789:   /*
 5790:    *  Call this at the bottom of your HTML page to have the
 5791:    *  mathematics typeset before the page is displayed.
 5792:    *  This can take a long time, so the user could cancel the
 5793:    *  page before it is complete; use it with caution, and only
 5794:    *  when there is a relatively small amount of math on the page.
 5795:    */
 5796:   ProcessBeforeShowing: function (obj) {
 5797:     jsMath.Setup.Body();
 5798:     var method = (jsMath.Controls.cookie.asynch ? "Asynchronous": "Synchronous");
 5799:     jsMath.Script.Push(jsMath.Translate,method,obj);
 5800:   }
 5801:   
 5802: });
 5803: 
 5804: jsMath.Translate = {
 5805: 
 5806:   element: [],  // the list of math elements on the page
 5807:   cancel: 0,    // set to 1 to cancel asynchronous processing
 5808:   
 5809:   /*
 5810:    *  Parse a TeX string in Text or Display mode and return
 5811:    *  the HTML for it (taking it from the cache, if available)
 5812:    */
 5813:   Parse: function (style,s,noCache) {
 5814:     var cache = jsMath.Global.cache[style];
 5815:     if (!cache[jsMath.em]) {cache[jsMath.em] = {}}
 5816:     var HTML = cache[jsMath.em][s];
 5817:     if (!HTML || noCache) {
 5818:       var parse = jsMath.Parse(s,null,null,style);
 5819:       parse.Atomize(); HTML = parse.Typeset();
 5820:       if (!noCache) {cache[jsMath.em][s] = HTML}
 5821:     }
 5822:     return HTML;
 5823:   },
 5824: 
 5825:   TextMode:    function (s,noCache) {this.Parse('T',s,noCache)},
 5826:   DisplayMode: function (s,noCache) {this.Parse('D',s,noCache)},
 5827:   
 5828:   /*
 5829:    *  Return the text of a given DOM element
 5830:    */
 5831:   GetElementText: function (element) {
 5832:     var text = this.recursiveElementText(element);
 5833:     element.alt = text;
 5834:     if (text.search('&') >= 0) {
 5835:       text = text.replace(/&lt;/g,'<');
 5836:       text = text.replace(/&gt;/g,'>');
 5837:       text = text.replace(/&quot;/g,'"');
 5838:       text = text.replace(/&amp;/g,'&');
 5839:     }
 5840:     return text;
 5841:   },
 5842:   recursiveElementText: function (element) {
 5843:     if (element.nodeValue != null) {return element.nodeValue}
 5844:     if (element.childNodes.length == 0) {return " "}
 5845:     var text = '';
 5846:     for (var i = 0; i < element.childNodes.length; i++) 
 5847:       {text += this.recursiveElementText(element.childNodes[i])}
 5848:     return text;
 5849:   },
 5850:   
 5851:   /*
 5852:    *  Move hidden to the location of the math element to be
 5853:    *  processed and reinitialize sizes for that location.
 5854:    */
 5855:   ResetHidden: function (element) {
 5856:     element.innerHTML =
 5857:       '<span style="visibility: hidden; position:absolute; top:0px;left:0px;"></span>'
 5858:         + jsMath.Browser.operaHiddenFix; // needed by Opera in tables
 5859:     element.className = '';
 5860:     jsMath.hidden = element.firstChild;
 5861:     if (!jsMath.BBoxFor("x").w) {jsMath.hidden = jsMath.hiddenTop}
 5862:     jsMath.ReInit();
 5863:   },
 5864: 
 5865:   
 5866:   /*
 5867:    *  Typeset the contents of an element in \textstyle
 5868:    */
 5869:   ConvertText: function (element,noCache) {
 5870:     var text = this.GetElementText(element);
 5871:     this.ResetHidden(element);
 5872:     if (text.match(/^\s*\\nocache([^a-zA-Z])/))
 5873:       {noCache = true; text = text.replace(/\s*\\nocache/,'')}
 5874:     text = this.Parse('T',text,noCache);
 5875:     element.className = 'typeset';
 5876:     element.innerHTML = text;
 5877:   },
 5878:   
 5879:   /*
 5880:    *  Typeset the contents of an element in \displaystyle
 5881:    */
 5882:   ConvertDisplay: function (element,noCache) {
 5883:     var text = this.GetElementText(element);
 5884:     this.ResetHidden(element);
 5885:     if (text.match(/^\s*\\nocache([^a-zA-Z])/))
 5886:       {noCache = true; text = text.replace(/\s*\\nocache/,'')}
 5887:     text = this.Parse('D',text,noCache);
 5888:     element.className = 'typeset';
 5889:     element.innerHTML = text;
 5890:   },
 5891:   
 5892:   /*
 5893:    *  Process a math element
 5894:    */
 5895:   ProcessElement: function (element) {
 5896:     this.restart = 0;
 5897:     var noCache = (element.className.toLowerCase().match(/(^| )nocache( |$)/) != null);
 5898:     try {
 5899:       if (element.tagName.toLowerCase() == 'div') {
 5900:         this.ConvertDisplay(element,noCache);
 5901:         element.onclick = jsMath.Click.CheckClick;
 5902:         element.ondblclick = jsMath.Click.CheckDblClick;
 5903:       } else if (element.tagName.toLowerCase() == 'span') {
 5904:         this.ConvertText(element,noCache);
 5905:         element.onclick = jsMath.Click.CheckClick;
 5906:         element.ondblclick = jsMath.Click.CheckDblClick;
 5907:       }
 5908:     } catch (err) {
 5909:       if (element.alt) {
 5910:         var tex = element.alt;
 5911:         tex = tex.replace(/&/g,'&amp;');
 5912:         tex = tex.replace(/</g,'&lt;');
 5913:         tex = tex.replace(/>/g,'&gt;');
 5914:         element.innerHTML = tex;
 5915:         element.className = 'math';
 5916:         if (noCache) {element.className += ' nocache'}
 5917:       }
 5918:       jsMath.hidden = jsMath.hiddenTop;
 5919:     }
 5920:   },
 5921: 
 5922:   /*
 5923:    *  Asynchronously process all the math elements starting with
 5924:    *  the k-th one
 5925:    */
 5926:   ProcessElements: function (k) {
 5927:     jsMath.Script.blocking = 1;
 5928:     if (k >= this.element.length || this.cancel) {
 5929:       this.ProcessComplete();
 5930:       if (this.cancel) {
 5931:         jsMath.Message.Set("Process Math: Canceled");
 5932:         jsMath.Message.Clear()
 5933:       }
 5934:       jsMath.Script.blocking = 0;
 5935:       jsMath.Script.Process();
 5936:     } else {
 5937:       this.ProcessElement(this.element[k]);
 5938:       if (this.restart) {
 5939:         jsMath.Script.Push(this,'ProcessElements',k);
 5940:         jsMath.Script.blocking = 0;
 5941:         setTimeout('jsMath.Script.Process()',jsMath.Browser.delay);
 5942:       } else {
 5943:         k++; var p = Math.floor(100 * k / this.element.length);
 5944:         jsMath.Message.Set('Processing Math: '+p+'%');
 5945:         setTimeout('jsMath.Translate.ProcessElements('+k+')',jsMath.Browser.delay);
 5946:       }
 5947:     }
 5948:   },
 5949: 
 5950:   /*
 5951:    *  Start the asynchronous processing of mathematics
 5952:    */
 5953:   Asynchronous: function (obj) {
 5954:     if (!jsMath.initialized) {jsMath.Init()}
 5955:     this.element = this.GetMathElements(obj);
 5956:     this.cancel = 0; this.asynchronous = 1;
 5957:     jsMath.Script.blocking = 1;
 5958:     jsMath.Message.Set('Processing Math: 0%',1);
 5959:     setTimeout('jsMath.Translate.ProcessElements(0)',jsMath.Browser.delay);
 5960:   },
 5961:   
 5962:   /*
 5963:    *  Do synchronous processing of mathematics
 5964:    */
 5965:   Synchronous: function (obj,i) {
 5966:     if (i == null) {
 5967:       if (!jsMath.initialized) {jsMath.Init()}
 5968:       this.element = this.GetMathElements(obj);
 5969:       i = 0;
 5970:     }
 5971:     this.asynchronous = 0;
 5972:     while (i < this.element.length) {
 5973:       this.ProcessElement(this.element[i]);
 5974:       if (this.restart) {
 5975:         jsMath.Synchronize('jsMath.Translate.Synchronous(null,'+i+')');
 5976:         jsMath.Script.Process();
 5977:         return;
 5978:       }
 5979:       i++;
 5980:     }
 5981:     this.ProcessComplete(1);
 5982:   },
 5983:   
 5984:   /*
 5985:    *  Look up all the math elements on the page and
 5986:    *  put them in a list sorted from top to bottom of the page
 5987:    */
 5988:   GetMathElements: function (obj) {
 5989:     var element = [];
 5990:     if (!obj) {obj = jsMath.document}
 5991:     if (typeof(obj) == 'string') {obj = jsMath.document.getElementById(obj)}
 5992:     if (!obj.getElementsByTagName) return null;
 5993:     var math = obj.getElementsByTagName('div');
 5994:     for (var k = 0; k < math.length; k++) {
 5995:       if (math[k].className.match(/(^| )math( |$)/)) {
 5996:         if (jsMath.Browser.renameOK && obj.getElementsByName) 
 5997:                {math[k].setAttribute('name','_jsMath_')}
 5998:           else {element[element.length] = math[k]}
 5999:       }
 6000:     }
 6001:     math = obj.getElementsByTagName('span');
 6002:     for (var k = 0; k < math.length; k++) {
 6003:       if (math[k].className.match(/(^| )math( |$)/)) {
 6004:         if (jsMath.Browser.renameOK && obj.getElementsByName) 
 6005:                {math[k].setAttribute('name','_jsMath_')}
 6006:           else {element[element.length] = math[k]}
 6007:       }
 6008:     }
 6009:     // this gets the SPAN and DIV elements interleaved in order
 6010:     if (jsMath.Browser.renameOK && obj.getElementsByName) {
 6011:       element = obj.getElementsByName('_jsMath_');
 6012:     } else if (jsMath.hidden.sourceIndex) {
 6013:       element.sort(function (a,b) {return a.sourceIndex - b.sourceIndex});
 6014:     }
 6015:     return element;
 6016:   },
 6017: 
 6018:   /*
 6019:    *  Remove the window message about processing math
 6020:    *  and clean up any marked <SPAN> or <DIV> tags
 6021:    */
 6022:   ProcessComplete: function (noMessage) {
 6023:     if (jsMath.Browser.renameOK) {
 6024:       var element = jsMath.document.getElementsByName('_jsMath_');
 6025:       for (var i = element.length-1; i >= 0; i--) {
 6026:         element[i].removeAttribute('name');
 6027:       }
 6028:     }
 6029:     jsMath.hidden = jsMath.hiddenTop;
 6030:     this.element = [];
 6031:     if (!noMessage) {
 6032:       jsMath.Message.Set('Processing Math: Done');
 6033:       jsMath.Message.Clear();
 6034:     }
 6035:     jsMath.Message.UnBlank();
 6036:     if (jsMath.Browser.safariImgBug &&
 6037:         (jsMath.Controls.cookie.font == 'symbol' ||
 6038:          jsMath.Controls.cookie.font == 'image')) {
 6039:       //
 6040:       //  For Safari, the images don't always finish
 6041:       //  updating, so nudge the window to cause a
 6042:       //  redraw.  (Hack!)
 6043:       //
 6044:       if (this.timeout) {clearTimeout(this.timeout)}
 6045:       this.timeout = setTimeout("jsMath.window.resizeBy(-1,0); "
 6046:                               + "jsMath.window.resizeBy(1,0); "
 6047:                               + "jsMath.Translate.timeout = null",2000);
 6048:     }
 6049:   },
 6050:   
 6051:   /*
 6052:    *  Cancel procesing elements
 6053:    */
 6054:   Cancel: function () {
 6055:     jsMath.Translate.cancel = 1;
 6056:     if (jsMath.Script.cancelTimer) {jsMath.Script.cancelLoad()}
 6057:   }
 6058:   
 6059: };
 6060: 
 6061: jsMath.Add(jsMath,{
 6062:   //
 6063:   //  Synchronize these with the loading of the tex2math plugin.
 6064:   //
 6065:   ConvertTeX: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertTeX',element)},
 6066:   ConvertTeX2: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertTeX2',element)},
 6067:   ConvertLaTeX: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertLaTeX',element)},
 6068:   ConvertCustom: function (element) {jsMath.Script.Push(jsMath.tex2math,'ConvertCustom',element)},
 6069:   CustomSearch: function (om,cm,od,cd) {jsMath.Script.Push(null,function () {jsMath.tex2math.CustomSearch(om,cm,od,cd)})},
 6070:   tex2math: {
 6071:     ConvertTeX: function () {},
 6072:     ConvertTeX2: function () {},
 6073:     ConvertLaTeX: function () {},
 6074:     ConvertCustom: function () {},
 6075:     CustomSearch: function () {}
 6076:   }
 6077: });
 6078: jsMath.Synchronize = jsMath.Script.Synchronize;
 6079: 
 6080: /***************************************************************************/
 6081: 
 6082: 
 6083: /*
 6084:  *  Initialize things
 6085:  */
 6086: try {
 6087:   if (window.parent != window && window.jsMathAutoload) {
 6088:     window.parent.jsMath = jsMath;
 6089:     jsMath.document = window.parent.document;
 6090:     jsMath.window = window.parent;
 6091:   }
 6092: } catch (err) {}
 6093: 
 6094: jsMath.Global.Register();
 6095: jsMath.Loaded();
 6096: jsMath.Controls.GetCookie();
 6097: jsMath.Setup.Source();
 6098: jsMath.Global.Init();
 6099: jsMath.Script.Init();
 6100: jsMath.Setup.Fonts();
 6101: if (jsMath.document.body) {jsMath.Setup.Body()}
 6102: 
 6103: }}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>