Annotation of loncom/html/adm/jsMath/uncompressed/jsMath.js, revision 1.3

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

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