#! /usr/bin/perl # # Creates the optable.js data (for inclusion on jax/element/mml/jax.js) # and the optable directory of auxiliary operator data. # # Usage: ./makeOpTable open(OPHTML,"Operator Dictionary.html") || die "Can't load operator dictionary"; $lines = join('',); $lines =~ s/.*\s*//is; $lines =~ s!.*!!is; $lines =~ s/^\s*//gm; $lines =~ s!(|)\n!\1!g; $lines =~ s!!!g; $lines =~ s!^]*>!!gm; $lines =~ s!$!!gm; $lines =~ s/&/&/g; $lines =~ s/&/&/g; $lines =~ s/<//g; foreach $line (split(/\n/,$lines)) { ($id,$char,$name,$form,$prec,$lspace,$rspace,$min,$attributes) = split(/<\/t[dh]>]*>/,$line); next if $id eq "min"; $op{$form}{$id} = [$lspace,$rspace,$attributes,$name]; } # hack to add in missing prefix and postfix | $op{prefix}{"|"} = [0,0,'fence stretchy symmetric','vertical line']; $op{postfix}{"|"} = [0,0,'fence stretchy symmetric','vertical line']; @RANGES = ( ["BasicLatin",0x20,0x7F,'REL'], ["Latin1Supplement",0xA0,0xFF,'ORD'], ["LatinExtendedA",0x100,0x17F,'ORD'], ["LatinExtendedB",0x180,0x24F,'ORD'], ["SpacingModLetters",0x2B0,0x2FF,'ORD'], ["CombDiacritMarks",0x300,0x36F,'ORD'], ["GreekAndCoptic",0x370,0x3FF,'ORD'], # ["Cyrillic",0x400,0x4FF,'ORD'], # ["PhoneticExtensions",0x1D00,0x1DBF,'ORD'], ["LatinExtendedAdditional",0x1E00,0x1EFF,'ORD'], ["GeneralPunctuation",0x2000,0x206F,'PUNCT'], ["SuperAndSubscripts",0x2070,0x209F,'ORD'], ["CurrencySymbols",0x20A0,0x20CF,'ORD'], ["CombDiactForSymbols",0x20D0,0x20FF,'ORD'], ["LetterlikeSymbols",0x2100,0x214F,'ORD'], ["NumberForms",0x2150,0x218F,'ORD'], ["Arrows",0x2190,0x21FF,'REL'], ["MathOperators",0x2200,0x22FF,'BIN'], ["MiscTechnical",0x2300,0x23FF,'ORD'], # ["ControlPictures",0x2400,0x243F,'ORD'], ["EnclosedAlphanum",0x2460,0x24FF,'ORD'], # ["BoxDrawing",0x2500,0x257F,'ORD'], # ["BlockElements",0x2580,0x259F,'ORD'], ["GeometricShapes",0x25A0,0x25FF,'ORD'], # ["MiscSymbols",0x2600,0x26FF,'ORD'], ["Dingbats",0x2700,0x27BF,'ORD'], ["MiscMathSymbolsA",0x27C0,0x27EF,'ORD'], ["SupplementalArrowsA",0x27F0,0x27FF,'REL'], ["SupplementalArrowsB",0x2900,0x297F,'REL'], ["MiscMathSymbolsB",0x2980,0x29FF,'ORD'], ["SuppMathOperators",0x2A00,0x2AFF,'BIN'], ["MiscSymbolsAndArrows",0x2B00,0x2BFF,'ORD'], # ["CJK",0x3000,0x303F,'ORD'], # ["Hiragana",0x3040,0x309F,'ORD'], # ["PUA",0xE000,0xFB00,'ORD'], # ["AlphaPresentForms",0xFB00,0xFB4F,'ORD'], # ["Specials",0xFFF0,0xFFFF,'ORD'], ["MathAlphabets",0x1D400,0x1D7FF,'ORD'], ); sub GetRange { my $n = shift; if ($n =~ m/^[0-9A-Z]{4}$/) {$n = hex($n)} elsif ($n =~ m/^&#x([0-9A-Z]+);/) {$n = hex($1)} else {$n = ord(substr($n,0,1))} foreach $range (@RANGES) { my ($name,$l,$u,$type) = @$range; return $name if $l <= $n && $n <= $u; } return "none"; } %TEX = ( '!' => ['CLOSE', '!'], '(' => ['OPEN', '('], ')' => ['CLOSE', ')'], '*' => ['BIN', '*'], '2217' => ['BIN', '*'], '+' => ['BIN', '+'], ',' => ['PUNCT', ','], '-' => ['BIN', '-'], '2212' => ['BIN', 'minus'], '.' => ['ORD', '.'], '/' => ['ORD', '/'], '2215' => ['BIN','/'], ':' => ['REL', ':'], ';' => ['PUNCT', ';'], '<' => ['REL', '<'], '=' => ['REL', '='], '>' => ['REL', '>'], '?' => ['CLOSE', '?'], '[' => ['OPEN', '['], ']' => ['CLOSE', ']'], '{' => ['OPEN', '{'], '}' => ['CLOSE', '}'], '|' => [{prefix => 'OPEN', infix => 'ORD', postfix => 'CLOSE'}, '|'], '_' => ['ORD', '_'], '#' => ['ORD', '#'], '$' => ['ORD', '$'], '%' => ['ORD', '%'], '&' => ['ORD', '&'], '^' => ['ORD', '^'], # accent for MathML '~' => ['ORD', '~'], # accent for MathML '`' => ['ORD', '`'], # accent for MathML # Ord symbols # '00A7' => ['ORD', '\\S'], # should not be an # '2135' => ['ORD', '\\aleph'], # should not be an # '210F' => ['ORD', '\\hbar'], # should not be an # '0131' => ['ORD', '\\imath'], # should not be an # '0237' => ['ORD', '\\jmath'], # should not be an '2113' => ['ORD', '\\ell'], '2118' => ['ORD', '\\wp'], '211C' => ['ORD', '\\Re'], '2111' => ['ORD', '\\Im'], '2202' => ['ORD', '\\partial'], '221E' => ['ORD', '\\infty'], '2032' => ['ORD', '\\prime'], '2205' => ['ORD', '\\emptyset'], '2207' => ['ORD', '\\nabla'], '221A' => ['ORD', '\\surd'], '22A4' => ['ORD', '\\top'], '22A5' => ['ORD', '\\bot'], '2220' => ['ORD', '\\angle'], '25B3' => ['ORD', '\\triangle'], '\\' => ['ORD', '\\backslash'], '2216' => ['ORD', '\\backslash'], '2200' => ['ORD', '\\forall'], '2203' => ['ORD', '\\exists'], '00AC' => ['ORD', '\\neg'], '266D' => ['ORD', '\\flat'], '266E' => ['ORD', '\\natural'], '266F' => ['ORD', '\\sharp'], '2663' => ['ORD', '\\clubsuit'], '2662' => ['ORD', '\\diamondsuit'], '2661' => ['ORD', '\\heartsuit'], '2660' => ['ORD', '\\spadesuit'], # Big ops '2210' => ['OP', '\\coprod'], '22C1' => ['OP', '\\bigvee'], '22C0' => ['OP', '\\bigwedge'], '2A04' => ['OP', '\\biguplus'], '22C2' => ['OP', '\\bigcap'], '22C3' => ['OP', '\\bigcup'], '222B' => ['OP', '\\int'], '220F' => ['OP', '\\prod'], '2211' => ['OP', '\\sum'], '2A02' => ['OP', '\\bigotimes'], '2A01' => ['OP', '\\bigoplus'], '2A00' => ['OP', '\\bigodot'], '222E' => ['OP', '\\oint'], '2A06' => ['OP', '\\bigsqcup'], '222B' => ['OP', '\\smallint'], # Binary operations '25C3' => ['BIN', '\\triangleleft'], '25B9' => ['BIN', '\\triangleright'], '25B3' => ['BIN', '\\bigtriangleup'], '25BD' => ['BIN', '\\bigtriangledown'], '2227' => ['BIN', '\\wedge'], '2228' => ['BIN', '\\vee'], '2229' => ['BIN', '\\cap'], '222A' => ['BIN', '\\cup'], '2021' => ['BIN', '\\ddagger'], '2020' => ['BIN', '\\dagger'], '2293' => ['BIN', '\\sqcap'], '2294' => ['BIN', '\\sqcup'], '228E' => ['BIN', '\\uplus'], '2A3F' => ['BIN', '\\amalg'], '22C4' => ['BIN', '\\diamond'], '2219' => ['BIN', '\\bullet'], '2240' => ['BIN', '\\wr'], '00F7' => ['BIN', '\\div'], '2299' => ['BIN', '\\odot'], '2298' => ['BIN', '\\oslash'], '2297' => ['BIN', '\\otimes'], '2296' => ['BIN', '\\ominus'], '2295' => ['BIN', '\\oplus'], '2213' => ['BIN', '\\mp'], '00B1' => ['BIN', '\\pm'], '2218' => ['BIN', '\\circ'], '25EF' => ['BIN', '\\bigcirc'], '2216' => ['BIN', '\\setminus'], '22C5' => ['BIN', '\\cdot'], '2217' => ['BIN', '\\ast'], '00D7' => ['BIN', '\\times'], '22C6' => ['BIN', '\\star'], # Relations '221D' => ['REL', '\\propto'], '2291' => ['REL', '\\sqsubseteq'], '2292' => ['REL', '\\sqsupseteq'], '2225' => ['REL', '\\parallel'], '2223' => ['REL', '\\mid'], '22A3' => ['REL', '\\dashv'], '22A2' => ['REL', '\\vdash'], '2264' => ['REL', '\\leq'], '2265' => ['REL', '\\geq'], '227B' => ['REL', '\\succ'], '227A' => ['REL', '\\prec'], '2248' => ['REL', '\\approx'], # '227D' => ['REL', '\\succeq'], # '227C' => ['REL', '\\preceq'], '2AB0' => ['REL', '\\succeq'], '2AAF' => ['REL', '\\preceq'], '2283' => ['REL', '\\supset'], '2282' => ['REL', '\\subset'], '2287' => ['REL', '\\supseteq'], '2286' => ['REL', '\\subseteq'], '2208' => ['REL', '\\in'], '220B' => ['REL', '\\ni'], '2209' => ['REL', '\\notin'], '220B' => ['REL', '\\owns'], '226B' => ['REL', '\\gg'], '226A' => ['REL', '\\ll'], '223C' => ['REL', '\\sim'], '2243' => ['REL', '\\simeq'], '22A5' => ['REL', '\\perp'], '2261' => ['REL', '\\equiv'], '224D' => ['REL', '\\asymp'], '2323' => ['REL', '\\smile'], '2322' => ['REL', '\\frown'], '2260' => ['REL', '\\ne'], '2245' => ['REL', '\\cong'], '2250' => ['REL', '\\doteq'], '22C8' => ['REL', '\\bowtie'], '22A8' => ['REL', '\\models'], '0338' => ['REL', '\\not'], # Arrows '21D4' => ['REL', '\\Leftrightarrow'], '21D0' => ['REL', '\\Leftarrow'], '21D2' => ['REL', '\\Rightarrow'], '2194' => ['REL', '\\leftrightarrow'], '2190' => ['REL', '\\leftarrow'], '2192' => ['REL', '\\rightarrow'], '21A6' => ['REL', '\\mapsto'], '21BC' => ['REL', '\\leftharpoonup'], '21BD' => ['REL', '\\leftharpoondown'], '21C0' => ['REL', '\\rightharpoonup'], '21C1' => ['REL', '\\rightharpoondown'], '2197' => ['REL', '\\nearrow'], '2198' => ['REL', '\\searrow'], '2196' => ['REL', '\\nwarrow'], '2199' => ['REL', '\\swarrow'], '21CC' => ['REL', '\\rightleftharpoons'], '21AA' => ['REL', '\\hookrightarrow'], '21A9' => ['REL', '\\hookleftarrow'], '27F5' => ['REL', '\\longleftarrow'], '27F8' => ['REL', '\\Longleftarrow'], '27F6' => ['REL', '\\longrightarrow'], '27F9' => ['REL', '\\Longrightarrow'], '27FA' => ['REL', '\\Longleftrightarrow'], '27F7' => ['REL', '\\longleftrightarrow'], '27FC' => ['REL', '\\longmapsto'], # Dots '2026' => ['INNER', '\\ldots'], '22EF' => ['INNER', '\\cdots'], '22EE' => ['ORD', '\\vdots'], '22F1' => ['INNER', '\\ddots'], '002E' => ['PUNCT', '\\ldotp','separator'], # '22C5' => ['PUNCT', '\\cdotp'], # already given above # '003A' => ['PUNCT', '\\colon'], # already given in dictionary # Over-under '203E' => ['ORD', '\\overline','stretchy'], '23AF' => ['ORD', '\\underline','stretchy'], '23DE' => ['ORD', '\\overbrace','stretchy'], '23DF' => ['ORD', '\\underbrace','stretchy'], # Accents '0301' => ['ORD', '\\acute','accent'], '0300' => ['ORD', '\\grave','accent'], '0308' => ['ORD', '\\ddot','accent'], '0303' => ['ORD', '\\tilde','accent stretchy'], '0304' => ['ORD', '\\bar','accent'], '0306' => ['ORD', '\\breve','accent'], '030C' => ['ORD', '\\check','accent'], '0302' => ['ORD', '\\hat','accent stretchy'], '20D7' => ['ORD', '\\vec','accent'], '0307' => ['ORD', '\\dot','accent'], '02CA' => ['ORD', '\\acute','accent'], '02CB' => ['ORD', '\\grave','accent'], '00A8' => ['ORD', '\\ddot','accent'], '02DC' => ['ORD', '\\tilde','accent stretchy'], '02C9' => ['ORD', '\\bar','accent'], '02D8' => ['ORD', '\\breve','accent'], '02C7' => ['ORD', '\\check','accent'], '02C6' => ['ORD', '\\hat','accent stretchy'], '02D9' => ['ORD', '\\dot','accent'], # Delimiters '2191' => ['REL', '\\uparrow'], '2193' => ['REL', '\\downarrow'], '2195' => ['REL', '\\updownarrow'], '21D1' => ['REL', '\\Uparrow'], '21D3' => ['REL', '\\Downarrow'], '21D5' => ['REL', '\\Updownarrow'], '2308' => ['OPEN', '\\lceil'], '2309' => ['CLOSE', '\\rceil'], '230A' => ['OPEN', '\\lfloor'], '230B' => ['CLOSE', '\\rfloor'], '23AA' => ['ORD', '\\bracevert'], '23B0' => ['OPEN', '\\lmoustache','fence stretchy symmetric'], '23B1' => ['CLOSE', '\\rmoustache','fence stretchy symmetric'], '27E8' => ['OPEN', '\\langle'], '27E9' => ['CLOSE', '\\rangle'], '27EE' => ['OPEN', '\\lgroup','fence stretchy symmetric'], '27EF' => ['CLOSE', '\\rgroup','fence stretchy symmetric'], # invisibles '2061' => ['ORD','function application'], '2062' => ['ORD','invisible times'], '2063' => ['ORD','invisible separator','separator'], '2064' => ['ORD','invisible plus'], # aliases '00AF' => ['ORD','horizontal line','accent stretchy'], '2015' => ['ORD','horizontal line','stretchy'], '2017' => ['ORD','horizontal line','stretchy'], '0332' => ['ORD','horizontal line','accent stretchy'], '2329' => ['OPEN','langle','fence stretchy symmetric'], '232A' => ['CLOSE','rangle','fence stretchy symmetric'], '2500' => ['ORD','horizontal line'], '2758' => ['REL','vertical separator','stretchy symmetric'], '3008' => ['OPEN','langle','fence stretchy symmetric'], '3009' => ['CLOSE','rangle','fence stretchy symmetric'], 'FE37' => ['ORD','horizontal brace down','accent stretchy'], 'FE38' => ['ORD','horizontal brace up','accent stretchy'], '00B7' => ['BIN','center dot'], '02B9' => ['ORD','prime'], '2022' => ['BIN','bullet'], '2044' => ['BIN','fraction slash'], '2305' => ['BIN','barwedge'], '2306' => ['BIN','doublebarwedge'], '25B5' => ['BIN','triangle'], '25BF' => ['BIN','triangledown'], '2A2F' => ['BIN','cross product'], ); %LSPACE = (ORD => 0, OP => 0, BIN => 3, REL => 4, OPEN => 0, CLOSE => 0, PUNCT => 0); %RSPACE = (ORD => 0, OP => 0, BIN => 3, REL => 4, OPEN => 0, CLOSE => 0, PUNCT => 3); @CLASS = ( '[0,0,TEXCLASS.ORD]' => 'ORD', '[1,1,TEXCLASS.ORD]' => 'ORD11', '[2,1,TEXCLASS.ORD]' => 'ORD21', '[0,2,TEXCLASS.ORD]' => 'ORD02', '[5,5,TEXCLASS.ORD]' => 'ORD55', '[1,2,TEXCLASS.OP,{largeop: true, movablelimits: true, symmetric: true}]' => 'OP', '[1,2,TEXCLASS.OP,{largeop: true, movablelimits: true}]' => 'OPFIXED', '[0,1,TEXCLASS.OP,{largeop: true, symmetric: true}]' => 'INTEGRAL', '[1,2,TEXCLASS.OP,{largeop: true, symmetric: true}]' => 'INTEGRAL2', '[3,3,TEXCLASS.BIN]' => 'BIN3', '[4,4,TEXCLASS.BIN]' => 'BIN4', '[0,1,TEXCLASS.BIN]' => 'BIN01', '[4,4,TEXCLASS.BIN,{stretchy: true}]' => 'TALLBIN', '[4,4,TEXCLASS.BIN,{largeop: true, movablelimits: true}]' => 'BINOP', '[5,5,TEXCLASS.REL]' => 'REL', '[1,1,TEXCLASS.REL,{stretchy: true}]' => 'REL1', '[4,4,TEXCLASS.REL]' => 'REL4', '[5,5,TEXCLASS.REL,{stretchy: true}]' => 'WIDEREL', '[5,5,TEXCLASS.REL,{accent: true, stretchy: true}]' => 'RELACCENT', '[0,0,TEXCLASS.OPEN,{fence: true, stretchy: true, symmetric: true}]' => 'OPEN', '[0,0,TEXCLASS.CLOSE,{fence: true, stretchy: true, symmetric: true}]' => 'CLOSE', '[0,0,TEXCLASS.INNER]' => 'INNER', '[0,3,TEXCLASS.PUNCT]' => 'PUNCT', '[0,0,TEXCLASS.ORD,{accent: true}]' => 'ACCENT', '[0,0,TEXCLASS.ORD,{accent: true, stretchy: true}]' => 'WIDEACCENT', ); while (@CLASS) { my $def = shift(@CLASS), $name = shift(@CLASS); $CLASS{$def} = $name; $CLASSDEF{$name} = $def; push(@CLASSES,$name); } foreach $form (reverse(sort(keys %op))) { foreach $id (sort(keys %{$op{$form}})) { $ID = $id; $UID = $id; $UID =~ s/([\\'])/\\\1/g; if ($ID =~ m/^&#x([0-9A-F]+);$/i) {$ID = $1; while (length($ID) < 4) {$ID = "0$ID"}; $UID = "\\u$ID"} $UID =~ s/&#x([0-9A-F]{4});/\\u\1/g; $UID =~ s/&#x([0-9A-F]{3});/\\u0\1/g; ($lspace,$rspace,$attributes,$name) = @{$op{$form}{$id}}; $class = ($TEX{$ID} ? $TEX{$ID}[0] : undef); $class = $class->{$form} if ref($class) eq 'HASH'; if (!($hasClass = defined($class))) { $class = "ORD"; $class = "REL" if $lspace == 5; $class = "BIN" if $lspace == 4 || $lspace == 3; $class = "ORD" if $lspace == 0 && $rspace == 0; $class = "OPEN" if $attributes =~ m/fence/ && $name =~ m/open|left/i; $class = "CLOSE" if $attributes =~ m/fence/ && $name =~ m/close|right/i; $class = "OP" if $attributes =~ m/largeop/; $class = "BIN" if length($ID) == 2; } @DATA = ($lspace,$rspace,"TEXCLASS.$class"); push(@DATA,"{".join(': true, ',sort(split(/ /,$attributes))).": true}") if $attributes; $DATA = "[".join(",",@DATA)."]"; $DATA = "MO.$CLASS{$DATA}" if defined $CLASS{$DATA}; $DATA = sprintf("%-30s"," '$UID': $DATA,")." // $name\n"; $USED{$ID} = 1; if ($hasClass) {$unicode = "Main"} else {$unicode = GetRange($ID)} $range{$unicode} = {} unless defined $range{$unicode}; $range{$unicode}{$form} = [] unless defined $range{$unicode}{$form}; push(@{$range{$unicode}{$form}},$DATA); } if ($form eq 'infix') { foreach $ID (sort(keys %TEX)) { unless ($USED{$ID}) { next if $onlyTeX && !$TEX{$ID}; @DATA = ($LSPACE{$TEX{$ID}[0]},$RSPACE{$TEX{$ID}[0]},"TEXCLASS.$TEX{$ID}[0]"); push(@DATA,"{".join(': true, ',sort(split(/ /,$TEX{$ID}[2]))).": true}") if $TEX{$ID}[2]; $DATA = "[".join(",",@DATA)."]"; $DATA = "MO.$CLASS{$DATA}" if defined $CLASS{$DATA}; $UID = $ID; $UID = "\\u$ID" if length($UID) == 4; $DATA = sprintf("%-30s"," '$UID': $DATA,")." // $TEX{$ID}[1]\n"; $range{Main} = {} unless defined $range{Main}; $range{Main}{infix} = [] unless defined $range{Main}{infix}; push(@{$range{Main}{infix}},$DATA); } } } } mkdir "optable" unless -e "optable"; @RANGEDEF = (); foreach $def (@RANGES) { my ($name,$l,$u,$class) = @$def; if (defined $range{$name}) { push(@RANGEDEF,"[".sprintf("0x%X,0x%X",$l,$u).",TEXCLASS.$class,\"$name\"]"); } elsif ($class ne 'REL') { push(@RANGEDEF,"[".sprintf("0x%X,0x%X",$l,$u).",TEXCLASS.$class]"); } } foreach $unicode (sort(keys %range)) { print "$unicode..."; @forms = (); if ($unicode eq "Main") { foreach $form (reverse(sort(keys %{$range{$unicode}}))) { $lines = $range{$unicode}{$form}; $lines->[scalar(@$lines)-1] =~ s!\, ( *)//! \1//!; push(@forms," $form: {\n".join("",@$lines)." }"); } open(JSFILE,">optable.js") || die "Can't write optable.js"; print JSFILE " var MO = {\n"; print JSFILE " ",join(",\n ",map {sprintf("%-11s",$_.":")." ".$CLASSDEF{$_}} @CLASSES),"\n"; print JSFILE " };\n\n"; print JSFILE " MML.mo.Augment({\n"; print JSFILE " SPACE: [\n"; print JSFILE " '0em',\n"; print JSFILE " '0.1111em',\n"; print JSFILE " '0.1667em',\n"; print JSFILE " '0.2222em',\n"; print JSFILE " '0.2667em',\n"; print JSFILE " '0.3333em'\n"; print JSFILE " ],\n"; print JSFILE " RANGES: [\n"; print JSFILE " ",join(",\n ",@RANGEDEF),"\n"; print JSFILE " ],\n"; print JSFILE " OPTABLE: {\n"; print JSFILE join(",\n",@forms),"\n"; print JSFILE " }\n"; print JSFILE " },{\n"; print JSFILE " OPTYPES: MO\n"; print JSFILE " });\n"; close(JSFILE); } else { foreach $form (reverse(sort(keys %{$range{$unicode}}))) { $lines = $range{$unicode}{$form}; $lines->[scalar(@$lines)-1] =~ s!, ( *)//! \1//!; push(@forms," $form: {\n".join("",@$lines)." }"); } open(JSFILE,">optable/$unicode.js") || die "Can't write optable/$unicode.js"; print JSFILE "/*************************************************************\n"; print JSFILE " *\n"; print JSFILE " * MathJax/jax/output/HTML-CSS/optable/$unicode.js\n"; print JSFILE " *\n"; print JSFILE " * Copyright (c) 2010 Design Science, Inc.\n"; print JSFILE " *\n"; print JSFILE " * Licensed under the Apache License, Version 2.0 (the \"License\");\n"; print JSFILE " * you may not use this file except in compliance with the License.\n"; print JSFILE " * You may obtain a copy of the License at\n"; print JSFILE " *\n"; print JSFILE " * http://www.apache.org/licenses/LICENSE-2.0\n"; print JSFILE " *\n"; print JSFILE " * Unless required by applicable law or agreed to in writing, software\n"; print JSFILE " * distributed under the License is distributed on an \"AS IS\" BASIS,\n"; print JSFILE " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"; print JSFILE " * See the License for the specific language governing permissions and\n"; print JSFILE " * limitations under the License.\n"; print JSFILE " *\n"; print JSFILE " */\n\n"; print JSFILE "(function (MML) {\n"; print JSFILE " var MO = MML.mo.OPTYPES;\n"; print JSFILE " var TEXCLASS = MML.TEXCLASS;\n\n"; print JSFILE " MathJax.Hub.Insert(MML.mo.prototype,{\n"; print JSFILE " OPTABLE: {\n"; print JSFILE join(",\n",@forms),"\n"; print JSFILE " }\n"; print JSFILE " });\n\n"; print JSFILE " MathJax.Ajax.loadComplete(MML.optableDir+\"/$unicode.js\");\n\n"; print JSFILE "})(MathJax.ElementJax.mml);\n"; close(JSFILE); } print "\n"; }