www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

content-mathml.js (63765B)


      1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 
      4 /*************************************************************
      5  *
      6  *  MathJax/extensions/MathML/content-mathml.js
      7  *
      8  *  This file provides methods to convert Content-MathML to
      9  *  Presentation MathML for processing by MathJax.  The transform is
     10  *  performed in a DOM filter for the MathML input jax, so that the
     11  *  Show Math As menu will still show the Original MathML as Content MathML,
     12  *  but the Presentation MathML can be obtained from the main MathML menu.
     13  *  
     14  *  To load it, include
     15  *  
     16  *      MathML: {
     17  *        extensions: ["content-mathml.js"]
     18  *      }
     19  *  
     20  *  in your configuration.
     21  *
     22  *  A portion of this file is taken from ctop.js which is
     23  *  Copyright (c) David Carlisle 2001, 2002, 2008, 2009, 2013,
     24  *  and is used by permission of David Carlisle, who has agreed to allow us
     25  *  to release it under the Apache2 license (see below).  That portion is
     26  *  indicated via comments.
     27  *  
     28  *  The remainder falls under the copyright that follows.
     29  *  ---------------------------------------------------------------------
     30  *  
     31  *  Copyright (c) 2013-2015 The MathJax Consortium
     32  * 
     33  *  Licensed under the Apache License, Version 2.0 (the "License");
     34  *  you may not use this file except in compliance with the License.
     35  *  You may obtain a copy of the License at
     36  * 
     37  *      http://www.apache.org/licenses/LICENSE-2.0
     38  * 
     39  *  Unless required by applicable law or agreed to in writing, software
     40  *  distributed under the License is distributed on an "AS IS" BASIS,
     41  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     42  *  See the License for the specific language governing permissions and
     43  *  limitations under the License.
     44  */
     45 
     46 
     47 MathJax.Extension["MathML/content-mathml"] = (function(HUB) {
     48   /* 
     49    * Content MathML to Presentation MathML conversion
     50    *
     51    * based on David Carlisle's ctop.js - https://web-xslt.googlecode.com/svn/trunk/ctop/ctop.js
     52    *
     53    */
     54 
     55 
     56   var isMSIE = HUB.Browser.isMSIE;
     57 
     58   if (isMSIE) {
     59     try {document.namespaces.add("m","http://www.w3.org/1998/Math/MathML")} catch (err) {}
     60   }
     61 
     62   var CONFIG = HUB.CombineConfig("MathML.content-mathml",{
     63     // render `a+(-b)` as `a-b`?
     64     collapsePlusMinus: true,
     65 
     66       /* mathvariant to use with corresponding <ci> type attribute */
     67       cistyles: {
     68         vector: 'bold-italic',
     69         matrix: 'bold-upright'
     70       },
     71 
     72       /* Symbol names to translate to characters
     73       */
     74       symbols: {
     75         gamma: '\u03B3'
     76       }
     77 
     78   });
     79 
     80   var CToP = {
     81     version: "2.6.0",
     82     settings: CONFIG,
     83 
     84     /* Transform the given <math> elements from Content MathML to Presentation MathML and replace the original elements
     85     */
     86     transformElements: function(elements) {
     87       for (var i = 0, l = elements.length; i<l; i++ ) {
     88         var mathNode = CToP.transformElement(elements[i]);
     89         elements[i].parentNode.replaceChild(mathNode,elements[i]); 
     90       }
     91     },
     92 
     93     /* Transform a Content MathML element into Presentation MathML, and return the new element
     94     */
     95     transformElement: function(element) {
     96       if (element.nodeName.indexOf(":") >= 0) element = CToP.cloneNode(element,true); // removes namespaces
     97       var mathNode = CToP.cloneNode(element);
     98       for (var j = 0, l = element.childNodes.length; j<l; j++ ) {
     99         CToP.applyTransform(mathNode,element.childNodes[j],0);
    100       }
    101       return mathNode;
    102     },
    103 
    104     getTextContent: function(element) {
    105       return element.text !== undefined ? element.text : element.innerText !== undefined ? element.innerText : element.textContent;
    106     },
    107 
    108     setTextContent: function(element,textContent) {
    109       for (var i = 0, l = element.childNodes.length; i<l; i++) {
    110         if (element.childNodes[i].nodeType === 3) {
    111           element.removeChild(element.childNodes[i]);
    112           i--;
    113           l--;
    114         }
    115       }
    116       element.appendChild(document.createTextNode(textContent));
    117     },
    118 
    119     cloneNode: function(element,deep) {
    120       var clone, i, l;
    121       if (element.nodeType === 1) {
    122         clone = CToP.createElement(element.nodeName);
    123         for (i = 0, l = element.attributes.length; i<l; i++ ) {
    124           clone.setAttribute(element.attributes[i].nodeName,element.attributes[i].nodeValue);
    125         }
    126         if (deep) {
    127           for (i = 0, l = element.childNodes.length; i<l; i++ ) {
    128             var clonedChild = CToP.cloneNode(element.childNodes[i],true);
    129             clone.appendChild(clonedChild);
    130           }
    131         }
    132       } else if (element.nodeType === 3) {
    133         clone = document.createTextNode(element.nodeValue);
    134       }
    135       return clone;
    136     },
    137 
    138     /* Create an element with given name, belonging to the MathML namespace
    139     */
    140     createElement: function(name) {
    141       name = name.replace(/^.*:/,"");  // remove namespace
    142       return (document.createElementNS ?
    143                  document.createElementNS("http://www.w3.org/1998/Math/MathML",name) :
    144                  document.createElement("m:"+name));
    145     },
    146 
    147     /* Get node's children
    148     */
    149     getChildren: function(node) {
    150       var children = [];
    151       for (var j = 0, l = node.childNodes.length; j<l; j++ ) {
    152         if (node.childNodes[j].nodeType === 1) {
    153           children.push(node.childNodes[j]);
    154         }
    155       }
    156       return children;
    157     },
    158 
    159     /* Classify node's children as argumentss, variable bindings, or qualifiers
    160     */
    161     classifyChildren: function(contentMMLNode) {
    162       var args = [], bvars = [], qualifiers = [];
    163       for (var j = 0, l = contentMMLNode.childNodes.length; j<l; j++ ) {
    164         if (contentMMLNode.childNodes[j].nodeType === 1) {
    165           var childNode = contentMMLNode.childNodes[j], name = childNode.nodeName;
    166           if (name === 'bvar') {
    167             bvars.push(childNode);
    168           } else if (name === 'condition'||
    169               name === 'degree'||
    170               name === 'momentabout'||
    171               name === 'logbase'||
    172               name === 'lowlimit'||
    173               name === 'uplimit'||
    174               (name === 'interval' && args.length<2)||
    175               name === 'domainofapplication') {
    176                 qualifiers.push(childNode);
    177               } else {
    178                 args.push(childNode);
    179               }
    180         }
    181       }
    182       return {
    183         args:args, 
    184           bvars:bvars, 
    185           qualifiers:qualifiers
    186       };
    187     },
    188 
    189     /* Add an element with given name and text content
    190     */
    191     appendToken: function(parentNode,name,textContent) {
    192       var element = CToP.createElement(name);
    193       element.appendChild(document.createTextNode(textContent));
    194       parentNode.appendChild(element);
    195       return element;
    196     },
    197 
    198     /* Transform a Content MathML node to Presentation MathML node(s), and attach it to the parent
    199     */
    200     applyTransform: function(parentNode,contentMMLNode,precedence) {
    201       if (!contentMMLNode) {
    202         var merror = CToP.createElement('merror');
    203         CToP.appendToken(merror,'mtext','Missing child node');
    204         parentNode.appendChild(merror);
    205         return;
    206       }
    207       if (contentMMLNode.nodeType === 1) {
    208         if (CToP.tokens[contentMMLNode.nodeName]) {
    209           CToP.tokens[contentMMLNode.nodeName](parentNode,contentMMLNode,precedence);
    210         } else if (contentMMLNode.childNodes.length === 0) {
    211           var mml = CToP.MML[contentMMLNode.nodeName];
    212           if (mml && mml.isa && mml.isa(CToP.mbase)) {
    213             parentNode.appendChild(CToP.cloneNode(contentMMLNode));
    214           } else {
    215             CToP.appendToken(parentNode,'mi',contentMMLNode.nodeName);
    216           }
    217         } else {
    218           var clonedChild = CToP.cloneNode(contentMMLNode);
    219           parentNode.appendChild(clonedChild);
    220           for (var j = 0, l = contentMMLNode.childNodes.length; j<l; j++ ) {
    221             CToP.applyTransform(clonedChild,contentMMLNode.childNodes[j],precedence);
    222           }
    223         }
    224       } else if (contentMMLNode.nodeType === 3) {
    225         parentNode.appendChild(CToP.cloneNode(contentMMLNode));
    226       }
    227     },
    228 
    229     /* Make an mfenced environment
    230     */
    231     createmfenced: function(children,open,close) {
    232       var mf = CToP.createElement('mfenced');
    233       mf.setAttribute('open',open);
    234       mf.setAttribute('close',close);
    235       for (var j = 0, l = children.length; j<l; j++ ) {
    236         CToP.applyTransform(mf,children[j],0);
    237       }
    238       return mf;
    239     },
    240 
    241     transforms: {
    242 
    243       /* Transform an identifier symbol
    244       */
    245       identifier: function(textContent) {
    246         return function(parentNode,contentMMLNode,precedence) {
    247           CToP.appendToken(parentNode,'mi',textContent);
    248         }
    249       },
    250 
    251       /* Transform a set or set-like notation
    252       */
    253       set: function(open,close) {
    254         var bindSet = CToP.transforms.bind('',',','|');
    255         return function(parentNode,contentMMLNode) {
    256           var children = CToP.classifyChildren(contentMMLNode);
    257 
    258           var args = children.args, bvars = children.bvars, qualifiers = children.qualifiers;
    259           if (bvars.length) {
    260             var firstArg = children.args[0];
    261             args = args.slice(1);
    262             var mfenced = CToP.createElement('mfenced');
    263             mfenced.setAttribute('open',open);
    264             mfenced.setAttribute('close',close);
    265             bindSet(mfenced,contentMMLNode,firstArg,args,bvars,qualifiers,0);
    266             parentNode.appendChild(mfenced);
    267           } else {
    268             parentNode.appendChild(CToP.createmfenced(args,open,close));
    269           }
    270         }
    271       },
    272 
    273       /* Transform a content token to a presentation token
    274        *
    275        * (function factory)
    276        * @param {string} name - name of the corresponding presentation MML tag
    277        */
    278       token: function(name) {
    279         return function(parentNode,contentMMLNode) {
    280           if (contentMMLNode.childNodes.length === 1 && contentMMLNode.childNodes[0].nodeType === 3) {
    281             CToP.appendToken(parentNode,name,CToP.getTextContent(contentMMLNode));
    282           } else {
    283             var mrow = CToP.createElement('mrow');
    284             for (var j = 0, l = contentMMLNode.childNodes.length; j<l; j++ ) {
    285               if (contentMMLNode.childNodes[j].nodeType === 3) {
    286                 CToP.appendToken(parentNode,name,CToP.getTextContent(contentMMLNode.childNodes[j]));
    287               }else{
    288                 CToP.applyTransform(mrow,contentMMLNode.childNodes[j],0);
    289               }
    290             }
    291             if (mrow.childNodes.length) {
    292               parentNode.appendChild(mrow);
    293             }
    294           }
    295         }
    296       },
    297 
    298       /* Transform a binary operation
    299        *
    300        * (function factory)
    301        */
    302       binary: function(name,tokenPrecedence) {
    303         return function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    304           var mrow = CToP.createElement('mrow');
    305           var needsBrackets = tokenPrecedence<precedence || (tokenPrecedence == precedence && name === "-");
    306           if (needsBrackets) {
    307             CToP.appendToken(mrow,'mo','(');
    308           }
    309           if (args.length>1) {
    310             CToP.applyTransform(mrow,args[0],tokenPrecedence);
    311           }
    312           CToP.appendToken(mrow,'mo',name);
    313           if (args.length>0) {
    314             var z = args[(args.length === 1)?0:1];
    315             CToP.applyTransform(mrow,z,tokenPrecedence);
    316           }	
    317           if (needsBrackets) {
    318             CToP.appendToken(mrow,'mo',')');
    319           }
    320           parentNode.appendChild(mrow);
    321         }
    322       },
    323 
    324       /* Transform an infix operator
    325        *
    326        * (function factory)
    327        */
    328       infix: function(name,tokenPrecedence) {
    329         return function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    330           var mrow = CToP.createElement('mrow');
    331           var needsBrackets = precedence>tokenPrecedence;
    332           if (needsBrackets) {
    333             CToP.appendToken(mrow,'mo','(');
    334           }
    335           for (var j = 0, l = args.length; j<l; j++ ) {
    336             if (j>0) {
    337               CToP.appendToken(mrow,'mo',name);
    338             }
    339             CToP.applyTransform(mrow,args[j],tokenPrecedence);
    340           }
    341           if (needsBrackets) {
    342             CToP.appendToken(mrow,'mo',')');
    343           }
    344           parentNode.appendChild(mrow);
    345         }
    346       },
    347 
    348       /* Transform an iterated operation, e.g. summation
    349        *
    350        * (function factory
    351        */
    352       iteration: function(name,limitSymbol) {
    353         return function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    354           var mrow = CToP.createElement('mrow');
    355           var mo = CToP.createElement('mo');
    356           CToP.setTextContent(mo,name);
    357           var munderover = CToP.createElement('munderover');
    358           munderover.appendChild(mo);
    359           var mrow1 = CToP.createElement('mrow');
    360           var i, j, num_qualifiers, num_bvars, children, bvar, num_children, num_args;
    361           for (i = 0, num_qualifiers = qualifiers.length; i<num_qualifiers; i++ ) {
    362             if (qualifiers[i].nodeName === 'lowlimit'||
    363                 qualifiers[i].nodeName === 'condition'||
    364                 qualifiers[i].nodeName === 'domainofapplication')
    365             {
    366               if (qualifiers[i].nodeName === 'lowlimit') {
    367                 for (j = 0, num_bvars = bvars.length; j<num_bvars; j++ ) {
    368                   bvar = bvars[j];
    369                   children = CToP.getChildren(bvar);
    370                   if (children.length) {
    371                     CToP.applyTransform(mrow1,children[0],0);
    372                   }
    373                 }
    374                 if (bvars.length) {
    375                   CToP.appendToken(mrow1,"mo",limitSymbol);
    376                 }
    377               }
    378               children = CToP.getChildren(qualifiers[i]);
    379               for (j = 0;j<children.length;j++) {
    380                 CToP.applyTransform(mrow1,children[j],0);
    381               }
    382             } else {
    383               children = CToP.getChildren(qualifiers[i]);
    384               if (qualifiers[i].nodeName === 'interval' && children.length === 2) {
    385                 for (j = 0, num_bvars = bvars.length; j<num_bvars; j++ ) {
    386                   bvar = bvars[j];
    387                   children = CToP.getChildren(bvar);
    388                   if (children.length) {
    389                     CToP.applyTransform(mrow1,children[0],0);
    390                   }
    391                 }
    392                 if (bvars.length) {
    393                   CToP.appendToken(mrow1,"mo","=");
    394                 }
    395                 CToP.applyTransform(mrow1,CToP.getChildren(qualifiers[i])[0],0);
    396               }
    397             }
    398           }
    399           munderover.appendChild(mrow1);
    400           var mjrow = CToP.createElement('mrow');
    401           for (i = 0, num_qualifiers = qualifiers.length; i<num_qualifiers; i++ ) {
    402             if (qualifiers[i].nodeName === 'uplimit' ||qualifiers[i].nodeName === 'interval' )
    403             {
    404               children = CToP.getChildren(qualifiers[i]);
    405               for (j = 0, num_children = children.length; j<num_children; j++ ) {
    406                 CToP.applyTransform(mjrow,children[j],0);
    407               }
    408             }
    409           }
    410           munderover.appendChild(mjrow);
    411           mrow.appendChild(munderover);
    412 
    413           for (i = 0, num_args = args.length; i<num_args; i++ ) {
    414             CToP.applyTransform(mrow,args[i],precedence);
    415           }
    416 
    417           parentNode.appendChild(mrow);
    418         }
    419       },
    420 
    421       /* Transform something which binds a variable, e.g. forall or lambda
    422        *
    423        * (function factory)
    424        */
    425       bind: function(name,argSeparator,conditionSeparator) {
    426         return function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    427           var mrow = CToP.createElement('mrow');
    428           var children, i, j, l, num_qualifiers, num_children;
    429           if (name) {
    430             CToP.appendToken(mrow,'mo',name);
    431           }
    432           for (j = 0, l = bvars.length; j<l; j++ ) {
    433             var bvar = bvars[j];
    434             if (j>0) {
    435               CToP.appendToken(mrow,'mo',',');
    436             }
    437             children = CToP.getChildren(bvar);
    438             if (children.length) {
    439               CToP.applyTransform(mrow,children[0],0);
    440             }
    441           }
    442 
    443           var conditions_mrow = CToP.createElement('mrow');
    444           var conditions = false;
    445           for (i = 0, num_qualifiers = qualifiers.length; i<num_qualifiers; i++ ) {
    446             if (qualifiers[i].nodeName === 'condition')	{
    447               conditions = true;
    448               children = CToP.getChildren(qualifiers[i]);
    449               for (j = 0, num_children = children.length; j<num_children; j++ ) {
    450                 CToP.applyTransform(conditions_mrow,children[j],0);
    451               }
    452             }
    453           }
    454           if (conditions) {
    455             CToP.appendToken(mrow,'mo',conditionSeparator);
    456           }
    457           mrow.appendChild(conditions_mrow);
    458           for (i = 0, num_qualifiers = qualifiers.length; i<num_qualifiers; i++ ) {
    459             if (qualifiers[i].nodeName != 'condition')	{
    460               CToP.appendToken(mrow,'mo','\u2208');
    461               children = CToP.getChildren(qualifiers[i]);
    462               for (j = 0, num_children = children.length; j<num_children; j++ ) {
    463                 CToP.applyTransform(mrow,children[j],0);
    464               }
    465             }
    466           }
    467           if (args.length && (bvars.length||children.length)) {
    468             CToP.appendToken(mrow,'mo',argSeparator);
    469           }
    470           for (i = 0, l = args.length; i<l; i++ ) {
    471             CToP.applyTransform(mrow,args[i],0);
    472           }
    473           parentNode.appendChild(mrow);
    474         }
    475       },
    476 
    477       /** Transform a function application
    478        *
    479        * i.e. something which ends up looking like `f(x,y,z)`, where `f` is a string
    480        *
    481        * (function factory)
    482        */
    483       fn: function(name) {
    484         return function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    485           var mrow = CToP.createElement('mrow');
    486           if (firstArg.childNodes.length) {
    487             CToP.applyTransform(mrow,firstArg,1);
    488           } else {
    489             CToP.appendToken(mrow,'mi',name);
    490           }
    491           CToP.appendToken(mrow,'mo','\u2061');
    492           mrow.appendChild(CToP.createmfenced(args,'(',')'));
    493           parentNode.appendChild(mrow);
    494         }
    495       },
    496 
    497       /** Transform a min/max operation
    498        *
    499        * (function factory)
    500        */
    501       minmax: function(name) {
    502         return function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    503           var mrow = CToP.createElement('mrow');
    504           CToP.appendToken(mrow,'mi',name);
    505           var mrow2 = CToP.createElement('mrow');
    506           CToP.appendToken(mrow2,'mo','{');
    507           for (var i = 0, l = args.length; i<l; i++ ) {
    508             if (i>0) {
    509               CToP.appendToken(mrow2,'mo',',');
    510             }
    511             CToP.applyTransform(mrow2,args[i],0);
    512           }
    513           if (qualifiers.length) {
    514             CToP.appendToken(mrow2,'mo','|');
    515             for (i = 0, l = qualifiers.length; i<l; i++ ) {
    516               CToP.applyTransform(mrow2,qualifiers[i],0);
    517             }
    518           }
    519           CToP.appendToken(mrow2,'mo','}');
    520           mrow.appendChild(mrow2);
    521           parentNode.appendChild(mrow);
    522         }
    523       }
    524     }
    525   }
    526 
    527   /* Functions to transform variable/atom tokens
    528   */
    529   CToP.tokens = {
    530     ci: function(parentNode,contentMMLNode,precedence) {
    531       if (contentMMLNode.childNodes.length === 1 && contentMMLNode.childNodes[0].nodeType === 3) {
    532         var mi = CToP.appendToken(parentNode,'mi',CToP.getTextContent(contentMMLNode));
    533         var type = contentMMLNode.getAttribute('type');
    534         if (type in CToP.settings.cistyles) {
    535           mi.setAttribute('mathvariant',CToP.settings.cistyles[type]);
    536         }
    537       } else {
    538         CToP.transforms.token('mi')(parentNode,contentMMLNode,precedence);
    539       }
    540     },
    541     cs: CToP.transforms.token('ms'),
    542 
    543     csymbol: function(parentNode,contentMMLNode,precedence) {
    544       var cd = contentMMLNode.getAttribute('cd');
    545       if (cd && CToP.contentDictionaries[cd]) {
    546         CToP.contentDictionaries[cd](parentNode,contentMMLNode,precedence);
    547       } else if (CToP.settings.symbols[name]) {
    548         CToP.appendToken(parentNode,'mi',CToP.settings.symbols[name]);
    549       } else {
    550         CToP.tokens.ci(parentNode,contentMMLNode);
    551       }
    552     },
    553     fn: function(parentNode,contentMMLNode,precedence) {
    554       CToP.applyTransform(parentNode,CToP.getChildren(contentMMLNode)[0],precedence);
    555     },
    556 
    557     naturalnumbers: CToP.transforms.identifier('\u2115'),
    558     integers: CToP.transforms.identifier('\u2124'),
    559     reals: CToP.transforms.identifier('\u211D'),
    560     rationals: CToP.transforms.identifier('\u211A'),
    561     complexes: CToP.transforms.identifier('\u2102'),
    562     primes: CToP.transforms.identifier('\u2119'),
    563     exponentiale: CToP.transforms.identifier('e'),
    564     imaginaryi: CToP.transforms.identifier('i'),
    565     notanumber: CToP.transforms.identifier('NaN'),
    566     eulergamma: CToP.transforms.identifier('\u03B3'),
    567     gamma: CToP.transforms.identifier('\u0263'),
    568     pi: CToP.transforms.identifier('\u03C0'),
    569     infinity: CToP.transforms.identifier('\u221E'),
    570     emptyset: CToP.transforms.identifier('\u2205'),
    571     "true": CToP.transforms.identifier('true'),
    572     "false": CToP.transforms.identifier('false'),
    573     set: CToP.transforms.set('{','}'),
    574     list: CToP.transforms.set('(',')'),
    575 
    576     interval: function(parentNode,contentMMLNode,precedence) {
    577       var closure = contentMMLNode.getAttribute('closure');
    578 
    579       var open, close;
    580       switch(closure) {
    581         case 'open':
    582           open = '(';
    583           close = ')';
    584           break;
    585         case 'open-closed':
    586           open = '(';
    587           close = ']';
    588           break;
    589         case 'closed-open':
    590           open = '[';
    591           close = ')';
    592           break;
    593         case 'closed':
    594         default:
    595           open = '[';
    596           close = ']';
    597       }
    598 
    599       parentNode.appendChild(CToP.createmfenced(CToP.getChildren(contentMMLNode),open,close));
    600     },
    601 
    602     apply: function(parentNode,contentMMLNode,precedence) {
    603       var children = CToP.classifyChildren(contentMMLNode);
    604 
    605       var firstArg = children.args[0];
    606       var args = children.args.slice(1), bvars = children.bvars, qualifiers = children.qualifiers;
    607 
    608       if (firstArg) {
    609         var name = firstArg.nodeName;
    610         name = (name === "csymbol") ? CToP.getTextContent(firstArg).toLowerCase() : name;
    611         if (CToP.applyTokens[name]) {
    612           CToP.applyTokens[name](parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
    613         } else {
    614           CToP.transforms.fn(name)(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
    615         }
    616       } else {
    617         parentNode.appendChild(CToP.createElement('mrow'));
    618       }
    619     },
    620 
    621     cn: function(parentNode,contentMMLNode,precedence) {
    622       var type = contentMMLNode.getAttribute("type");
    623       var base = contentMMLNode.getAttribute("base");
    624       if (type || base) {
    625         if (base) {
    626           type = 'based-integer';
    627         }
    628         switch(type) {
    629           case 'integer':
    630           case 'real':
    631           case 'double':
    632           case 'constant':
    633             CToP.transforms.token('mn')(parentNode,contentMMLNode);
    634             break;
    635           case 'hexdouble':
    636             CToP.appendToken(parentNode,'mn','0x'+CToP.getTextContent(contentMMLNode));
    637             break;
    638           default:
    639             var apply = CToP.createElement('apply');
    640             var mrow = CToP.createElement('mrow');
    641             var c = CToP.createElement(type);
    642             apply.appendChild(c);
    643             if (base) {
    644               CToP.appendToken(apply,'mn',base);
    645             }
    646             for (var j = 0, l = contentMMLNode.childNodes.length; j<l; j++ ) {
    647               if (contentMMLNode.childNodes[j].nodeType === 3) {
    648                 CToP.appendToken(mrow,'cn',CToP.getTextContent(contentMMLNode.childNodes[j]));
    649               }else if (contentMMLNode.childNodes[j].nodeName === 'sep') {
    650                 apply.appendChild(mrow);
    651                 mrow = CToP.createElement('mrow');
    652               } else {
    653                 mrow.appendChild(CToP.cloneNode(contentMMLNode.childNodes[j],true));
    654               }
    655             }
    656             apply.appendChild(mrow);
    657             CToP.applyTransform(parentNode,apply,0);
    658         }
    659       } else {  
    660         CToP.transforms.token('mn')(parentNode,contentMMLNode);
    661       }
    662     },
    663 
    664     vector: function(parentNode,contentMMLNode,precedence) {
    665       var mrow = CToP.createElement('mrow');
    666       CToP.appendToken(mrow,'mo','(');
    667 
    668       var mtable = CToP.createElement('mtable');
    669       var children = CToP.getChildren(contentMMLNode);
    670       for (var i = 0, l = children.length; i<l; i++ ) {
    671         var mtr = CToP.createElement('mtr');
    672         var mtd = CToP.createElement('mtd');
    673         CToP.applyTransform(mtd,children[i],0);
    674         mtr.appendChild(mtd);
    675         mtable.appendChild(mtr);
    676       }
    677 
    678       mrow.appendChild(mtable);
    679       CToP.appendToken(mrow,'mo',')');
    680       parentNode.appendChild(mrow);
    681     },
    682 
    683     piecewise: function(parentNode,contentMMLNode,precedence) {
    684       var mrow = CToP.createElement('mrow');
    685       CToP.appendToken(mrow,'mo','{');
    686       var mtable = CToP.createElement('mtable');
    687       mrow.appendChild(mtable);
    688       var children = CToP.getChildren(contentMMLNode);
    689       for (var i = 0, l = children.length; i<l; i++ ) {
    690         CToP.applyTransform(mtable,children[i],0);
    691       }
    692       parentNode.appendChild(mrow);
    693     },
    694 
    695     piece: function(parentNode,contentMMLNode,precedence) {
    696       var mtr = CToP.createElement('mtr');
    697       var children = CToP.getChildren(contentMMLNode);
    698       for (var i = 0, l = children.length; i<l; i++ ) {
    699         var mtd = CToP.createElement('mtd');
    700         mtr.appendChild(mtd);
    701         CToP.applyTransform(mtd,children[i],0);
    702         if (i === 0) {
    703           mtd = CToP.createElement('mtd');
    704           CToP.appendToken(mtd,"mtext","\u00A0if\u00A0");
    705           mtr.appendChild(mtd);
    706         }
    707       }
    708       parentNode.appendChild(mtr);
    709     },
    710 
    711     otherwise: function(parentNode,contentMMLNode,precedence) {
    712       var mtr = CToP.createElement('mtr');
    713       var children = CToP.getChildren(contentMMLNode);
    714       if (children.length) {
    715         var mtd = CToP.createElement('mtd');
    716         mtr.appendChild(mtd);
    717         CToP.applyTransform(mtd,children[0],0);
    718         mtd = CToP.createElement('mtd');
    719         mtd.setAttribute('columnspan','2');
    720         CToP.appendToken(mtd,"mtext","\u00A0otherwise");
    721         mtr.appendChild(mtd);
    722       }
    723       parentNode.appendChild(mtr);
    724     },
    725 
    726     matrix: function(parentNode,contentMMLNode,precedence) {
    727       var children = CToP.classifyChildren(contentMMLNode);
    728       var args = children.args, bvars = children.bvars, qualifiers = children.qualifiers;
    729 
    730       if (bvars.length || qualifiers.length) {
    731         var mrow = CToP.createElement('mrow');
    732         CToP.appendToken(mrow,"mo","[");
    733         var msub = CToP.createElement('msub');
    734         CToP.appendToken(msub,'mi','m');
    735         var mrow2 = CToP.createElement('mrow');
    736         for (var i = 0, l = bvars.length; i<l; i++ ) {
    737           if (i != 0) {
    738             CToP.appendToken(mrow2,'mo',',');
    739           }	
    740           CToP.applyTransform(mrow2,bvars[i].childNodes[0],0);
    741         }
    742         msub.appendChild(mrow2);
    743         mrow.appendChild(msub);
    744         var msub2 = CToP.cloneNode(msub,true);
    745         CToP.appendToken(mrow,'mo','|');
    746         mrow.appendChild(msub2);
    747         CToP.appendToken(mrow,'mo','=');
    748         for (i = 0, l = args.length; i<l; i++ ) {
    749           if (i != 0) {
    750             CToP.appendToken(mrow,'mo',',');
    751           }	
    752           CToP.applyTransform(mrow,args[i],0);
    753         }
    754         CToP.appendToken(mrow,'mo',';');
    755         for (i = 0, l = qualifiers.length; i<l; i++) {
    756           if (i != 0) {
    757             CToP.appendToken(mrow,'mo',',');
    758           }	
    759           CToP.applyTransform(mrow,qualifiers[i],0);
    760         }
    761         CToP.appendToken(mrow,'mo',']');
    762         parentNode.appendChild(mrow);
    763       } else {
    764         var mfenced = CToP.createElement('mfenced');
    765         var mtable = CToP.createElement('mtable');
    766         for (i = 0, l = args.length; i<l; i++ ) {
    767           CToP.applyTransform(mtable,args[i],0);
    768         }
    769         mfenced.appendChild(mtable);
    770         parentNode.appendChild(mfenced);
    771       }
    772     },
    773 
    774     matrixrow: function(parentNode,contentMMLNode,precedence) {
    775       var mtr = CToP.createElement('mtr');
    776       var children = CToP.getChildren(contentMMLNode);
    777       for (var i = 0, l = children.length; i<l; i++ ) {
    778         var mtd = CToP.createElement('mtd');
    779         CToP.applyTransform(mtd,children[i],0);
    780         mtr.appendChild(mtd);
    781       }
    782       parentNode.appendChild(mtr);
    783     },
    784 
    785     condition: function(parentNode,contentMMLNode,precedence) {
    786       var mrow = CToP.createElement('mrow');
    787       var children = CToP.getChildren(contentMMLNode);
    788       for (var i = 0, l = children.length; i<l; i++ ) {
    789         CToP.applyTransform(mrow,children[i],0);
    790       }
    791       parentNode.appendChild(mrow);
    792     },
    793 
    794     lambda: function(parentNode,contentMMLNode,precedence) {
    795       var firstArg = CToP.createElement('lambda');
    796       var children = CToP.classifyChildren(contentMMLNode);
    797       var args = children.args, bvars = children.bvars, qualifiers = children.qualifiers;
    798       var i, l, num_qualifiers;
    799       
    800       if (bvars.length) {
    801         CToP.applyTokens.lambda(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
    802       } else {
    803         var mrow = CToP.createElement('mrow');
    804         for (i = 0, l = args.length; i<l; i++ ) {
    805           CToP.applyTransform(mrow,args[i],0);
    806         }
    807         if (qualifiers.length) {
    808           var msub = CToP.createElement('msub');
    809           CToP.appendToken(msub,'mo','|');
    810           var mrow2 = CToP.createElement('mrow');
    811           for (i = 0, num_qualifiers = qualifiers.length; i<num_qualifiers; i++ ) {
    812             children = CToP.getChildren(qualifiers[i]);
    813             for (var j = 0, num_children = children.length; j<num_children; j++ ) {
    814               CToP.applyTransform(mrow2,children[j],0);
    815             }
    816           }
    817           msub.appendChild(mrow2);
    818           mrow.appendChild(msub);
    819         }
    820         parentNode.appendChild(mrow);
    821       }
    822     },
    823 
    824     ident: function(parentNode,contentMMLNode,precedence) {
    825       CToP.appendToken(parentNode,"mi","id")
    826     },
    827 
    828     domainofapplication: function(parentNode,contentMMLNode,precedence) {
    829       var merror = CToP.createElement('merror');
    830       CToP.appendToken(merror,'mtext','unexpected domainofapplication');
    831       parentNode.appendChild(merror);
    832     },
    833 
    834     share: function(parentNode,contentMMLNode,precedence) {
    835       var mi = CToP.createElement('mi');
    836       mi.setAttribute('href',contentMMLNode.getAttribute('href'));
    837       CToP.setTextContent(mi,"Share " + contentMMLNode.getAttribute('href'));
    838       parentNode.appendChild(mi);
    839     },
    840 
    841     cerror: function(parentNode,contentMMLNode,precedence) {
    842       var merror = CToP.createElement('merror');
    843       var children = CToP.getChildren(contentMMLNode);
    844       for (var i = 0, l = children.length; i<l; i++ ) {
    845         CToP.applyTransform(merror,children[i],0);
    846       }
    847       parentNode.appendChild(merror);
    848     },
    849 
    850     semantics: function(parentNode,contentMMLNode,precedence)  {
    851       var mrow = CToP.createElement('mrow');
    852       var children = CToP.getChildren(contentMMLNode);
    853       if (children.length) {
    854         var z = children[0];
    855         for (var i = 0, l = children.length; i<l; i++ ) {
    856           if (children[i].nodeName === 'annotation-xml' && children[i].getAttribute('encoding') === 'MathML-Presentation') {
    857             z = children[i];
    858             break;
    859           }
    860         }
    861         CToP.applyTransform(mrow,z,0);
    862       }
    863       parentNode.appendChild(mrow);
    864     },
    865 
    866     "annotation-xml": function(parentNode,contentMMLNode,precedence)  {
    867       var mrow = CToP.createElement('mrow');
    868       var children = CToP.getChildren(contentMMLNode);
    869       for (var i = 0, l = children.length; i<l; i++ ) {
    870         CToP.applyTransform(mrow,children[i],0);
    871       }
    872       parentNode.appendChild(mrow);
    873     }
    874   };
    875 
    876   CToP.tokens.reln = CToP.tokens.bind = CToP.tokens.apply;
    877 
    878   CToP.contentDictionaries = {
    879     "setname1": function(parentNode,contentMMLNode,precedence) {
    880       var sets = {
    881         C: '\u2102',
    882         N: '\u2115',
    883         P: '\u2119',
    884         Q: '\u211A',
    885         R: '\u211D',
    886         Z: '\u2124'
    887       }
    888       var name = CToP.getTextContent(contentMMLNode);
    889       CToP.appendToken(parentNode,'mi',sets[name]);
    890     },
    891     aritherror: function(parentNode,contentMMLNode,precedence) {
    892       var name = CToP.getTextContent(contentMMLNode);
    893       CToP.appendToken(parentNode,'mi',name+':');
    894     }
    895   }
    896 
    897   /* Functions to transform function/operation application tokens
    898   */
    899   CToP.applyTokens = {
    900     rem: CToP.transforms.binary('mod',3),
    901     divide: CToP.transforms.binary('/',3),
    902     remainder: CToP.transforms.binary('mod',3),
    903     implies: CToP.transforms.binary('\u21D2',3),
    904     factorof: CToP.transforms.binary('|',3),
    905     "in": CToP.transforms.binary('\u2208',3),
    906     notin: CToP.transforms.binary('\u2209',3),
    907     notsubset: CToP.transforms.binary('\u2288',2),
    908     notprsubset: CToP.transforms.binary('\u2284',2),
    909     setdiff: CToP.transforms.binary('\u2216',2),
    910     eq: CToP.transforms.infix('=',1),
    911     compose: CToP.transforms.infix('\u2218',0),
    912     "left_compose": CToP.transforms.infix('\u2218',1),
    913     xor: CToP.transforms.infix('xor',3),
    914     neq: CToP.transforms.infix('\u2260',1),
    915     gt: CToP.transforms.infix('>',1),
    916     lt: CToP.transforms.infix('<',1),
    917     geq: CToP.transforms.infix('\u2265',1),
    918     leq: CToP.transforms.infix('\u2264',1),
    919     equivalent: CToP.transforms.infix('\u2261',1),
    920     approx: CToP.transforms.infix('\u2248',1),
    921     subset: CToP.transforms.infix('\u2286',2),
    922     prsubset: CToP.transforms.infix('\u2282',2),
    923     cartesianproduct: CToP.transforms.infix('\u00D7',2),
    924     "cartesian_product": CToP.transforms.infix('\u00D7',2),
    925     vectorproduct: CToP.transforms.infix('\u00D7',2),
    926     scalarproduct: CToP.transforms.infix('.',2),
    927     outerproduct: CToP.transforms.infix('\u2297',2),
    928     sum: CToP.transforms.iteration('\u2211','='),
    929     product: CToP.transforms.iteration('\u220F','='),
    930     forall: CToP.transforms.bind('\u2200','.',','),
    931     exists: CToP.transforms.bind('\u2203','.',','),
    932     lambda: CToP.transforms.bind('\u03BB','.',','),
    933     limit: CToP.transforms.iteration('lim','\u2192'),
    934     sdev: CToP.transforms.fn('\u03c3'),
    935     determinant: CToP.transforms.fn('det'),
    936     max: CToP.transforms.minmax('max'),
    937     min: CToP.transforms.minmax('min'),
    938     real: CToP.transforms.fn('\u211b'),
    939     imaginary: CToP.transforms.fn('\u2111'),
    940     set: CToP.transforms.set('{','}'),
    941     list: CToP.transforms.set('(',')'),
    942 
    943     exp: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    944       var msup = CToP.createElement('msup');
    945       CToP.appendToken(msup,'mi','e');
    946       CToP.applyTransform(msup,args[0],0);
    947       parentNode.appendChild(msup);
    948     },
    949 
    950     union: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    951       if (bvars.length) {
    952         CToP.transforms.iteration('\u22C3','=')(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
    953       } else {
    954         CToP.transforms.infix('\u222A',2)(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
    955       }
    956     },
    957 
    958     intersect: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    959       if (bvars.length) {
    960         CToP.transforms.iteration('\u22C2','=')(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
    961       } else {
    962         var mrow = CToP.createElement('mrow');
    963         var needsBrackets = precedence>2;
    964         if (needsBrackets) {
    965           CToP.appendToken(mrow,'mo','(');
    966         }
    967         for (var j = 0, l = args.length; j<l; j++ ) {
    968           var argBrackets = false;
    969           if (j>0) {
    970             CToP.appendToken(mrow,'mo','\u2229');
    971             if (args[j].nodeName === 'apply') {
    972               var child = CToP.getChildren(args[j])[0];
    973               argBrackets = child.nodeName  ===  'union';
    974             }
    975           }
    976           if (argBrackets) {
    977             CToP.appendToken(mrow,'mo','(');
    978           }
    979           CToP.applyTransform(mrow,args[j],2);
    980           if (argBrackets) {
    981             CToP.appendToken(mrow,'mo',')');
    982           }
    983         }
    984         if (needsBrackets) {
    985           CToP.appendToken(mrow,'mo',')');
    986         }
    987         parentNode.appendChild(mrow);
    988       }
    989     },
    990 
    991     floor: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
    992       var mrow = CToP.createElement('mrow');
    993       CToP.appendToken(mrow,'mo','\u230a');
    994       CToP.applyTransform(mrow,args[0],0);
    995       CToP.appendToken(mrow,'mo','\u230b');
    996       parentNode.appendChild(mrow);
    997     },
    998 
    999     conjugate: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1000       var mover = CToP.createElement('mover');
   1001       CToP.applyTransform(mover,args[0],0);
   1002       CToP.appendToken(mover,'mo','\u00af');
   1003       parentNode.appendChild(mover);
   1004     },
   1005 
   1006     abs: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1007       var mrow = CToP.createElement('mrow');
   1008       CToP.appendToken(mrow,'mo','|');
   1009       CToP.applyTransform(mrow,args[0],0);
   1010       CToP.appendToken(mrow,'mo','|');
   1011       parentNode.appendChild(mrow);
   1012     },
   1013 
   1014     and: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1015       if (bvars.length || qualifiers.length) {
   1016         CToP.transforms.iteration('\u22c0','=')(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,4);
   1017       } else {
   1018         CToP.transforms.infix('\u2227',2)(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
   1019       }
   1020     },
   1021 
   1022     or: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1023       if (bvars.length || qualifiers.length) {
   1024         CToP.transforms.iteration('\u22c1','=')(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,4);
   1025       } else {
   1026         CToP.transforms.infix('\u2228',2)(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
   1027       }
   1028     },
   1029 
   1030     xor: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1031       if (bvars.length || qualifiers.length) {
   1032         CToP.transforms.iteration('xor','=')(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,4);
   1033       } else {
   1034         CToP.transforms.infix('xor',2)(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
   1035       }
   1036     },
   1037 
   1038     card: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1039       var mrow = CToP.createElement('mrow');
   1040       CToP.appendToken(mrow,'mo','|');
   1041       CToP.applyTransform(mrow,args[0],0);
   1042       CToP.appendToken(mrow,'mo','|');
   1043       parentNode.appendChild(mrow);
   1044     },
   1045 
   1046     mean: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1047       if (args.length === 1) {
   1048         var mover = CToP.createElement('mover');
   1049         CToP.applyTransform(mover,args[0],0);
   1050         CToP.appendToken(mover,'mo','\u00af');
   1051         parentNode.appendChild(mover);
   1052       } else {
   1053         parentNode.appendChild(CToP.createmfenced(args,'\u27e8','\u27e9'));
   1054       }
   1055     },
   1056 
   1057     moment: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1058       var degree, momentabout, children, i, j, l;
   1059 
   1060       for (i = 0, l = qualifiers.length; i<l; i++ ) {
   1061         if (qualifiers[i].nodeName === 'degree') {
   1062           degree = qualifiers[i];
   1063         } else if (qualifiers[i].nodeName === 'momentabout') {
   1064           momentabout = qualifiers[i];
   1065         }
   1066       }
   1067 
   1068       var mrow = CToP.createElement('mrow');
   1069       CToP.appendToken(mrow,'mo','\u27e8');
   1070       var argrow = CToP.createElement('mrow');
   1071       if (args.length>1) {
   1072         argrow.appendChild(CToP.createmfenced(args,'(',')'));
   1073       } else {
   1074         CToP.applyTransform(argrow,args[0],0);
   1075       }
   1076       if (degree) {
   1077         var msup = CToP.createElement('msup');
   1078         msup.appendChild(argrow);
   1079         children = CToP.getChildren(degree);
   1080         for (j = 0, l = children.length; j<l; j++ ) {
   1081           CToP.applyTransform(msup,children[j],0);
   1082         }
   1083         mrow.appendChild(msup);
   1084       } else {
   1085         mrow.appendChild(argrow);
   1086       }
   1087       CToP.appendToken(mrow,'mo','\u27e9');
   1088 
   1089       if (momentabout) {
   1090         var msub = CToP.createElement('msub');
   1091         msub.appendChild(mrow);
   1092         children = CToP.getChildren(momentabout);
   1093         for (j = 0, l = children.length; j<l; j++ ) {
   1094           CToP.applyTransform(msub,children[j],0);
   1095         }
   1096         parentNode.appendChild(msub);
   1097       } else {
   1098         parentNode.appendChild(mrow);
   1099       }
   1100     },
   1101 
   1102     variance: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1103       var mrow = CToP.createElement('mrow');
   1104       var msup = CToP.createElement('msup');
   1105       CToP.appendToken(msup,'mo','\u03c3');
   1106       CToP.appendToken(msup,'mn','2');
   1107       mrow.appendChild(msup);
   1108       CToP.appendToken(mrow,'mo','\u2061');
   1109       mrow.appendChild(CToP.createmfenced(args,'(',')'));
   1110       parentNode.appendChild(mrow);
   1111     },
   1112 
   1113     grad: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1114       var mrow = CToP.createElement('mrow');
   1115       CToP.appendToken(mrow,'mo','\u2207');
   1116       CToP.appendToken(mrow,'mo','\u2061');
   1117       mrow.appendChild(CToP.createmfenced(args,'(',')'));
   1118       parentNode.appendChild(mrow);
   1119     },
   1120 
   1121     laplacian: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1122       var mrow = CToP.createElement('mrow');
   1123       var msup = CToP.createElement('msup');
   1124       CToP.appendToken(msup,'mo','\u2207');
   1125       CToP.appendToken(msup,'mn','2');
   1126       mrow.appendChild(msup);
   1127       CToP.appendToken(mrow,'mo','\u2061');
   1128       mrow.appendChild(CToP.createmfenced(args,'(',')'));
   1129       parentNode.appendChild(mrow);
   1130     },
   1131 
   1132     curl: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1133       var mrow = CToP.createElement('mrow');
   1134       CToP.appendToken(mrow,'mo','\u2207');
   1135       CToP.appendToken(mrow,'mo','\u00d7');
   1136       var needsBrackets = args[0].nodeName === 'apply';
   1137       if (needsBrackets) {
   1138         mrow.appendChild(CToP.createmfenced(args,'(', ')'));
   1139       }
   1140       else {
   1141         CToP.applyTransform(mrow,args[0],precedence);
   1142       }
   1143       parentNode.appendChild(mrow);
   1144     },
   1145 
   1146     divergence: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1147       var mrow = CToP.createElement('mrow');
   1148       CToP.appendToken(mrow,'mo','\u2207');
   1149       CToP.appendToken(mrow,'mo','\u22c5');
   1150       var needsBrackets = args[0].nodeName === 'apply';
   1151       if (needsBrackets) {
   1152         mrow.appendChild(CToP.createmfenced(args,'(', ')'));
   1153       }
   1154       else {
   1155         CToP.applyTransform(mrow,args[0],precedence);
   1156       }
   1157       parentNode.appendChild(mrow);
   1158     },
   1159 
   1160     not: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1161       var mrow = CToP.createElement('mrow');
   1162       CToP.appendToken(mrow,'mo','\u00ac');
   1163       var needsBrackets = args[0].nodeName === 'apply' || args[0].nodeName === 'bind';
   1164       if (needsBrackets) {
   1165         CToP.appendToken(mrow,'mo','(');
   1166       }
   1167       CToP.applyTransform(mrow,args[0],precedence);
   1168       if (needsBrackets) {
   1169         CToP.appendToken(mrow,'mo',')');
   1170       }
   1171       parentNode.appendChild(mrow)
   1172     },
   1173 
   1174     divide: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1175       var mfrac = CToP.createElement('mfrac');
   1176       CToP.applyTransform(mfrac,args[0],0);
   1177       CToP.applyTransform(mfrac,args[1],0);
   1178       parentNode.appendChild(mfrac);
   1179     },
   1180 
   1181     tendsto: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1182       var type;
   1183       if (firstArg.nodeName === 'tendsto') {
   1184         type = firstArg.getAttribute('type');
   1185       } else {
   1186         type = CToP.getTextContent(args[0]);
   1187         args = args.slice(1);
   1188       }
   1189       var name = (type === 'above')? '\u2198' :
   1190         (type === 'below') ? '\u2197' : '\u2192' ;
   1191       CToP.transforms.binary(name,2)(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence);
   1192     },
   1193 
   1194     minus: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1195       var tokenPrecedence = args.length === 1 ? 5 : 2;
   1196 
   1197       var mrow = CToP.createElement('mrow');
   1198       var needsBrackets = tokenPrecedence<precedence;
   1199       if (needsBrackets) {
   1200         CToP.appendToken(mrow,'mo','(');
   1201       }
   1202 
   1203       if (args.length === 1) {
   1204         CToP.appendToken(mrow,'mo','-');
   1205         CToP.applyTransform(mrow,args[0],tokenPrecedence);
   1206       } else {
   1207         CToP.applyTransform(mrow,args[0],tokenPrecedence);
   1208         CToP.appendToken(mrow,'mo','-');
   1209         var bracketArg;
   1210         if (args[1].nodeName === 'apply') {
   1211           var argOp = CToP.getChildren(args[1])[0];
   1212           bracketArg = argOp.nodeName === 'plus' || argOp.nodeName === 'minus';
   1213         }
   1214         if (bracketArg) {
   1215           CToP.appendToken(mrow,'mo','(');
   1216         }
   1217         CToP.applyTransform(mrow,args[1],tokenPrecedence);
   1218         if (bracketArg) {
   1219           CToP.appendToken(mrow,'mo',')');
   1220         }
   1221       }
   1222 
   1223       if (needsBrackets) {
   1224         CToP.appendToken(mrow,'mo',')');
   1225       }
   1226       parentNode.appendChild(mrow);
   1227     },
   1228 
   1229     "complex-cartesian": function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1230       var mrow = CToP.createElement('mrow');
   1231       CToP.applyTransform(mrow,args[0],0);
   1232       CToP.appendToken(mrow,'mo','+');
   1233       CToP.applyTransform(mrow,args[1],0);
   1234       CToP.appendToken(mrow,'mo','\u2062');
   1235       CToP.appendToken(mrow,'mi','i');
   1236       parentNode.appendChild(mrow);
   1237     },
   1238 
   1239     "complex-polar": function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1240       var mrow = CToP.createElement('mrow');
   1241       CToP.applyTransform(mrow,args[0],0);
   1242       CToP.appendToken(mrow,'mo','\u2062');
   1243       var msup = CToP.createElement('msup');
   1244       CToP.appendToken(msup,'mi','e');
   1245       var exponent = CToP.createElement('mrow');
   1246       CToP.applyTransform(exponent,args[1],0);
   1247       CToP.appendToken(exponent,'mo','\u2062');
   1248       CToP.appendToken(exponent,'mi','i');
   1249       msup.appendChild(exponent);
   1250       mrow.appendChild(msup);
   1251       parentNode.appendChild(mrow);
   1252     },
   1253 
   1254     integer: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1255       CToP.applyTransform(parentNode,args[0],0);
   1256     },
   1257 
   1258     "based-integer": function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1259       var msub = CToP.createElement('msub');
   1260       CToP.applyTransform(msub,args[1],0);
   1261       CToP.applyTransform(msub,args[0],0);
   1262       parentNode.appendChild(msub);
   1263     },
   1264 
   1265     rational: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1266       var mfrac = CToP.createElement('mfrac');
   1267       CToP.applyTransform(mfrac,args[0],0);
   1268       CToP.applyTransform(mfrac,args[1],0);
   1269       parentNode.appendChild(mfrac);
   1270     },
   1271 
   1272     times: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1273       var mrow = CToP.createElement('mrow');
   1274       var needsBrackets = precedence>3;
   1275       if (needsBrackets) {
   1276         CToP.appendToken(mrow,'mo','(');
   1277       }
   1278       for (var j = 0, l = args.length; j<l; j++ ) {
   1279         if (j>0) {
   1280           CToP.appendToken(mrow,'mo',(args[j].nodeName === 'cn') ? "\u00D7" :"\u2062");
   1281         }
   1282         CToP.applyTransform(mrow,args[j],3);
   1283       }
   1284       if (needsBrackets) {
   1285         CToP.appendToken(mrow,'mo',')');
   1286       }
   1287       parentNode.appendChild(mrow);
   1288     },
   1289 
   1290     plus: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1291       var mrow = CToP.createElement('mrow');
   1292       var needsBrackets = precedence>2;
   1293       if (needsBrackets) {
   1294         CToP.appendToken(mrow,'mo','(');
   1295       }
   1296       for (var j = 0, l = args.length; j<l; j++ ) {
   1297         var arg = args[j];
   1298         var children = CToP.getChildren(arg);
   1299         if (j>0) {
   1300           var n;
   1301           if (CToP.settings.collapsePlusMinus) {
   1302             if (arg.nodeName === 'cn' && !(children.length) && (n = Number(CToP.getTextContent(arg))) <0) {
   1303               CToP.appendToken(mrow,'mo','\u2212');
   1304               CToP.appendToken(mrow,'mn', -n);
   1305             } else if (arg.nodeName === 'apply' && children.length === 2 && children[0].nodeName === 'minus') {
   1306               CToP.appendToken(mrow,'mo','\u2212');
   1307               CToP.applyTransform(mrow,children[1],2);
   1308             } else if (arg.nodeName === 'apply' && children.length>2 && children[0].nodeName === 'times' && children[1].nodeName === 'cn' && ( n = Number(CToP.getTextContent(children[1])) < 0)) {
   1309               CToP.appendToken(mrow,'mo','\u2212');
   1310               CToP.getTextContent(children[1]) = -n;// fix me: modifying document
   1311               CToP.applyTransform(mrow,arg,2);
   1312             } else{
   1313               CToP.appendToken(mrow,'mo','+');
   1314               CToP.applyTransform(mrow,arg,2);
   1315             }
   1316           } else {
   1317             CToP.appendToken(mrow,'mo','+');
   1318             CToP.applyTransform(mrow,arg,2);
   1319           }
   1320         } else {
   1321           CToP.applyTransform(mrow,arg,2);	
   1322         }
   1323       }
   1324       if (needsBrackets) {
   1325         CToP.appendToken(mrow,'mo',')');
   1326       }
   1327       parentNode.appendChild(mrow);
   1328     },
   1329 
   1330     transpose: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1331       var msup = CToP.createElement('msup');
   1332       CToP.applyTransform(msup,args[0],precedence);
   1333       CToP.appendToken(msup,'mi','T');
   1334       parentNode.appendChild(msup);
   1335     },
   1336 
   1337     power: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1338       var msup = CToP.createElement('msup');
   1339       CToP.applyTransform(msup,args[0],3);
   1340       CToP.applyTransform(msup,args[1],precedence);
   1341       parentNode.appendChild(msup);
   1342     },
   1343 
   1344     selector: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence) {
   1345       var msub = CToP.createElement('msub');
   1346       var mrow = args ? args[0]: CToP.createElement('mrow');
   1347       CToP.applyTransform(msub,mrow,0);
   1348       var mrow2 = CToP.createElement('mrow');
   1349       for (var i = 1, l = args.length; i<l; i++ ) {
   1350         if (i != 1) {
   1351           CToP.appendToken(mrow2,'mo',',');
   1352         }	
   1353         CToP.applyTransform(mrow2,args[i],0);
   1354       }
   1355       msub.appendChild(mrow2);
   1356       parentNode.appendChild(msub);
   1357     },
   1358 
   1359     log: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1360       var mrow = CToP.createElement('mrow');
   1361       var mi = CToP.createElement('mi');
   1362       CToP.setTextContent(mi,'log');
   1363       if (qualifiers.length && qualifiers[0].nodeName === 'logbase') {
   1364         var msub = CToP.createElement('msub');
   1365         msub.appendChild(mi);
   1366         CToP.applyTransform(msub,CToP.getChildren(qualifiers[0])[0],0);
   1367         mrow.appendChild(msub);
   1368       } else {
   1369         mrow.appendChild(mi);
   1370       }
   1371       CToP.applyTransform(mrow,args[0],7);
   1372       parentNode.appendChild(mrow);
   1373     },
   1374 
   1375     "int": function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1376       var mrow = CToP.createElement('mrow');
   1377       var mo = CToP.createElement('mo');
   1378       CToP.setTextContent(mo,'\u222B');
   1379       var msubsup = CToP.createElement('msubsup');
   1380       msubsup.appendChild(mo);
   1381       var mrow1 = CToP.createElement('mrow');
   1382       var children, i, j, l, num_qualifiers, num_children;
   1383       for (i = 0, num_qualifiers = qualifiers.length; i<num_qualifiers; i++ ) {
   1384         if (qualifiers[i].nodeName === 'lowlimit'||
   1385             qualifiers[i].nodeName === 'condition'||
   1386             qualifiers[i].nodeName === 'domainofapplication')
   1387         {
   1388           children = CToP.getChildren(qualifiers[i]);
   1389           for (j = 0, num_children = children.length; j<num_children; j++ ) {
   1390             CToP.applyTransform(mrow1,children[j],0);
   1391           }
   1392         } else {
   1393           children = CToP.getChildren(qualifiers[i]);
   1394           if (qualifiers[i].nodeName === 'interval' && children.length === 2) {
   1395             CToP.applyTransform(mrow1,children[0],0);
   1396           }
   1397         }
   1398       }
   1399       msubsup.appendChild(mrow1);
   1400       var mrow2 = CToP.createElement('mrow');
   1401       for (i = 0, num_qualifiers = qualifiers.length; i<num_qualifiers; i++ ) {
   1402         if (qualifiers[i].nodeName === 'uplimit') {
   1403           children = CToP.getChildren(qualifiers[i]);
   1404           for (j = 0, num_children = children.length; j<num_children; j++ ) {
   1405             CToP.applyTransform(mrow2,children[j],0);
   1406           }
   1407           break;
   1408         } else if (qualifiers[i].nodeName === 'interval' ) {
   1409           children = CToP.getChildren(qualifiers[i]);
   1410           CToP.applyTransform(mrow2,children[children.length-1],0);
   1411           break;
   1412         }
   1413       }
   1414       msubsup.appendChild(mrow2);
   1415       mrow.appendChild(msubsup);
   1416       for (i = 0, l = args.length; i<l; i++ ) {
   1417         CToP.applyTransform(mrow,args[i],0);
   1418       }
   1419       for (i = 0, l = bvars.length; i<l; i++ ) {
   1420         var bvar = bvars[i];
   1421         children = CToP.getChildren(bvar);
   1422         if (children.length) {
   1423           var mrow3 = CToP.createElement("mrow");
   1424           CToP.appendToken(mrow3,'mi','d');
   1425           CToP.applyTransform(mrow3,children[0],0);
   1426           mrow.appendChild(mrow3);
   1427         }
   1428       }
   1429       parentNode.appendChild(mrow);
   1430     },
   1431 
   1432     inverse: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1433       var msup = CToP.createElement('msup');
   1434       var arg = (args.length) ? args[0] : CToP.createElement('mrow');
   1435       CToP.applyTransform(msup,arg,precedence);
   1436       var mfenced = CToP.createElement('mfenced');
   1437       CToP.appendToken(mfenced,'mn','-1');
   1438       msup.appendChild(mfenced);
   1439       parentNode.appendChild(msup);
   1440     },
   1441 
   1442     quotient: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1443       var mrow = CToP.createElement('mrow');
   1444       CToP.appendToken(mrow,'mo','\u230A');
   1445       if (args.length) {
   1446         CToP.applyTransform(mrow,args[0],0);
   1447         CToP.appendToken(mrow,'mo','/');
   1448         if (args.length>1) {
   1449           CToP.applyTransform(mrow,args[1],0);
   1450         }
   1451       }
   1452       CToP.appendToken(mrow,'mo','\u230B');
   1453       parentNode.appendChild(mrow);
   1454     },
   1455 
   1456     factorial: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1457       var mrow = CToP.createElement('mrow');
   1458       CToP.applyTransform(mrow,args[0],4);
   1459       CToP.appendToken(mrow,'mo','!');
   1460       parentNode.appendChild(mrow);
   1461     },
   1462 
   1463     root: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1464       var mr;
   1465       if (firstArg.nodeName === 'root' && (qualifiers.length === 0 || (qualifiers[0].nodeName === 'degree' && CToP.getTextContent(qualifiers[0]) === '2'))) {
   1466         mr = CToP.createElement('msqrt');
   1467         for (var i = 0, l = args.length; i<l; i++ ) {
   1468           CToP.applyTransform(mr,args[i],0);
   1469         }
   1470       } else {
   1471         mr = CToP.createElement('mroot');
   1472         CToP.applyTransform(mr,args[0],0);
   1473         var arg = (firstArg.nodeName === 'root') ? qualifiers[0].childNodes[0] : args[1];
   1474         CToP.applyTransform(mr,arg,0);
   1475       }
   1476       parentNode.appendChild(mr);
   1477     },
   1478 
   1479     diff: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1480       if (bvars.length) {	// d/dx form
   1481         var outNode;
   1482         var mfrac = CToP.createElement('mfrac');
   1483         var toprow = CToP.createElement('mrow');
   1484         var bottomrow = CToP.createElement('mrow');
   1485         mfrac.appendChild(toprow);
   1486         mfrac.appendChild(bottomrow);
   1487 
   1488         var bvar, degreeNode, msup, mrow;
   1489 
   1490         var d = CToP.createElement('mi');
   1491         CToP.setTextContent(d,'d');
   1492 
   1493         var children = CToP.getChildren(bvars[0]);
   1494         for (var j = 0, l = children.length; j<l; j++ ) {
   1495           if (children[j].nodeName === 'degree') {
   1496             var childNode = CToP.getChildren(children[j])[0];
   1497             if (CToP.getTextContent(childNode) != '1') {
   1498               degreeNode = childNode;
   1499               msup = CToP.createElement('msup');
   1500               msup.appendChild(d);
   1501               d = msup;
   1502               CToP.applyTransform(d,degreeNode,0);
   1503             }
   1504           } else {
   1505             bvar = children[j];
   1506           }
   1507         }
   1508         toprow.appendChild(d);
   1509 
   1510         if (args.length) {
   1511           switch(args[0].nodeName) {
   1512             case 'apply':
   1513             case 'bind':
   1514             case 'reln':
   1515               mrow = CToP.createElement('mrow');
   1516               mrow.appendChild(mfrac);
   1517               CToP.applyTransform(mrow,args[0],3);
   1518               outNode = mrow;
   1519               break;
   1520             default:
   1521               CToP.applyTransform(toprow,args[0],0);
   1522               outNode = mfrac;
   1523           }
   1524         }
   1525 
   1526         CToP.appendToken(bottomrow,'mi','d');
   1527 
   1528         if (degreeNode) {
   1529           var msup2 = CToP.createElement('msup');
   1530           CToP.applyTransform(msup2,bvar,0);
   1531           CToP.applyTransform(msup2,degreeNode,0);
   1532           bottomrow.appendChild(msup2);
   1533         } else {
   1534           CToP.applyTransform(bottomrow,bvar,0);
   1535         }
   1536 
   1537 
   1538         parentNode.appendChild(outNode);
   1539       } else {	// f' form
   1540         msup = CToP.createElement('msup');
   1541         mrow = CToP.createElement('mrow');
   1542         msup.appendChild(mrow);
   1543         CToP.applyTransform(mrow,args[0],0); 
   1544         CToP.appendToken(msup,'mo','\u2032'); // tick
   1545         parentNode.appendChild(msup);
   1546       }
   1547     },
   1548 
   1549     partialdiff: function(parentNode,contentMMLNode,firstArg,args,bvars,qualifiers,precedence)  {
   1550       var msup, msub, mrow;
   1551 
   1552       var mfrac = CToP.createElement('mfrac');
   1553       var toprow = CToP.createElement('mrow');
   1554       var bottomrow = CToP.createElement('mrow');
   1555       mfrac.appendChild(toprow);
   1556       mfrac.appendChild(bottomrow);
   1557 
   1558       var differendNode, degree, children;
   1559 
   1560       if (bvars.length === 0 && args.length === 2 && args[0].nodeName === 'list') {
   1561         if (args[1].nodeName === 'lambda') {	// `d^(n+m)/(dx^n dy^m) f` form, through a lambda
   1562           degree = CToP.getChildren(args[0]).length;
   1563           if (degree != 1) {
   1564             msup = CToP.createElement('msup');
   1565             CToP.appendToken(msup,'mo','\u2202');	// curly d
   1566             CToP.appendToken(msup,'mn',degree);
   1567             toprow.appendChild(msup);
   1568           } else {
   1569             CToP.appendToken(toprow,'mo','\u2202');
   1570           }
   1571 
   1572           children = CToP.getChildren(args[1]);
   1573 
   1574           differendNode = children[children.length - 1];	// thing being differentiated
   1575 
   1576           var bvarNames = [];
   1577           var lambdaChildren = CToP.getChildren(args[1]);	// names of bound variables
   1578           var lambdaSequence = CToP.getChildren(args[0]);	// indices of bound variable names, in order
   1579           for (var i = 0, l = lambdaChildren.length; i<l; i++ ) {
   1580             if (lambdaChildren[i].nodeName === 'bvar') {
   1581               bvarNames.push(CToP.getChildren(lambdaChildren[i])[0]);
   1582             }
   1583           }
   1584 
   1585           var lastN = null;
   1586           degree = 0;
   1587           function addDiff(n,degree) {
   1588             CToP.appendToken(bottomrow,'mo','\u2202');
   1589             var bvar = bvarNames[n];
   1590             if (degree>1) {
   1591               var msup = CToP.createElement('msup');
   1592               CToP.applyTransform(msup,bvar,0);
   1593               CToP.appendToken(msup,'mn',degree);
   1594               bottomrow.appendChild(msup);
   1595             } else {
   1596               CToP.applyTransform(bottomrow,bvar,0);
   1597             }
   1598           }
   1599           for (i = 0, l = lambdaSequence.length; i<l; i++ ) {
   1600             var n = Number(CToP.getTextContent(lambdaSequence[i]))-1;
   1601             if (lastN !== null && n != lastN) {
   1602               addDiff(lastN,degree);
   1603               degree = 0;
   1604             }
   1605             lastN = n;
   1606             degree += 1;
   1607           }
   1608           if (lastN) {
   1609             addDiff(lastN,degree);
   1610           }
   1611         } else {	// `D_i_j f` form
   1612           mrow = CToP.createElement('mrow');
   1613           msub = CToP.createElement('msub');
   1614           CToP.appendToken(msub,'mi','D');
   1615           var bvar = CToP.getChildren(args[0]);
   1616           msub.appendChild(CToP.createmfenced(bvar,'',''));
   1617           mrow.appendChild(msub);
   1618           CToP.applyTransform(mrow,args[1],0);
   1619           parentNode.appendChild(mrow);
   1620           return;
   1621         }
   1622       } else {	// `d^(n+m)/(dx^n dy^m) f` form, with bvars
   1623         msup = CToP.createElement('msup');
   1624         toprow.appendChild(msup);
   1625         CToP.appendToken(msup,'mo','\u2202');
   1626 
   1627         var degreeRow = CToP.createElement('mrow');
   1628         msup.appendChild(degreeRow);
   1629 
   1630         var qualifier;
   1631 
   1632         if (qualifiers.length && qualifiers[0].nodeName === 'degree' && CToP.getChildren(qualifiers[0]).length) {
   1633           qualifier = CToP.getChildren(qualifiers[0])[0];
   1634           CToP.applyTransform(degreeRow,qualifier,0);
   1635         } else {
   1636           degree = 0;
   1637           var hadFirst = false;
   1638           for (i = 0, l = bvars.length; i<l; i++ ) {
   1639             children = CToP.getChildren(bvars[i]);
   1640             if (children.length === 2) {
   1641               for (var j = 0;j<2;j++) {
   1642                 if (children[j].nodeName === 'degree') {
   1643                   if (/^\s*\d+\s*$/.test(CToP.getTextContent(children[j]))) {
   1644                     degree += Number(CToP.getTextContent(children[j]));
   1645                   } else {
   1646                     if (hadFirst) {
   1647                       CToP.appendToken(degreeRow,'mo','+');
   1648                     }
   1649                     hadFirst = true;
   1650                     CToP.applyTransform(degreeRow,CToP.getChildren(children[j])[0],0);
   1651                   }
   1652                 }
   1653               }
   1654             } else {
   1655               degree++;
   1656             }
   1657           }
   1658           if (degree>0) {
   1659             if (hadFirst) {
   1660               CToP.appendToken(degreeRow,'mo','+');
   1661             }   
   1662             CToP.appendToken(degreeRow,'mn',degree);
   1663           }
   1664         }
   1665 
   1666         if (args.length) {
   1667           differendNode = args[0];
   1668         }
   1669 
   1670         for (i = 0, l = bvars.length; i<l; i++ ) {
   1671           CToP.appendToken(bottomrow,'mo','\u2202');
   1672           children = CToP.getChildren(bvars[i]);
   1673 
   1674           if (children.length === 2) {
   1675             for (j = 0;j<2;j++) {
   1676               if (children[j].nodeName === 'degree') {
   1677                 var msup2 = CToP.createElement('msup');
   1678                 CToP.applyTransform(msup2,children[1-j],0);
   1679                 var bvarDegreeNode = CToP.getChildren(children[j])[0];
   1680                 CToP.applyTransform(msup2,bvarDegreeNode,0);
   1681                 bottomrow.appendChild(msup2);
   1682               }
   1683             }
   1684           } else if (children.length === 1) {
   1685             CToP.applyTransform(bottomrow,children[0],0);
   1686           }
   1687         }
   1688       }
   1689       if (differendNode) {
   1690         switch(differendNode.nodeName) {
   1691           case 'apply':
   1692           case 'bind':
   1693           case 'reln':
   1694             mrow = CToP.createElement('mrow');
   1695             mrow.appendChild(mfrac);
   1696             CToP.applyTransform(mrow,differendNode,3);
   1697             outNode = mrow;
   1698             break;
   1699           default:
   1700             CToP.applyTransform(toprow,differendNode,0);
   1701             outNode = mfrac;
   1702         }
   1703       } else {
   1704         outNode = mfrac;
   1705       }
   1706       parentNode.appendChild(outNode);
   1707     }
   1708   };
   1709   CToP.applyTokens.size = CToP.applyTokens.card;
   1710 
   1711   return CToP;
   1712 })(MathJax.Hub);
   1713 
   1714 
   1715 MathJax.Hub.Register.StartupHook("MathML Jax Ready",function () {
   1716 
   1717   var MATHML = MathJax.InputJax.MathML;
   1718 
   1719   var CToP = MathJax.Extension["MathML/content-mathml"];
   1720   CToP.mbase = MathJax.ElementJax.mml.mbase;
   1721   CToP.MML = MathJax.ElementJax.mml;
   1722 
   1723   MATHML.DOMfilterHooks.Add(function (data) {
   1724     data.math = CToP.transformElement(data.math);
   1725   });
   1726 
   1727   MathJax.Hub.Startup.signal.Post("MathML/content-mathml Ready");
   1728 });
   1729 
   1730 MathJax.Ajax.loadComplete("[MathJax]/extensions/MathML/content-mathml.js");