da03 commited on
Commit
b498cbf
1 Parent(s): a3459d2
app.py CHANGED
@@ -12,6 +12,8 @@ import diffusers
12
  from diffusers import DDPMPipeline
13
  from transformers import AutoTokenizer, AutoModel
14
 
 
 
15
  tz = timezone('EST')
16
 
17
  API_ENDPOINT = os.getenv('API_ENDPOINT')
@@ -83,8 +85,13 @@ with gr.Blocks() as demo:
83
  current_time = datetime.now(tz)
84
  print (current_time, formula)
85
  data = {'formula': formula, 'api_key': API_KEY}
86
- latex = formula # TODO: normalize
87
- encoder_hidden_states = forward_encoder(latex)
 
 
 
 
 
88
 
89
  try:
90
  i = 0
 
12
  from diffusers import DDPMPipeline
13
  from transformers import AutoTokenizer, AutoModel
14
 
15
+ from utils import normalize_formula
16
+
17
  tz = timezone('EST')
18
 
19
  API_ENDPOINT = os.getenv('API_ENDPOINT')
 
85
  current_time = datetime.now(tz)
86
  print (current_time, formula)
87
  data = {'formula': formula, 'api_key': API_KEY}
88
+ try:
89
+ formula_normalized = normalize_formula(formula)
90
+ except Exception as e:
91
+ print (e)
92
+ formula_normalized = formula
93
+ print ('normalized', formula_normalized)
94
+ encoder_hidden_states = forward_encoder(formula_normalized)
95
 
96
  try:
97
  i = 0
katex/LICENSE.txt ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Khan Academy
4
+
5
+ This software also uses portions of the underscore.js project, which is
6
+ MIT licensed with the following copyright:
7
+
8
+ Copyright (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative
9
+ Reporters & Editors
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
katex/README.md ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # [<img src="https://khan.github.io/KaTeX/katex-logo.svg" width="130" alt="KaTeX">](https://khan.github.io/KaTeX/) [![Build Status](https://travis-ci.org/Khan/KaTeX.svg?branch=master)](https://travis-ci.org/Khan/KaTeX)
2
+
3
+ [![Join the chat at https://gitter.im/Khan/KaTeX](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Khan/KaTeX?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
+
5
+ KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
6
+
7
+ * **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://jsperf.com/katex-vs-mathjax/).
8
+ * **Print quality:** KaTeX’s layout is based on Donald Knuth’s TeX, the gold standard for math typesetting.
9
+ * **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources.
10
+ * **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML.
11
+
12
+ KaTeX supports all major browsers, including Chrome, Safari, Firefox, Opera, and IE 8 - IE 11. A list of supported commands can be on the [wiki](https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX).
13
+
14
+ ## Usage
15
+
16
+ You can [download KaTeX](https://github.com/khan/katex/releases) and host it on your server or include the `katex.min.js` and `katex.min.css` files on your page directly from a CDN:
17
+
18
+ ```html
19
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.css">
20
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.js"></script>
21
+ ```
22
+
23
+ #### In-browser rendering
24
+
25
+ Call `katex.render` with a TeX expression and a DOM element to render into:
26
+
27
+ ```js
28
+ katex.render("c = \\pm\\sqrt{a^2 + b^2}", element);
29
+ ```
30
+
31
+ If KaTeX can't parse the expression, it throws a `katex.ParseError` error.
32
+
33
+ #### Server side rendering or rendering to a string
34
+
35
+ To generate HTML on the server or to generate an HTML string of the rendered math, you can use `katex.renderToString`:
36
+
37
+ ```js
38
+ var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}");
39
+ // '<span class="katex">...</span>'
40
+ ```
41
+
42
+ Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression.
43
+
44
+ #### Rendering options
45
+
46
+ You can provide an object of options as the last argument to `katex.render` and `katex.renderToString`. Available options are:
47
+
48
+ - `displayMode`: `boolean`. If `true` the math will be rendered in display mode, which will put the math in display style (so `\int` and `\sum` are large, for example), and will center the math on the page on its own line. If `false` the math will be rendered in inline mode. (default: `false`)
49
+ - `throwOnError`: `boolean`. If `true`, KaTeX will throw a `ParseError` when it encounters an unsupported command. If `false`, KaTeX will render the unsupported command as text in the color given by `errorColor`. (default: `true`)
50
+ - `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`)
51
+
52
+ For example:
53
+
54
+ ```js
55
+ katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { displayMode: true });
56
+ ```
57
+
58
+ #### Automatic rendering of math on a page
59
+
60
+ Math on the page can be automatically rendered using the auto-render extension. See [the Auto-render README](contrib/auto-render/README.md) for more information.
61
+
62
+ ## Contributing
63
+
64
+ See [CONTRIBUTING.md](CONTRIBUTING.md)
65
+
66
+ ## License
67
+
68
+ KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT).
katex/cli.js ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ // Simple CLI for KaTeX.
3
+ // Reads TeX from stdin, outputs HTML to stdout.
4
+ /* eslint no-console:0 */
5
+
6
+ var katex = require("./");
7
+ var input = "";
8
+
9
+ // Skip the first two args, which are just "node" and "cli.js"
10
+ var args = process.argv.slice(2);
11
+
12
+ if (args.indexOf("--help") !== -1) {
13
+ console.log(process.argv[0] + " " + process.argv[1] +
14
+ " [ --help ]" +
15
+ " [ --display-mode ]");
16
+
17
+ console.log("\n" +
18
+ "Options:");
19
+ console.log(" --help Display this help message");
20
+ console.log(" --display-mode Render in display mode (not inline mode)");
21
+ process.exit();
22
+ }
23
+
24
+ process.stdin.on("data", function(chunk) {
25
+ input += chunk.toString();
26
+ });
27
+
28
+ process.stdin.on("end", function() {
29
+ var options = { displayMode: args.indexOf("--display-mode") !== -1 };
30
+ var output = katex.renderToString(input, options);
31
+ console.log(output);
32
+ });
katex/katex.js ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint no-console:0 */
2
+ /**
3
+ * This is the main entry point for KaTeX. Here, we expose functions for
4
+ * rendering expressions either to DOM nodes or to markup strings.
5
+ *
6
+ * We also expose the ParseError class to check if errors thrown from KaTeX are
7
+ * errors in the expression, or errors in javascript handling.
8
+ */
9
+
10
+ var ParseError = require("./src/ParseError");
11
+ var Settings = require("./src/Settings");
12
+
13
+ var buildTree = require("./src/buildTree");
14
+ var parseTree = require("./src/parseTree");
15
+ var utils = require("./src/utils");
16
+
17
+ /**
18
+ * Parse and build an expression, and place that expression in the DOM node
19
+ * given.
20
+ */
21
+ var render = function(expression, baseNode, options) {
22
+ utils.clearNode(baseNode);
23
+
24
+ var settings = new Settings(options);
25
+
26
+ var tree = parseTree(expression, settings);
27
+ var node = buildTree(tree, expression, settings).toNode();
28
+
29
+ baseNode.appendChild(node);
30
+ };
31
+
32
+ // KaTeX's styles don't work properly in quirks mode. Print out an error, and
33
+ // disable rendering.
34
+ if (typeof document !== "undefined") {
35
+ if (document.compatMode !== "CSS1Compat") {
36
+ typeof console !== "undefined" && console.warn(
37
+ "Warning: KaTeX doesn't work in quirks mode. Make sure your " +
38
+ "website has a suitable doctype.");
39
+
40
+ render = function() {
41
+ throw new ParseError("KaTeX doesn't work in quirks mode.");
42
+ };
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Parse and build an expression, and return the markup for that.
48
+ */
49
+ var renderToString = function(expression, options) {
50
+ var settings = new Settings(options);
51
+
52
+ var tree = parseTree(expression, settings);
53
+ return buildTree(tree, expression, settings).toMarkup();
54
+ };
55
+
56
+ /**
57
+ * Parse an expression and return the parse tree.
58
+ */
59
+ var generateParseTree = function(expression, options) {
60
+ var settings = new Settings(options);
61
+ return parseTree(expression, settings);
62
+ };
63
+
64
+ module.exports = {
65
+ render: render,
66
+ renderToString: renderToString,
67
+ /**
68
+ * NOTE: This method is not currently recommended for public use.
69
+ * The internal tree representation is unstable and is very likely
70
+ * to change. Use at your own risk.
71
+ */
72
+ __parse: generateParseTree,
73
+ ParseError: ParseError,
74
+ };
katex/package.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_args": [
3
+ [
4
+ "katex",
5
+ "/home/srush/Projects/im2latex"
6
+ ]
7
+ ],
8
+ "_from": "katex@latest",
9
+ "_id": "katex@0.6.0",
10
+ "_inCache": true,
11
+ "_installable": true,
12
+ "_location": "/katex",
13
+ "_nodeVersion": "4.2.1",
14
+ "_npmOperationalInternal": {
15
+ "host": "packages-12-west.internal.npmjs.com",
16
+ "tmp": "tmp/katex-0.6.0.tgz_1460769444991_0.38667152682319283"
17
+ },
18
+ "_npmUser": {
19
+ "email": "kevinb7@gmail.com",
20
+ "name": "kevinbarabash"
21
+ },
22
+ "_npmVersion": "2.15.2",
23
+ "_phantomChildren": {},
24
+ "_requested": {
25
+ "name": "katex",
26
+ "raw": "katex",
27
+ "rawSpec": "",
28
+ "scope": null,
29
+ "spec": "latest",
30
+ "type": "tag"
31
+ },
32
+ "_requiredBy": [
33
+ "#USER"
34
+ ],
35
+ "_resolved": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz",
36
+ "_shasum": "12418e09121c05c92041b6b3b9fb6bab213cb6f3",
37
+ "_shrinkwrap": null,
38
+ "_spec": "katex",
39
+ "_where": "/home/srush/Projects/im2latex",
40
+ "bin": {
41
+ "katex": "cli.js"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/Khan/KaTeX/issues"
45
+ },
46
+ "dependencies": {
47
+ "match-at": "^0.1.0"
48
+ },
49
+ "description": "Fast math typesetting for the web.",
50
+ "devDependencies": {
51
+ "browserify": "^10.2.4",
52
+ "clean-css": "~2.2.15",
53
+ "eslint": "^1.10.2",
54
+ "express": "~3.3.3",
55
+ "glob": "^5.0.15",
56
+ "jasmine": "^2.3.2",
57
+ "jasmine-core": "^2.3.4",
58
+ "js-yaml": "^3.3.1",
59
+ "jspngopt": "^0.1.0",
60
+ "less": "~1.7.5",
61
+ "nomnom": "^1.8.1",
62
+ "pako": "0.2.7",
63
+ "selenium-webdriver": "^2.46.1",
64
+ "uglify-js": "~2.4.15"
65
+ },
66
+ "directories": {},
67
+ "dist": {
68
+ "shasum": "12418e09121c05c92041b6b3b9fb6bab213cb6f3",
69
+ "tarball": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz"
70
+ },
71
+ "files": [
72
+ "cli.js",
73
+ "dist/",
74
+ "katex.js",
75
+ "src/"
76
+ ],
77
+ "gitHead": "b94fc6534d5c23f944906a52a592bee4e0090665",
78
+ "homepage": "https://github.com/Khan/KaTeX#readme",
79
+ "license": "MIT",
80
+ "main": "katex.js",
81
+ "maintainers": [
82
+ {
83
+ "name": "kevinbarabash",
84
+ "email": "kevinb7@gmail.com"
85
+ },
86
+ {
87
+ "name": "spicyj",
88
+ "email": "ben@benalpert.com"
89
+ },
90
+ {
91
+ "name": "xymostech",
92
+ "email": "xymostech@gmail.com"
93
+ }
94
+ ],
95
+ "name": "katex",
96
+ "optionalDependencies": {},
97
+ "readme": "ERROR: No README data found!",
98
+ "repository": {
99
+ "type": "git",
100
+ "url": "git://github.com/Khan/KaTeX.git"
101
+ },
102
+ "scripts": {
103
+ "prepublish": "make dist",
104
+ "start": "node server.js",
105
+ "test": "make lint test"
106
+ },
107
+ "version": "0.6.0"
108
+ }
katex/src/Lexer.js ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * The Lexer class handles tokenizing the input in various ways. Since our
3
+ * parser expects us to be able to backtrack, the lexer allows lexing from any
4
+ * given starting point.
5
+ *
6
+ * Its main exposed function is the `lex` function, which takes a position to
7
+ * lex from and a type of token to lex. It defers to the appropriate `_innerLex`
8
+ * function.
9
+ *
10
+ * The various `_innerLex` functions perform the actual lexing of different
11
+ * kinds.
12
+ */
13
+
14
+ var matchAt = require("../../match-at");
15
+
16
+ var ParseError = require("./ParseError");
17
+
18
+ // The main lexer class
19
+ function Lexer(input) {
20
+ this._input = input;
21
+ }
22
+
23
+ // The resulting token returned from `lex`.
24
+ function Token(text, data, position) {
25
+ this.text = text;
26
+ this.data = data;
27
+ this.position = position;
28
+ }
29
+
30
+ /* The following tokenRegex
31
+ * - matches typical whitespace (but not NBSP etc.) using its first group
32
+ * - matches symbol combinations which result in a single output character
33
+ * - does not match any control character \x00-\x1f except whitespace
34
+ * - does not match a bare backslash
35
+ * - matches any ASCII character except those just mentioned
36
+ * - does not match the BMP private use area \uE000-\uF8FF
37
+ * - does not match bare surrogate code units
38
+ * - matches any BMP character except for those just described
39
+ * - matches any valid Unicode surrogate pair
40
+ * - matches a backslash followed by one or more letters
41
+ * - matches a backslash followed by any BMP character, including newline
42
+ * Just because the Lexer matches something doesn't mean it's valid input:
43
+ * If there is no matching function or symbol definition, the Parser will
44
+ * still reject the input.
45
+ */
46
+ var tokenRegex = new RegExp(
47
+ "([ \r\n\t]+)|(" + // whitespace
48
+ "---?" + // special combinations
49
+ "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint
50
+ "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair
51
+ "|\\\\(?:[a-zA-Z]+|[^\uD800-\uDFFF])" + // function name
52
+ ")"
53
+ );
54
+
55
+ var whitespaceRegex = /\s*/;
56
+
57
+ /**
58
+ * This function lexes a single normal token. It takes a position and
59
+ * whether it should completely ignore whitespace or not.
60
+ */
61
+ Lexer.prototype._innerLex = function(pos, ignoreWhitespace) {
62
+ var input = this._input;
63
+ if (pos === input.length) {
64
+ return new Token("EOF", null, pos);
65
+ }
66
+ var match = matchAt(tokenRegex, input, pos);
67
+ if (match === null) {
68
+ throw new ParseError(
69
+ "Unexpected character: '" + input[pos] + "'",
70
+ this, pos);
71
+ } else if (match[2]) { // matched non-whitespace
72
+ return new Token(match[2], null, pos + match[2].length);
73
+ } else if (ignoreWhitespace) {
74
+ return this._innerLex(pos + match[1].length, true);
75
+ } else { // concatenate whitespace to a single space
76
+ return new Token(" ", null, pos + match[1].length);
77
+ }
78
+ };
79
+
80
+ // A regex to match a CSS color (like #ffffff or BlueViolet)
81
+ var cssColor = /#[a-z0-9]+|[a-z]+/i;
82
+
83
+ /**
84
+ * This function lexes a CSS color.
85
+ */
86
+ Lexer.prototype._innerLexColor = function(pos) {
87
+ var input = this._input;
88
+
89
+ // Ignore whitespace
90
+ var whitespace = matchAt(whitespaceRegex, input, pos)[0];
91
+ pos += whitespace.length;
92
+
93
+ var match;
94
+ if ((match = matchAt(cssColor, input, pos))) {
95
+ // If we look like a color, return a color
96
+ return new Token(match[0], null, pos + match[0].length);
97
+ } else {
98
+ throw new ParseError("Invalid color", this, pos);
99
+ }
100
+ };
101
+
102
+ // A regex to match a dimension. Dimensions look like
103
+ // "1.2em" or ".4pt" or "1 ex"
104
+ var sizeRegex = /(-?)\s*(\d+(?:\.\d*)?|\.\d+)\s*([a-z]{2})/;
105
+
106
+ /**
107
+ * This function lexes a dimension.
108
+ */
109
+ Lexer.prototype._innerLexSize = function(pos) {
110
+ var input = this._input;
111
+
112
+ // Ignore whitespace
113
+ var whitespace = matchAt(whitespaceRegex, input, pos)[0];
114
+ pos += whitespace.length;
115
+
116
+ var match;
117
+ if ((match = matchAt(sizeRegex, input, pos))) {
118
+ var unit = match[3];
119
+ // We only currently handle "em" and "ex" units
120
+ // if (unit !== "em" && unit !== "ex") {
121
+ // throw new ParseError("Invalid unit: '" + unit + "'", this, pos);
122
+ // }
123
+ return new Token(match[0], {
124
+ number: +(match[1] + match[2]),
125
+ unit: unit,
126
+ }, pos + match[0].length);
127
+ }
128
+
129
+ throw new ParseError("Invalid size", this, pos);
130
+ };
131
+
132
+ /**
133
+ * This function lexes a string of whitespace.
134
+ */
135
+ Lexer.prototype._innerLexWhitespace = function(pos) {
136
+ var input = this._input;
137
+
138
+ var whitespace = matchAt(whitespaceRegex, input, pos)[0];
139
+ pos += whitespace.length;
140
+
141
+ return new Token(whitespace[0], null, pos);
142
+ };
143
+
144
+ /**
145
+ * This function lexes a single token starting at `pos` and of the given mode.
146
+ * Based on the mode, we defer to one of the `_innerLex` functions.
147
+ */
148
+ Lexer.prototype.lex = function(pos, mode) {
149
+ if (mode === "math") {
150
+ return this._innerLex(pos, true);
151
+ } else if (mode === "text") {
152
+ return this._innerLex(pos, false);
153
+ } else if (mode === "color") {
154
+ return this._innerLexColor(pos);
155
+ } else if (mode === "size") {
156
+ return this._innerLexSize(pos);
157
+ } else if (mode === "whitespace") {
158
+ return this._innerLexWhitespace(pos);
159
+ }
160
+ };
161
+
162
+ module.exports = Lexer;
katex/src/Options.js ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file contains information about the options that the Parser carries
3
+ * around with it while parsing. Data is held in an `Options` object, and when
4
+ * recursing, a new `Options` object can be created with the `.with*` and
5
+ * `.reset` functions.
6
+ */
7
+
8
+ /**
9
+ * This is the main options class. It contains the style, size, color, and font
10
+ * of the current parse level. It also contains the style and size of the parent
11
+ * parse level, so size changes can be handled efficiently.
12
+ *
13
+ * Each of the `.with*` and `.reset` functions passes its current style and size
14
+ * as the parentStyle and parentSize of the new options class, so parent
15
+ * handling is taken care of automatically.
16
+ */
17
+ function Options(data) {
18
+ this.style = data.style;
19
+ this.color = data.color;
20
+ this.size = data.size;
21
+ this.phantom = data.phantom;
22
+ this.font = data.font;
23
+
24
+ if (data.parentStyle === undefined) {
25
+ this.parentStyle = data.style;
26
+ } else {
27
+ this.parentStyle = data.parentStyle;
28
+ }
29
+
30
+ if (data.parentSize === undefined) {
31
+ this.parentSize = data.size;
32
+ } else {
33
+ this.parentSize = data.parentSize;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Returns a new options object with the same properties as "this". Properties
39
+ * from "extension" will be copied to the new options object.
40
+ */
41
+ Options.prototype.extend = function(extension) {
42
+ var data = {
43
+ style: this.style,
44
+ size: this.size,
45
+ color: this.color,
46
+ parentStyle: this.style,
47
+ parentSize: this.size,
48
+ phantom: this.phantom,
49
+ font: this.font,
50
+ };
51
+
52
+ for (var key in extension) {
53
+ if (extension.hasOwnProperty(key)) {
54
+ data[key] = extension[key];
55
+ }
56
+ }
57
+
58
+ return new Options(data);
59
+ };
60
+
61
+ /**
62
+ * Create a new options object with the given style.
63
+ */
64
+ Options.prototype.withStyle = function(style) {
65
+ return this.extend({
66
+ style: style,
67
+ });
68
+ };
69
+
70
+ /**
71
+ * Create a new options object with the given size.
72
+ */
73
+ Options.prototype.withSize = function(size) {
74
+ return this.extend({
75
+ size: size,
76
+ });
77
+ };
78
+
79
+ /**
80
+ * Create a new options object with the given color.
81
+ */
82
+ Options.prototype.withColor = function(color) {
83
+ return this.extend({
84
+ color: color,
85
+ });
86
+ };
87
+
88
+ /**
89
+ * Create a new options object with "phantom" set to true.
90
+ */
91
+ Options.prototype.withPhantom = function() {
92
+ return this.extend({
93
+ phantom: true,
94
+ });
95
+ };
96
+
97
+ /**
98
+ * Create a new options objects with the give font.
99
+ */
100
+ Options.prototype.withFont = function(font) {
101
+ return this.extend({
102
+ font: font,
103
+ });
104
+ };
105
+
106
+ /**
107
+ * Create a new options object with the same style, size, and color. This is
108
+ * used so that parent style and size changes are handled correctly.
109
+ */
110
+ Options.prototype.reset = function() {
111
+ return this.extend({});
112
+ };
113
+
114
+ /**
115
+ * A map of color names to CSS colors.
116
+ * TODO(emily): Remove this when we have real macros
117
+ */
118
+ var colorMap = {
119
+ "katex-blue": "#6495ed",
120
+ "katex-orange": "#ffa500",
121
+ "katex-pink": "#ff00af",
122
+ "katex-red": "#df0030",
123
+ "katex-green": "#28ae7b",
124
+ "katex-gray": "gray",
125
+ "katex-purple": "#9d38bd",
126
+ "katex-blueA": "#c7e9f1",
127
+ "katex-blueB": "#9cdceb",
128
+ "katex-blueC": "#58c4dd",
129
+ "katex-blueD": "#29abca",
130
+ "katex-blueE": "#1c758a",
131
+ "katex-tealA": "#acead7",
132
+ "katex-tealB": "#76ddc0",
133
+ "katex-tealC": "#5cd0b3",
134
+ "katex-tealD": "#55c1a7",
135
+ "katex-tealE": "#49a88f",
136
+ "katex-greenA": "#c9e2ae",
137
+ "katex-greenB": "#a6cf8c",
138
+ "katex-greenC": "#83c167",
139
+ "katex-greenD": "#77b05d",
140
+ "katex-greenE": "#699c52",
141
+ "katex-goldA": "#f7c797",
142
+ "katex-goldB": "#f9b775",
143
+ "katex-goldC": "#f0ac5f",
144
+ "katex-goldD": "#e1a158",
145
+ "katex-goldE": "#c78d46",
146
+ "katex-redA": "#f7a1a3",
147
+ "katex-redB": "#ff8080",
148
+ "katex-redC": "#fc6255",
149
+ "katex-redD": "#e65a4c",
150
+ "katex-redE": "#cf5044",
151
+ "katex-maroonA": "#ecabc1",
152
+ "katex-maroonB": "#ec92ab",
153
+ "katex-maroonC": "#c55f73",
154
+ "katex-maroonD": "#a24d61",
155
+ "katex-maroonE": "#94424f",
156
+ "katex-purpleA": "#caa3e8",
157
+ "katex-purpleB": "#b189c6",
158
+ "katex-purpleC": "#9a72ac",
159
+ "katex-purpleD": "#715582",
160
+ "katex-purpleE": "#644172",
161
+ "katex-mintA": "#f5f9e8",
162
+ "katex-mintB": "#edf2df",
163
+ "katex-mintC": "#e0e5cc",
164
+ "katex-grayA": "#fdfdfd",
165
+ "katex-grayB": "#f7f7f7",
166
+ "katex-grayC": "#eeeeee",
167
+ "katex-grayD": "#dddddd",
168
+ "katex-grayE": "#cccccc",
169
+ "katex-grayF": "#aaaaaa",
170
+ "katex-grayG": "#999999",
171
+ "katex-grayH": "#555555",
172
+ "katex-grayI": "#333333",
173
+ "katex-kaBlue": "#314453",
174
+ "katex-kaGreen": "#639b24",
175
+ };
176
+
177
+ /**
178
+ * Gets the CSS color of the current options object, accounting for the
179
+ * `colorMap`.
180
+ */
181
+ Options.prototype.getColor = function() {
182
+ if (this.phantom) {
183
+ return "transparent";
184
+ } else {
185
+ return colorMap[this.color] || this.color;
186
+ }
187
+ };
188
+
189
+ module.exports = Options;
katex/src/ParseError.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This is the ParseError class, which is the main error thrown by KaTeX
3
+ * functions when something has gone wrong. This is used to distinguish internal
4
+ * errors from errors in the expression that the user provided.
5
+ */
6
+ function ParseError(message, lexer, position) {
7
+ var error = "KaTeX parse error: " + message;
8
+
9
+ if (lexer !== undefined && position !== undefined) {
10
+ // If we have the input and a position, make the error a bit fancier
11
+
12
+ // Prepend some information
13
+ error += " at position " + position + ": ";
14
+
15
+ // Get the input
16
+ var input = lexer._input;
17
+ // Insert a combining underscore at the correct position
18
+ input = input.slice(0, position) + "\u0332" +
19
+ input.slice(position);
20
+
21
+ // Extract some context from the input and add it to the error
22
+ var begin = Math.max(0, position - 15);
23
+ var end = position + 15;
24
+ error += input.slice(begin, end);
25
+ }
26
+
27
+ // Some hackery to make ParseError a prototype of Error
28
+ // See http://stackoverflow.com/a/8460753
29
+ var self = new Error(error);
30
+ self.name = "ParseError";
31
+ self.__proto__ = ParseError.prototype;
32
+
33
+ self.position = position;
34
+ return self;
35
+ }
36
+
37
+ // More hackery
38
+ ParseError.prototype.__proto__ = Error.prototype;
39
+
40
+ module.exports = ParseError;
katex/src/Parser.js ADDED
@@ -0,0 +1,798 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint no-constant-condition:0 */
2
+ var functions = require("./functions");
3
+ var environments = require("./environments");
4
+ var Lexer = require("./Lexer");
5
+ var symbols = require("./symbols");
6
+ var utils = require("./utils");
7
+
8
+ var parseData = require("./parseData");
9
+ var ParseError = require("./ParseError");
10
+
11
+ global_str = ""
12
+
13
+ /**
14
+ * This file contains the parser used to parse out a TeX expression from the
15
+ * input. Since TeX isn't context-free, standard parsers don't work particularly
16
+ * well.
17
+ *
18
+ * The strategy of this parser is as such:
19
+ *
20
+ * The main functions (the `.parse...` ones) take a position in the current
21
+ * parse string to parse tokens from. The lexer (found in Lexer.js, stored at
22
+ * this.lexer) also supports pulling out tokens at arbitrary places. When
23
+ * individual tokens are needed at a position, the lexer is called to pull out a
24
+ * token, which is then used.
25
+ *
26
+ * The parser has a property called "mode" indicating the mode that
27
+ * the parser is currently in. Currently it has to be one of "math" or
28
+ * "text", which denotes whether the current environment is a math-y
29
+ * one or a text-y one (e.g. inside \text). Currently, this serves to
30
+ * limit the functions which can be used in text mode.
31
+ *
32
+ * The main functions then return an object which contains the useful data that
33
+ * was parsed at its given point, and a new position at the end of the parsed
34
+ * data. The main functions can call each other and continue the parsing by
35
+ * using the returned position as a new starting point.
36
+ *
37
+ * There are also extra `.handle...` functions, which pull out some reused
38
+ * functionality into self-contained functions.
39
+ *
40
+ * The earlier functions return ParseNodes.
41
+ * The later functions (which are called deeper in the parse) sometimes return
42
+ * ParseFuncOrArgument, which contain a ParseNode as well as some data about
43
+ * whether the parsed object is a function which is missing some arguments, or a
44
+ * standalone object which can be used as an argument to another function.
45
+ */
46
+
47
+ /**
48
+ * Main Parser class
49
+ */
50
+ function Parser(input, settings) {
51
+ // Make a new lexer
52
+ this.lexer = new Lexer(input);
53
+ // Store the settings for use in parsing
54
+ this.settings = settings;
55
+ }
56
+
57
+ var ParseNode = parseData.ParseNode;
58
+
59
+ /**
60
+ * An initial function (without its arguments), or an argument to a function.
61
+ * The `result` argument should be a ParseNode.
62
+ */
63
+ function ParseFuncOrArgument(result, isFunction) {
64
+ this.result = result;
65
+ // Is this a function (i.e. is it something defined in functions.js)?
66
+ this.isFunction = isFunction;
67
+ }
68
+
69
+ /**
70
+ * Checks a result to make sure it has the right type, and throws an
71
+ * appropriate error otherwise.
72
+ *
73
+ * @param {boolean=} consume whether to consume the expected token,
74
+ * defaults to true
75
+ */
76
+ Parser.prototype.expect = function(text, consume) {
77
+ if (this.nextToken.text !== text) {
78
+ throw new ParseError(
79
+ "Expected '" + text + "', got '" + this.nextToken.text + "'",
80
+ this.lexer, this.nextToken.position
81
+ );
82
+ }
83
+ if (consume !== false) {
84
+ this.consume();
85
+ }
86
+ };
87
+
88
+ /**
89
+ * Considers the current look ahead token as consumed,
90
+ * and fetches the one after that as the new look ahead.
91
+ */
92
+ Parser.prototype.consume = function() {
93
+ this.pos = this.nextToken.position;
94
+
95
+ global_str = global_str + " " + this.nextToken.text
96
+ this.nextToken = this.lexer.lex(this.pos, this.mode);
97
+ };
98
+
99
+ /**
100
+ * Main parsing function, which parses an entire input.
101
+ *
102
+ * @return {?Array.<ParseNode>}
103
+ */
104
+ Parser.prototype.parse = function() {
105
+ // Try to parse the input
106
+ this.mode = "math";
107
+ this.pos = 0;
108
+ this.nextToken = this.lexer.lex(this.pos, this.mode);
109
+ var parse = this.parseInput();
110
+ return parse;
111
+ };
112
+
113
+ /**
114
+ * Parses an entire input tree.
115
+ */
116
+ Parser.prototype.parseInput = function() {
117
+ // Parse an expression
118
+ var expression = this.parseExpression(false);
119
+ // If we succeeded, make sure there's an EOF at the end
120
+ this.expect("EOF", false);
121
+ return expression;
122
+ };
123
+
124
+ var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
125
+
126
+ /**
127
+ * Parses an "expression", which is a list of atoms.
128
+ *
129
+ * @param {boolean} breakOnInfix Should the parsing stop when we hit infix
130
+ * nodes? This happens when functions have higher precendence
131
+ * than infix nodes in implicit parses.
132
+ *
133
+ * @param {?string} breakOnToken The token that the expression should end with,
134
+ * or `null` if something else should end the expression.
135
+ *
136
+ * @return {ParseNode}
137
+ */
138
+ Parser.prototype.parseExpression = function(breakOnInfix, breakOnToken) {
139
+ var body = [];
140
+ // Keep adding atoms to the body until we can't parse any more atoms (either
141
+ // we reached the end, a }, or a \right)
142
+ while (true) {
143
+ var lex = this.nextToken;
144
+ var pos = this.pos;
145
+ if (endOfExpression.indexOf(lex.text) !== -1) {
146
+ break;
147
+ }
148
+ if (breakOnToken && lex.text === breakOnToken) {
149
+ break;
150
+ }
151
+ var atom = this.parseAtom();
152
+ if (!atom) {
153
+ if (!this.settings.throwOnError && lex.text[0] === "\\") {
154
+ var errorNode = this.handleUnsupportedCmd();
155
+ body.push(errorNode);
156
+
157
+ pos = lex.position;
158
+ continue;
159
+ }
160
+
161
+ break;
162
+ }
163
+ if (breakOnInfix && atom.type === "infix") {
164
+ // rewind so we can parse the infix atom again
165
+ this.pos = pos;
166
+ this.nextToken = lex;
167
+ break;
168
+ }
169
+ body.push(atom);
170
+ }
171
+ return this.handleInfixNodes(body);
172
+ };
173
+
174
+ /**
175
+ * Rewrites infix operators such as \over with corresponding commands such
176
+ * as \frac.
177
+ *
178
+ * There can only be one infix operator per group. If there's more than one
179
+ * then the expression is ambiguous. This can be resolved by adding {}.
180
+ *
181
+ * @returns {Array}
182
+ */
183
+ Parser.prototype.handleInfixNodes = function(body) {
184
+ var overIndex = -1;
185
+ var funcName;
186
+
187
+ for (var i = 0; i < body.length; i++) {
188
+ var node = body[i];
189
+ if (node.type === "infix") {
190
+ if (overIndex !== -1) {
191
+ throw new ParseError("only one infix operator per group",
192
+ this.lexer, -1);
193
+ }
194
+ overIndex = i;
195
+ funcName = node.value.replaceWith;
196
+ }
197
+ }
198
+
199
+ if (overIndex !== -1) {
200
+ var numerNode;
201
+ var denomNode;
202
+
203
+ var numerBody = body.slice(0, overIndex);
204
+ var denomBody = body.slice(overIndex + 1);
205
+
206
+ if (numerBody.length === 1 && numerBody[0].type === "ordgroup") {
207
+ numerNode = numerBody[0];
208
+ } else {
209
+ numerNode = new ParseNode("ordgroup", numerBody, this.mode);
210
+ }
211
+
212
+ if (denomBody.length === 1 && denomBody[0].type === "ordgroup") {
213
+ denomNode = denomBody[0];
214
+ } else {
215
+ denomNode = new ParseNode("ordgroup", denomBody, this.mode);
216
+ }
217
+
218
+ var value = this.callFunction(
219
+ funcName, [numerNode, denomNode], null);
220
+ return [new ParseNode(value.type, value, this.mode)];
221
+ } else {
222
+ return body;
223
+ }
224
+ };
225
+
226
+ // The greediness of a superscript or subscript
227
+ var SUPSUB_GREEDINESS = 1;
228
+
229
+ /**
230
+ * Handle a subscript or superscript with nice errors.
231
+ */
232
+ Parser.prototype.handleSupSubscript = function(name) {
233
+ var symbol = this.nextToken.text;
234
+ var symPos = this.pos;
235
+ this.consume();
236
+ var group = this.parseGroup();
237
+
238
+ if (!group) {
239
+ if (!this.settings.throwOnError && this.nextToken.text[0] === "\\") {
240
+ return this.handleUnsupportedCmd();
241
+ } else {
242
+ // throw new ParseError(
243
+ // "Expected group after '" + symbol + "'",
244
+ // this.lexer,
245
+ // symPos + 1
246
+ // );
247
+ }
248
+ } else if (group.isFunction) {
249
+ // ^ and _ have a greediness, so handle interactions with functions'
250
+ // greediness
251
+ var funcGreediness = functions[group.result].greediness;
252
+ if (funcGreediness > SUPSUB_GREEDINESS) {
253
+ return this.parseFunction(group);
254
+ } else {
255
+ throw new ParseError(
256
+ "Got function '" + group.result + "' with no arguments " +
257
+ "as " + name,
258
+ this.lexer, symPos + 1);
259
+ }
260
+ } else {
261
+ return group.result;
262
+ }
263
+ };
264
+
265
+ /**
266
+ * Converts the textual input of an unsupported command into a text node
267
+ * contained within a color node whose color is determined by errorColor
268
+ */
269
+ Parser.prototype.handleUnsupportedCmd = function() {
270
+ var text = this.nextToken.text;
271
+ var textordArray = [];
272
+
273
+ for (var i = 0; i < text.length; i++) {
274
+ textordArray.push(new ParseNode("textord", text[i], "text"));
275
+ }
276
+
277
+ var textNode = new ParseNode(
278
+ "text",
279
+ {
280
+ body: textordArray,
281
+ type: "text",
282
+ },
283
+ this.mode);
284
+
285
+ var colorNode = new ParseNode(
286
+ "color",
287
+ {
288
+ color: this.settings.errorColor,
289
+ value: [textNode],
290
+ type: "color",
291
+ },
292
+ this.mode);
293
+
294
+ this.consume();
295
+ return colorNode;
296
+ };
297
+
298
+ /**
299
+ * Parses a group with optional super/subscripts.
300
+ *
301
+ * @return {?ParseNode}
302
+ */
303
+ Parser.prototype.parseAtom = function() {
304
+ // The body of an atom is an implicit group, so that things like
305
+ // \left(x\right)^2 work correctly.
306
+ var base = this.parseImplicitGroup();
307
+
308
+ // In text mode, we don't have superscripts or subscripts
309
+ if (this.mode === "text") {
310
+ return base;
311
+ }
312
+
313
+ // Note that base may be empty (i.e. null) at this point.
314
+
315
+ var superscript;
316
+ var subscript;
317
+ while (true) {
318
+ // Lex the first token
319
+ var lex = this.nextToken;
320
+
321
+ if (lex.text === "\\limits" || lex.text === "\\nolimits") {
322
+ // We got a limit control
323
+ if (!base || base.type !== "op") {
324
+ throw new ParseError(
325
+ "Limit controls must follow a math operator",
326
+ this.lexer, this.pos);
327
+ } else {
328
+ var limits = lex.text === "\\limits";
329
+ base.value.limits = limits;
330
+ base.value.alwaysHandleSupSub = true;
331
+ }
332
+ this.consume();
333
+ } else if (lex.text === "^") {
334
+ // We got a superscript start
335
+ // if (superscript) {
336
+ // throw new ParseError(
337
+ // "Double superscript", this.lexer, this.pos);
338
+ // }
339
+ superscript = this.handleSupSubscript("superscript");
340
+ } else if (lex.text === "_") {
341
+ // We got a subscript start
342
+ // if (subscript) {
343
+ // throw new ParseError(
344
+ // "Double subscript", this.lexer, this.pos);
345
+ // }
346
+ subscript = this.handleSupSubscript("subscript");
347
+ } else if (lex.text === "'") {
348
+ // We got a prime
349
+ var prime = new ParseNode("textord", "\\prime", this.mode);
350
+
351
+ // Many primes can be grouped together, so we handle this here
352
+ var primes = [prime];
353
+ this.consume();
354
+ // Keep lexing tokens until we get something that's not a prime
355
+ while (this.nextToken.text === "'") {
356
+ // For each one, add another prime to the list
357
+ primes.push(prime);
358
+ this.consume();
359
+ }
360
+ // Put them into an ordgroup as the superscript
361
+ superscript = new ParseNode("ordgroup", primes, this.mode);
362
+ } else {
363
+ // If it wasn't ^, _, or ', stop parsing super/subscripts
364
+ break;
365
+ }
366
+ }
367
+
368
+ if (superscript || subscript) {
369
+ // If we got either a superscript or subscript, create a supsub
370
+ return new ParseNode("supsub", {
371
+ base: base,
372
+ sup: superscript,
373
+ sub: subscript,
374
+ }, this.mode);
375
+ } else {
376
+ // Otherwise return the original body
377
+ return base;
378
+ }
379
+ };
380
+
381
+ // A list of the size-changing functions, for use in parseImplicitGroup
382
+ var sizeFuncs = [
383
+ "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
384
+ "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge", "\\textrm", "\\rm", "\\cal",
385
+ "\\bf", "\\siptstyle", "\\boldmath", "\\it"
386
+ ];
387
+
388
+ // A list of the style-changing functions, for use in parseImplicitGroup
389
+ var styleFuncs = [
390
+ "\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle",
391
+ ];
392
+
393
+ /**
394
+ * Parses an implicit group, which is a group that starts at the end of a
395
+ * specified, and ends right before a higher explicit group ends, or at EOL. It
396
+ * is used for functions that appear to affect the current style, like \Large or
397
+ * \textrm, where instead of keeping a style we just pretend that there is an
398
+ * implicit grouping after it until the end of the group. E.g.
399
+ * small text {\Large large text} small text again
400
+ * It is also used for \left and \right to get the correct grouping.
401
+ *
402
+ * @return {?ParseNode}
403
+ */
404
+ Parser.prototype.parseImplicitGroup = function() {
405
+ var start = this.parseSymbol();
406
+
407
+ if (start == null) {
408
+ // If we didn't get anything we handle, fall back to parseFunction
409
+ return this.parseFunction();
410
+ }
411
+
412
+ var func = start.result;
413
+ var body;
414
+ if (func === "\\left") {
415
+ // If we see a left:
416
+ // Parse the entire left function (including the delimiter)
417
+ var left = this.parseFunction(start);
418
+ // Parse out the implicit body
419
+ body = this.parseExpression(false);
420
+ // Check the next token
421
+ this.expect("\\right", false);
422
+ var right = this.parseFunction();
423
+ return new ParseNode("leftright", {
424
+ body: body,
425
+ left: left.value.value,
426
+ right: right.value.value,
427
+ }, this.mode);
428
+ } else if (func === "\\begin") {
429
+ // begin...end is similar to left...right
430
+ var begin = this.parseFunction(start);
431
+ var envName = begin.value.name;
432
+ var name = (begin.value.name + "")
433
+
434
+ global_str = global_str.substring(0, global_str.length - (name.length * 2 + 2)) + name + "}"
435
+
436
+ if (!environments.hasOwnProperty(envName)) {
437
+ throw new ParseError(
438
+ "No such environment: " + envName,
439
+ this.lexer, begin.value.namepos);
440
+ }
441
+ // Build the environment object. Arguments and other information will
442
+ // be made available to the begin and end methods using properties.
443
+ var env = environments[envName];
444
+ var args = this.parseArguments("\\begin{" + envName + "}", env);
445
+ var context = {
446
+ mode: this.mode,
447
+ envName: envName,
448
+ parser: this,
449
+ lexer: this.lexer,
450
+ positions: args.pop(),
451
+ };
452
+ var result = env.handler(context, args);
453
+ this.expect("\\end", false);
454
+ var end = this.parseFunction();
455
+
456
+ var name = (begin.value.name + "")
457
+
458
+ global_str = global_str.substring(0, global_str.length - (name.length * 2 + 2)) + name + "}"
459
+ if (end.value.name !== envName) {
460
+ throw new ParseError(
461
+ "Mismatch: \\begin{" + envName + "} matched " +
462
+ "by \\end{" + end.value.name + "}",
463
+ this.lexer /* , end.value.namepos */);
464
+ // TODO: Add position to the above line and adjust test case,
465
+ // requires #385 to get merged first
466
+ }
467
+ result.position = end.position;
468
+
469
+ return result;
470
+
471
+ } else if (func.value == "\\matrix" || func.value == "\\pmatrix" || func.value == "\\cases") {
472
+ // if (!environments.hasOwnProperty(envName)) {
473
+ // throw new ParseError(
474
+ // "No such environment: " + envName,
475
+ // this.lexer, begin.value.namepos);
476
+ // }
477
+ // Build the environment object. Arguments and other information will
478
+ // be made available to the begin and end methods using properties.
479
+
480
+ envName = func.value.slice(1);
481
+ var env = environments[envName];
482
+ // var args = this.parseArguments("\\matrix{", env);
483
+ this.expect("{", true);
484
+ var context = {
485
+ mode: this.mode,
486
+ envName: envName,
487
+ parser: this,
488
+ lexer: this.lexer
489
+ };
490
+
491
+ var result = env.handler(context, {} );
492
+ // exit();
493
+ this.expect("}", true);
494
+ // var end = this.parseFunction();
495
+ var next = this.nextToken.text;
496
+ // exit();
497
+ // console.log(next);
498
+ // var name = ( + "")
499
+
500
+ // global_str = global_str.substring(0, global_str.length - (name.length * 2 + 2)) + name + "}"
501
+ // result.position = end.position;
502
+
503
+ return result;
504
+
505
+ } else if (utils.contains(sizeFuncs, func)) {
506
+ // If we see a sizing function, parse out the implict body
507
+ body = this.parseExpression(false);
508
+
509
+ return new ParseNode("sizing", {
510
+ // Figure out what size to use based on the list of functions above
511
+ original: func,
512
+ size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
513
+ value: body,
514
+ }, this.mode);
515
+ } else if (utils.contains(styleFuncs, func)) {
516
+ // If we see a styling function, parse out the implict body
517
+ body = this.parseExpression(true);
518
+ return new ParseNode("styling", {
519
+ // Figure out what style to use by pulling out the style from
520
+ // the function name
521
+ original: func,
522
+ style: func.slice(1, func.length - 5),
523
+ value: body,
524
+ }, this.mode);
525
+ } else {
526
+ // Defer to parseFunction if it's not a function we handle
527
+ return this.parseFunction(start);
528
+ }
529
+ };
530
+
531
+ /**
532
+ * Parses an entire function, including its base and all of its arguments.
533
+ * The base might either have been parsed already, in which case
534
+ * it is provided as an argument, or it's the next group in the input.
535
+ *
536
+ * @param {ParseFuncOrArgument=} baseGroup optional as described above
537
+ * @return {?ParseNode}
538
+ */
539
+ Parser.prototype.parseFunction = function(baseGroup) {
540
+ if (!baseGroup) {
541
+ baseGroup = this.parseGroup();
542
+ }
543
+
544
+ if (baseGroup) {
545
+ if (baseGroup.isFunction) {
546
+ var func = baseGroup.result;
547
+ var funcData = functions[func];
548
+ if (this.mode === "text" && !funcData.allowedInText) {
549
+ // throw new ParseError(
550
+ // "Can't use function '" + func + "' in text mode",
551
+ // this.lexer, baseGroup.position);
552
+ }
553
+
554
+ var args = this.parseArguments(func, funcData);
555
+ var result = this.callFunction(func, args, args.pop());
556
+ return new ParseNode(result.type, result, this.mode);
557
+ } else {
558
+ return baseGroup.result;
559
+ }
560
+ } else {
561
+ return null;
562
+ }
563
+ };
564
+
565
+ /**
566
+ * Call a function handler with a suitable context and arguments.
567
+ */
568
+ Parser.prototype.callFunction = function(name, args, positions) {
569
+ var context = {
570
+ funcName: name,
571
+ parser: this,
572
+ lexer: this.lexer,
573
+ positions: positions,
574
+ };
575
+ return functions[name].handler(context, args);
576
+ };
577
+
578
+ /**
579
+ * Parses the arguments of a function or environment
580
+ *
581
+ * @param {string} func "\name" or "\begin{name}"
582
+ * @param {{numArgs:number,numOptionalArgs:number|undefined}} funcData
583
+ * @return the array of arguments, with the list of positions as last element
584
+ */
585
+ Parser.prototype.parseArguments = function(func, funcData) {
586
+ var totalArgs = funcData.numArgs + funcData.numOptionalArgs;
587
+ if (totalArgs === 0) {
588
+ return [[this.pos]];
589
+ }
590
+
591
+ var baseGreediness = funcData.greediness;
592
+ var positions = [this.pos];
593
+ var args = [];
594
+
595
+ for (var i = 0; i < totalArgs; i++) {
596
+ var argType = funcData.argTypes && funcData.argTypes[i];
597
+ var arg;
598
+ if (i < funcData.numOptionalArgs) {
599
+ if (argType) {
600
+ arg = this.parseSpecialGroup(argType, true);
601
+ } else {
602
+ arg = this.parseOptionalGroup();
603
+ }
604
+ if (!arg) {
605
+ args.push(null);
606
+ positions.push(this.pos);
607
+ continue;
608
+ }
609
+ } else {
610
+ if (argType) {
611
+ arg = this.parseSpecialGroup(argType);
612
+ } else {
613
+ arg = this.parseGroup();
614
+ }
615
+ if (!arg) {
616
+ if (!this.settings.throwOnError &&
617
+ this.nextToken.text[0] === "\\") {
618
+ arg = new ParseFuncOrArgument(
619
+ this.handleUnsupportedCmd(this.nextToken.text),
620
+ false);
621
+ } else {
622
+ throw new ParseError(
623
+ "Expected group after '" + func + "'",
624
+ this.lexer, this.pos);
625
+ }
626
+ }
627
+ }
628
+ var argNode;
629
+ if (arg.isFunction) {
630
+ var argGreediness =
631
+ functions[arg.result].greediness;
632
+ if (argGreediness > baseGreediness) {
633
+ argNode = this.parseFunction(arg);
634
+ } else {
635
+ // throw new ParseError(
636
+ // "Got function '" + arg.result + "' as " +
637
+ // "argument to '" + func + "'",
638
+ // this.lexer, this.pos - 1);
639
+ }
640
+ } else {
641
+ argNode = arg.result;
642
+ }
643
+ args.push(argNode);
644
+ positions.push(this.pos);
645
+ }
646
+
647
+ args.push(positions);
648
+
649
+ return args;
650
+ };
651
+
652
+
653
+ /**
654
+ * Parses a group when the mode is changing. Takes a position, a new mode, and
655
+ * an outer mode that is used to parse the outside.
656
+ *
657
+ * @return {?ParseFuncOrArgument}
658
+ */
659
+ Parser.prototype.parseSpecialGroup = function(innerMode, optional) {
660
+ var outerMode = this.mode;
661
+ // Handle `original` argTypes
662
+ if (innerMode === "original") {
663
+ innerMode = outerMode;
664
+ }
665
+
666
+ if (innerMode === "color" || innerMode === "size") {
667
+ // color and size modes are special because they should have braces and
668
+ // should only lex a single symbol inside
669
+ var openBrace = this.nextToken;
670
+ if (optional && openBrace.text !== "[") {
671
+ // optional arguments should return null if they don't exist
672
+ return null;
673
+ }
674
+ // The call to expect will lex the token after the '{' in inner mode
675
+ this.mode = innerMode;
676
+ this.expect(optional ? "[" : "{");
677
+ var inner = this.nextToken;
678
+ this.mode = outerMode;
679
+ var data;
680
+ if (innerMode === "color") {
681
+ data = inner.text;
682
+ } else {
683
+ data = inner.data;
684
+ }
685
+ this.consume(); // consume the token stored in inner
686
+ this.expect(optional ? "]" : "}");
687
+ return new ParseFuncOrArgument(
688
+ new ParseNode(innerMode, data, outerMode),
689
+ false);
690
+ } else if (innerMode === "text") {
691
+ // text mode is special because it should ignore the whitespace before
692
+ // it
693
+ var whitespace = this.lexer.lex(this.pos, "whitespace");
694
+ this.pos = whitespace.position;
695
+ }
696
+
697
+ // By the time we get here, innerMode is one of "text" or "math".
698
+ // We switch the mode of the parser, recurse, then restore the old mode.
699
+ this.mode = innerMode;
700
+ this.nextToken = this.lexer.lex(this.pos, innerMode);
701
+ var res;
702
+ if (optional) {
703
+ res = this.parseOptionalGroup();
704
+ } else {
705
+ res = this.parseGroup();
706
+ }
707
+ this.mode = outerMode;
708
+ this.nextToken = this.lexer.lex(this.pos, outerMode);
709
+ return res;
710
+ };
711
+
712
+ /**
713
+ * Parses a group, which is either a single nucleus (like "x") or an expression
714
+ * in braces (like "{x+y}")
715
+ *
716
+ * @return {?ParseFuncOrArgument}
717
+ */
718
+ Parser.prototype.parseGroup = function() {
719
+ // Try to parse an open brace
720
+ if (this.nextToken.text === "{") {
721
+ // If we get a brace, parse an expression
722
+ this.consume();
723
+ var expression = this.parseExpression(false);
724
+ // Make sure we get a close brace
725
+ this.expect("}");
726
+ return new ParseFuncOrArgument(
727
+ new ParseNode("ordgroup", expression, this.mode),
728
+ false);
729
+ } else {
730
+ // Otherwise, just return a nucleus
731
+ return this.parseSymbol();
732
+ }
733
+ };
734
+
735
+ /**
736
+ * Parses a group, which is an expression in brackets (like "[x+y]")
737
+ *
738
+ * @return {?ParseFuncOrArgument}
739
+ */
740
+ Parser.prototype.parseOptionalGroup = function() {
741
+ // Try to parse an open bracket
742
+ if (this.nextToken.text === "[") {
743
+ // If we get a brace, parse an expression
744
+ this.consume();
745
+ var expression = this.parseExpression(false, "]");
746
+ // Make sure we get a close bracket
747
+ this.expect("]");
748
+ return new ParseFuncOrArgument(
749
+ new ParseNode("ordgroup", expression, this.mode),
750
+ false);
751
+ } else {
752
+ // Otherwise, return null,
753
+ return null;
754
+ }
755
+ };
756
+
757
+ /**
758
+ * Parse a single symbol out of the string. Here, we handle both the functions
759
+ * we have defined, as well as the single character symbols
760
+ *
761
+ * @return {?ParseFuncOrArgument}
762
+ */
763
+ Parser.prototype.parseSymbol = function() {
764
+ var nucleus = this.nextToken;
765
+
766
+ if (functions[nucleus.text]) {
767
+ this.consume();
768
+ // If there exists a function with this name, we return the function and
769
+ // say that it is a function.
770
+ return new ParseFuncOrArgument(
771
+ nucleus.text,
772
+ true);
773
+ } else if (symbols[this.mode][nucleus.text]) {
774
+ this.consume();
775
+ // Otherwise if this is a no-argument function, find the type it
776
+ // corresponds to in the symbols map
777
+ return new ParseFuncOrArgument(
778
+ new ParseNode(symbols[this.mode][nucleus.text].group,
779
+ nucleus.text, this.mode),
780
+ false);
781
+ } else if (nucleus.text == "EOF" || nucleus.text == "{") {
782
+ return null;
783
+
784
+ } else {
785
+ this.consume();
786
+ // console.error(nucleus);
787
+ return new ParseFuncOrArgument(
788
+ new ParseNode(symbols["math"]["\\sigma"].group,
789
+ nucleus.text, this.mode),
790
+ false);
791
+ // console.log(nucleus.text);
792
+ // return null;
793
+ }
794
+ };
795
+
796
+ Parser.prototype.ParseNode = ParseNode;
797
+
798
+ module.exports = Parser;
katex/src/Settings.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This is a module for storing settings passed into KaTeX. It correctly handles
3
+ * default settings.
4
+ */
5
+
6
+ /**
7
+ * Helper function for getting a default value if the value is undefined
8
+ */
9
+ function get(option, defaultValue) {
10
+ return option === undefined ? defaultValue : option;
11
+ }
12
+
13
+ /**
14
+ * The main Settings object
15
+ *
16
+ * The current options stored are:
17
+ * - displayMode: Whether the expression should be typeset by default in
18
+ * textstyle or displaystyle (default false)
19
+ */
20
+ function Settings(options) {
21
+ // allow null options
22
+ options = options || {};
23
+ this.displayMode = get(options.displayMode, false);
24
+ this.throwOnError = get(options.throwOnError, true);
25
+ this.errorColor = get(options.errorColor, "#cc0000");
26
+ }
27
+
28
+ module.exports = Settings;
katex/src/Style.js ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file contains information and classes for the various kinds of styles
3
+ * used in TeX. It provides a generic `Style` class, which holds information
4
+ * about a specific style. It then provides instances of all the different kinds
5
+ * of styles possible, and provides functions to move between them and get
6
+ * information about them.
7
+ */
8
+
9
+ /**
10
+ * The main style class. Contains a unique id for the style, a size (which is
11
+ * the same for cramped and uncramped version of a style), a cramped flag, and a
12
+ * size multiplier, which gives the size difference between a style and
13
+ * textstyle.
14
+ */
15
+ function Style(id, size, multiplier, cramped) {
16
+ this.id = id;
17
+ this.size = size;
18
+ this.cramped = cramped;
19
+ this.sizeMultiplier = multiplier;
20
+ }
21
+
22
+ /**
23
+ * Get the style of a superscript given a base in the current style.
24
+ */
25
+ Style.prototype.sup = function() {
26
+ return styles[sup[this.id]];
27
+ };
28
+
29
+ /**
30
+ * Get the style of a subscript given a base in the current style.
31
+ */
32
+ Style.prototype.sub = function() {
33
+ return styles[sub[this.id]];
34
+ };
35
+
36
+ /**
37
+ * Get the style of a fraction numerator given the fraction in the current
38
+ * style.
39
+ */
40
+ Style.prototype.fracNum = function() {
41
+ return styles[fracNum[this.id]];
42
+ };
43
+
44
+ /**
45
+ * Get the style of a fraction denominator given the fraction in the current
46
+ * style.
47
+ */
48
+ Style.prototype.fracDen = function() {
49
+ return styles[fracDen[this.id]];
50
+ };
51
+
52
+ /**
53
+ * Get the cramped version of a style (in particular, cramping a cramped style
54
+ * doesn't change the style).
55
+ */
56
+ Style.prototype.cramp = function() {
57
+ return styles[cramp[this.id]];
58
+ };
59
+
60
+ /**
61
+ * HTML class name, like "displaystyle cramped"
62
+ */
63
+ Style.prototype.cls = function() {
64
+ return sizeNames[this.size] + (this.cramped ? " cramped" : " uncramped");
65
+ };
66
+
67
+ /**
68
+ * HTML Reset class name, like "reset-textstyle"
69
+ */
70
+ Style.prototype.reset = function() {
71
+ return resetNames[this.size];
72
+ };
73
+
74
+ // IDs of the different styles
75
+ var D = 0;
76
+ var Dc = 1;
77
+ var T = 2;
78
+ var Tc = 3;
79
+ var S = 4;
80
+ var Sc = 5;
81
+ var SS = 6;
82
+ var SSc = 7;
83
+
84
+ // String names for the different sizes
85
+ var sizeNames = [
86
+ "displaystyle textstyle",
87
+ "textstyle",
88
+ "scriptstyle",
89
+ "scriptscriptstyle",
90
+ ];
91
+
92
+ // Reset names for the different sizes
93
+ var resetNames = [
94
+ "reset-textstyle",
95
+ "reset-textstyle",
96
+ "reset-scriptstyle",
97
+ "reset-scriptscriptstyle",
98
+ ];
99
+
100
+ // Instances of the different styles
101
+ var styles = [
102
+ new Style(D, 0, 1.0, false),
103
+ new Style(Dc, 0, 1.0, true),
104
+ new Style(T, 1, 1.0, false),
105
+ new Style(Tc, 1, 1.0, true),
106
+ new Style(S, 2, 0.7, false),
107
+ new Style(Sc, 2, 0.7, true),
108
+ new Style(SS, 3, 0.5, false),
109
+ new Style(SSc, 3, 0.5, true),
110
+ ];
111
+
112
+ // Lookup tables for switching from one style to another
113
+ var sup = [S, Sc, S, Sc, SS, SSc, SS, SSc];
114
+ var sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc];
115
+ var fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc];
116
+ var fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc];
117
+ var cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc];
118
+
119
+ // We only export some of the styles. Also, we don't export the `Style` class so
120
+ // no more styles can be generated.
121
+ module.exports = {
122
+ DISPLAY: styles[D],
123
+ TEXT: styles[T],
124
+ SCRIPT: styles[S],
125
+ SCRIPTSCRIPT: styles[SS],
126
+ };
katex/src/buildCommon.js ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint no-console:0 */
2
+ /**
3
+ * This module contains general functions that can be used for building
4
+ * different kinds of domTree nodes in a consistent manner.
5
+ */
6
+
7
+ var domTree = require("./domTree");
8
+ var fontMetrics = require("./fontMetrics");
9
+ var symbols = require("./symbols");
10
+ var utils = require("./utils");
11
+
12
+ var greekCapitals = [
13
+ "\\Gamma",
14
+ "\\Delta",
15
+ "\\Theta",
16
+ "\\Lambda",
17
+ "\\Xi",
18
+ "\\Pi",
19
+ "\\Sigma",
20
+ "\\Upsilon",
21
+ "\\Phi",
22
+ "\\Psi",
23
+ "\\Omega",
24
+ ];
25
+
26
+ var dotlessLetters = [
27
+ "\u0131", // dotless i, \imath
28
+ "\u0237", // dotless j, \jmath
29
+ ];
30
+
31
+ /**
32
+ * Makes a symbolNode after translation via the list of symbols in symbols.js.
33
+ * Correctly pulls out metrics for the character, and optionally takes a list of
34
+ * classes to be attached to the node.
35
+ */
36
+ var makeSymbol = function(value, style, mode, color, classes) {
37
+ // Replace the value with its replaced value from symbol.js
38
+ if (symbols[mode][value] && symbols[mode][value].replace) {
39
+ value = symbols[mode][value].replace;
40
+ }
41
+
42
+ var metrics = fontMetrics.getCharacterMetrics(value, style);
43
+
44
+ var symbolNode;
45
+ if (metrics) {
46
+ symbolNode = new domTree.symbolNode(
47
+ value, metrics.height, metrics.depth, metrics.italic, metrics.skew,
48
+ classes);
49
+ } else {
50
+ // TODO(emily): Figure out a good way to only print this in development
51
+ typeof console !== "undefined" && console.warn(
52
+ "No character metrics for '" + value + "' in style '" +
53
+ style + "'");
54
+ symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes);
55
+ }
56
+
57
+ if (color) {
58
+ symbolNode.style.color = color;
59
+ }
60
+
61
+ return symbolNode;
62
+ };
63
+
64
+ /**
65
+ * Makes a symbol in Main-Regular or AMS-Regular.
66
+ * Used for rel, bin, open, close, inner, and punct.
67
+ */
68
+ var mathsym = function(value, mode, color, classes) {
69
+ // Decide what font to render the symbol in by its entry in the symbols
70
+ // table.
71
+ // Have a special case for when the value = \ because the \ is used as a
72
+ // textord in unsupported command errors but cannot be parsed as a regular
73
+ // text ordinal and is therefore not present as a symbol in the symbols
74
+ // table for text
75
+ if (value === "\\" || symbols[mode][value].font === "main") {
76
+ return makeSymbol(value, "Main-Regular", mode, color, classes);
77
+ } else {
78
+ return makeSymbol(
79
+ value, "AMS-Regular", mode, color, classes.concat(["amsrm"]));
80
+ }
81
+ };
82
+
83
+ /**
84
+ * Makes a symbol in the default font for mathords and textords.
85
+ */
86
+ var mathDefault = function(value, mode, color, classes, type) {
87
+ if (type === "mathord") {
88
+ return mathit(value, mode, color, classes);
89
+ } else if (type === "textord") {
90
+ return makeSymbol(
91
+ value, "Main-Regular", mode, color, classes.concat(["mathrm"]));
92
+ } else {
93
+ throw new Error("unexpected type: " + type + " in mathDefault");
94
+ }
95
+ };
96
+
97
+ /**
98
+ * Makes a symbol in the italic math font.
99
+ */
100
+ var mathit = function(value, mode, color, classes) {
101
+ if (/[0-9]/.test(value.charAt(0)) ||
102
+ // glyphs for \imath and \jmath do not exist in Math-Italic so we
103
+ // need to use Main-Italic instead
104
+ utils.contains(dotlessLetters, value) ||
105
+ utils.contains(greekCapitals, value)) {
106
+ return makeSymbol(
107
+ value, "Main-Italic", mode, color, classes.concat(["mainit"]));
108
+ } else {
109
+ return makeSymbol(
110
+ value, "Math-Italic", mode, color, classes.concat(["mathit"]));
111
+ }
112
+ };
113
+
114
+ /**
115
+ * Makes either a mathord or textord in the correct font and color.
116
+ */
117
+ var makeOrd = function(group, options, type) {
118
+ var mode = group.mode;
119
+ var value = group.value;
120
+ if (symbols[mode][value] && symbols[mode][value].replace) {
121
+ value = symbols[mode][value].replace;
122
+ }
123
+
124
+ var classes = ["mord"];
125
+ var color = options.getColor();
126
+
127
+ var font = options.font;
128
+ if (font) {
129
+ if (font === "mathit" || utils.contains(dotlessLetters, value)) {
130
+ return mathit(value, mode, color, classes);
131
+ } else {
132
+ var fontName = fontMap[font].fontName;
133
+ if (fontMetrics.getCharacterMetrics(value, fontName)) {
134
+ return makeSymbol(
135
+ value, fontName, mode, color, classes.concat([font]));
136
+ } else {
137
+ return mathDefault(value, mode, color, classes, type);
138
+ }
139
+ }
140
+ } else {
141
+ return mathDefault(value, mode, color, classes, type);
142
+ }
143
+ };
144
+
145
+ /**
146
+ * Calculate the height, depth, and maxFontSize of an element based on its
147
+ * children.
148
+ */
149
+ var sizeElementFromChildren = function(elem) {
150
+ var height = 0;
151
+ var depth = 0;
152
+ var maxFontSize = 0;
153
+
154
+ if (elem.children) {
155
+ for (var i = 0; i < elem.children.length; i++) {
156
+ if (elem.children[i].height > height) {
157
+ height = elem.children[i].height;
158
+ }
159
+ if (elem.children[i].depth > depth) {
160
+ depth = elem.children[i].depth;
161
+ }
162
+ if (elem.children[i].maxFontSize > maxFontSize) {
163
+ maxFontSize = elem.children[i].maxFontSize;
164
+ }
165
+ }
166
+ }
167
+
168
+ elem.height = height;
169
+ elem.depth = depth;
170
+ elem.maxFontSize = maxFontSize;
171
+ };
172
+
173
+ /**
174
+ * Makes a span with the given list of classes, list of children, and color.
175
+ */
176
+ var makeSpan = function(classes, children, color) {
177
+ var span = new domTree.span(classes, children);
178
+
179
+ sizeElementFromChildren(span);
180
+
181
+ if (color) {
182
+ span.style.color = color;
183
+ }
184
+
185
+ return span;
186
+ };
187
+
188
+ /**
189
+ * Makes a document fragment with the given list of children.
190
+ */
191
+ var makeFragment = function(children) {
192
+ var fragment = new domTree.documentFragment(children);
193
+
194
+ sizeElementFromChildren(fragment);
195
+
196
+ return fragment;
197
+ };
198
+
199
+ /**
200
+ * Makes an element placed in each of the vlist elements to ensure that each
201
+ * element has the same max font size. To do this, we create a zero-width space
202
+ * with the correct font size.
203
+ */
204
+ var makeFontSizer = function(options, fontSize) {
205
+ var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
206
+ fontSizeInner.style.fontSize =
207
+ (fontSize / options.style.sizeMultiplier) + "em";
208
+
209
+ var fontSizer = makeSpan(
210
+ ["fontsize-ensurer", "reset-" + options.size, "size5"],
211
+ [fontSizeInner]);
212
+
213
+ return fontSizer;
214
+ };
215
+
216
+ /**
217
+ * Makes a vertical list by stacking elements and kerns on top of each other.
218
+ * Allows for many different ways of specifying the positioning method.
219
+ *
220
+ * Arguments:
221
+ * - children: A list of child or kern nodes to be stacked on top of each other
222
+ * (i.e. the first element will be at the bottom, and the last at
223
+ * the top). Element nodes are specified as
224
+ * {type: "elem", elem: node}
225
+ * while kern nodes are specified as
226
+ * {type: "kern", size: size}
227
+ * - positionType: The method by which the vlist should be positioned. Valid
228
+ * values are:
229
+ * - "individualShift": The children list only contains elem
230
+ * nodes, and each node contains an extra
231
+ * "shift" value of how much it should be
232
+ * shifted (note that shifting is always
233
+ * moving downwards). positionData is
234
+ * ignored.
235
+ * - "top": The positionData specifies the topmost point of
236
+ * the vlist (note this is expected to be a height,
237
+ * so positive values move up)
238
+ * - "bottom": The positionData specifies the bottommost point
239
+ * of the vlist (note this is expected to be a
240
+ * depth, so positive values move down
241
+ * - "shift": The vlist will be positioned such that its
242
+ * baseline is positionData away from the baseline
243
+ * of the first child. Positive values move
244
+ * downwards.
245
+ * - "firstBaseline": The vlist will be positioned such that
246
+ * its baseline is aligned with the
247
+ * baseline of the first child.
248
+ * positionData is ignored. (this is
249
+ * equivalent to "shift" with
250
+ * positionData=0)
251
+ * - positionData: Data used in different ways depending on positionType
252
+ * - options: An Options object
253
+ *
254
+ */
255
+ var makeVList = function(children, positionType, positionData, options) {
256
+ var depth;
257
+ var currPos;
258
+ var i;
259
+ if (positionType === "individualShift") {
260
+ var oldChildren = children;
261
+ children = [oldChildren[0]];
262
+
263
+ // Add in kerns to the list of children to get each element to be
264
+ // shifted to the correct specified shift
265
+ depth = -oldChildren[0].shift - oldChildren[0].elem.depth;
266
+ currPos = depth;
267
+ for (i = 1; i < oldChildren.length; i++) {
268
+ var diff = -oldChildren[i].shift - currPos -
269
+ oldChildren[i].elem.depth;
270
+ var size = diff -
271
+ (oldChildren[i - 1].elem.height +
272
+ oldChildren[i - 1].elem.depth);
273
+
274
+ currPos = currPos + diff;
275
+
276
+ children.push({type: "kern", size: size});
277
+ children.push(oldChildren[i]);
278
+ }
279
+ } else if (positionType === "top") {
280
+ // We always start at the bottom, so calculate the bottom by adding up
281
+ // all the sizes
282
+ var bottom = positionData;
283
+ for (i = 0; i < children.length; i++) {
284
+ if (children[i].type === "kern") {
285
+ bottom -= children[i].size;
286
+ } else {
287
+ bottom -= children[i].elem.height + children[i].elem.depth;
288
+ }
289
+ }
290
+ depth = bottom;
291
+ } else if (positionType === "bottom") {
292
+ depth = -positionData;
293
+ } else if (positionType === "shift") {
294
+ depth = -children[0].elem.depth - positionData;
295
+ } else if (positionType === "firstBaseline") {
296
+ depth = -children[0].elem.depth;
297
+ } else {
298
+ depth = 0;
299
+ }
300
+
301
+ // Make the fontSizer
302
+ var maxFontSize = 0;
303
+ for (i = 0; i < children.length; i++) {
304
+ if (children[i].type === "elem") {
305
+ maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize);
306
+ }
307
+ }
308
+ var fontSizer = makeFontSizer(options, maxFontSize);
309
+
310
+ // Create a new list of actual children at the correct offsets
311
+ var realChildren = [];
312
+ currPos = depth;
313
+ for (i = 0; i < children.length; i++) {
314
+ if (children[i].type === "kern") {
315
+ currPos += children[i].size;
316
+ } else {
317
+ var child = children[i].elem;
318
+
319
+ var shift = -child.depth - currPos;
320
+ currPos += child.height + child.depth;
321
+
322
+ var childWrap = makeSpan([], [fontSizer, child]);
323
+ childWrap.height -= shift;
324
+ childWrap.depth += shift;
325
+ childWrap.style.top = shift + "em";
326
+
327
+ realChildren.push(childWrap);
328
+ }
329
+ }
330
+
331
+ // Add in an element at the end with no offset to fix the calculation of
332
+ // baselines in some browsers (namely IE, sometimes safari)
333
+ var baselineFix = makeSpan(
334
+ ["baseline-fix"], [fontSizer, new domTree.symbolNode("\u200b")]);
335
+ realChildren.push(baselineFix);
336
+
337
+ var vlist = makeSpan(["vlist"], realChildren);
338
+ // Fix the final height and depth, in case there were kerns at the ends
339
+ // since the makeSpan calculation won't take that in to account.
340
+ vlist.height = Math.max(currPos, vlist.height);
341
+ vlist.depth = Math.max(-depth, vlist.depth);
342
+ return vlist;
343
+ };
344
+
345
+ // A table of size -> font size for the different sizing functions
346
+ var sizingMultiplier = {
347
+ size1: 0.5,
348
+ size2: 0.7,
349
+ size3: 0.8,
350
+ size4: 0.9,
351
+ size5: 1.0,
352
+ size6: 1.2,
353
+ size7: 1.44,
354
+ size8: 1.73,
355
+ size9: 2.07,
356
+ size10: 2.49,
357
+ };
358
+
359
+ // A map of spacing functions to their attributes, like size and corresponding
360
+ // CSS class
361
+ var spacingFunctions = {
362
+ "\\qquad": {
363
+ size: "2em",
364
+ className: "qquad",
365
+ },
366
+ "\\quad": {
367
+ size: "1em",
368
+ className: "quad",
369
+ },
370
+ "\\enspace": {
371
+ size: "0.5em",
372
+ className: "enspace",
373
+ },
374
+ "\\;": {
375
+ size: "0.277778em",
376
+ className: "thickspace",
377
+ },
378
+ "\\:": {
379
+ size: "0.22222em",
380
+ className: "mediumspace",
381
+ },
382
+ "\\,": {
383
+ size: "0.16667em",
384
+ className: "thinspace",
385
+ },
386
+ "\\!": {
387
+ size: "-0.16667em",
388
+ className: "negativethinspace",
389
+ },
390
+ };
391
+
392
+ /**
393
+ * Maps TeX font commands to objects containing:
394
+ * - variant: string used for "mathvariant" attribute in buildMathML.js
395
+ * - fontName: the "style" parameter to fontMetrics.getCharacterMetrics
396
+ */
397
+ // A map between tex font commands an MathML mathvariant attribute values
398
+ var fontMap = {
399
+ // styles
400
+ "mathbf": {
401
+ variant: "bold",
402
+ fontName: "Main-Bold",
403
+ },
404
+ "mathrm": {
405
+ variant: "normal",
406
+ fontName: "Main-Regular",
407
+ },
408
+
409
+ // "mathit" is missing because it requires the use of two fonts: Main-Italic
410
+ // and Math-Italic. This is handled by a special case in makeOrd which ends
411
+ // up calling mathit.
412
+
413
+ // families
414
+ "mathbb": {
415
+ variant: "double-struck",
416
+ fontName: "AMS-Regular",
417
+ },
418
+ "mathcal": {
419
+ variant: "script",
420
+ fontName: "Caligraphic-Regular",
421
+ },
422
+ "mathfrak": {
423
+ variant: "fraktur",
424
+ fontName: "Fraktur-Regular",
425
+ },
426
+ "mathscr": {
427
+ variant: "script",
428
+ fontName: "Script-Regular",
429
+ },
430
+ "mathsf": {
431
+ variant: "sans-serif",
432
+ fontName: "SansSerif-Regular",
433
+ },
434
+ "mathtt": {
435
+ variant: "monospace",
436
+ fontName: "Typewriter-Regular",
437
+ },
438
+ };
439
+
440
+ module.exports = {
441
+ fontMap: fontMap,
442
+ makeSymbol: makeSymbol,
443
+ mathsym: mathsym,
444
+ makeSpan: makeSpan,
445
+ makeFragment: makeFragment,
446
+ makeVList: makeVList,
447
+ makeOrd: makeOrd,
448
+ sizingMultiplier: sizingMultiplier,
449
+ spacingFunctions: spacingFunctions,
450
+ };
katex/src/buildHTML.js ADDED
@@ -0,0 +1,1402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint no-console:0 */
2
+ /**
3
+ * This file does the main work of building a domTree structure from a parse
4
+ * tree. The entry point is the `buildHTML` function, which takes a parse tree.
5
+ * Then, the buildExpression, buildGroup, and various groupTypes functions are
6
+ * called, to produce a final HTML tree.
7
+ */
8
+
9
+ var ParseError = require("./ParseError");
10
+ var Style = require("./Style");
11
+
12
+ var buildCommon = require("./buildCommon");
13
+ var delimiter = require("./delimiter");
14
+ var domTree = require("./domTree");
15
+ var fontMetrics = require("./fontMetrics");
16
+ var utils = require("./utils");
17
+
18
+ var makeSpan = buildCommon.makeSpan;
19
+
20
+ /**
21
+ * Take a list of nodes, build them in order, and return a list of the built
22
+ * nodes. This function handles the `prev` node correctly, and passes the
23
+ * previous element from the list as the prev of the next element.
24
+ */
25
+ var buildExpression = function(expression, options, prev) {
26
+ var groups = [];
27
+ for (var i = 0; i < expression.length; i++) {
28
+ var group = expression[i];
29
+ groups.push(buildGroup(group, options, prev));
30
+ prev = group;
31
+ }
32
+ return groups;
33
+ };
34
+
35
+ // List of types used by getTypeOfGroup,
36
+ // see https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types
37
+ var groupToType = {
38
+ mathord: "mord",
39
+ textord: "mord",
40
+ bin: "mbin",
41
+ rel: "mrel",
42
+ text: "mord",
43
+ open: "mopen",
44
+ close: "mclose",
45
+ inner: "minner",
46
+ genfrac: "mord",
47
+ array: "mord",
48
+ spacing: "mord",
49
+ punct: "mpunct",
50
+ ordgroup: "mord",
51
+ op: "mop",
52
+ katex: "mord",
53
+ overline: "mord",
54
+ underline: "mord",
55
+ rule: "mord",
56
+ leftright: "minner",
57
+ sqrt: "mord",
58
+ accent: "mord",
59
+ };
60
+
61
+ /**
62
+ * Gets the final math type of an expression, given its group type. This type is
63
+ * used to determine spacing between elements, and affects bin elements by
64
+ * causing them to change depending on what types are around them. This type
65
+ * must be attached to the outermost node of an element as a CSS class so that
66
+ * spacing with its surrounding elements works correctly.
67
+ *
68
+ * Some elements can be mapped one-to-one from group type to math type, and
69
+ * those are listed in the `groupToType` table.
70
+ *
71
+ * Others (usually elements that wrap around other elements) often have
72
+ * recursive definitions, and thus call `getTypeOfGroup` on their inner
73
+ * elements.
74
+ */
75
+ var getTypeOfGroup = function(group) {
76
+ if (group == null) {
77
+ // Like when typesetting $^3$
78
+ return groupToType.mathord;
79
+ } else if (group.type === "supsub") {
80
+ return getTypeOfGroup(group.value.base);
81
+ } else if (group.type === "llap" || group.type === "rlap") {
82
+ return getTypeOfGroup(group.value);
83
+ } else if (group.type === "color") {
84
+ return getTypeOfGroup(group.value.value);
85
+ } else if (group.type === "sizing") {
86
+ return getTypeOfGroup(group.value.value);
87
+ } else if (group.type === "styling") {
88
+ return getTypeOfGroup(group.value.value);
89
+ } else if (group.type === "delimsizing") {
90
+ return groupToType[group.value.delimType];
91
+ } else {
92
+ return groupToType[group.type];
93
+ }
94
+ };
95
+
96
+ /**
97
+ * Sometimes, groups perform special rules when they have superscripts or
98
+ * subscripts attached to them. This function lets the `supsub` group know that
99
+ * its inner element should handle the superscripts and subscripts instead of
100
+ * handling them itself.
101
+ */
102
+ var shouldHandleSupSub = function(group, options) {
103
+ if (!group) {
104
+ return false;
105
+ } else if (group.type === "op") {
106
+ // Operators handle supsubs differently when they have limits
107
+ // (e.g. `\displaystyle\sum_2^3`)
108
+ return group.value.limits &&
109
+ (options.style.size === Style.DISPLAY.size ||
110
+ group.value.alwaysHandleSupSub);
111
+ } else if (group.type === "accent") {
112
+ return isCharacterBox(group.value.base);
113
+ } else {
114
+ return null;
115
+ }
116
+ };
117
+
118
+ /**
119
+ * Sometimes we want to pull out the innermost element of a group. In most
120
+ * cases, this will just be the group itself, but when ordgroups and colors have
121
+ * a single element, we want to pull that out.
122
+ */
123
+ var getBaseElem = function(group) {
124
+ if (!group) {
125
+ return false;
126
+ } else if (group.type === "ordgroup") {
127
+ if (group.value.length === 1) {
128
+ return getBaseElem(group.value[0]);
129
+ } else {
130
+ return group;
131
+ }
132
+ } else if (group.type === "color") {
133
+ if (group.value.value.length === 1) {
134
+ return getBaseElem(group.value.value[0]);
135
+ } else {
136
+ return group;
137
+ }
138
+ } else {
139
+ return group;
140
+ }
141
+ };
142
+
143
+ /**
144
+ * TeXbook algorithms often reference "character boxes", which are simply groups
145
+ * with a single character in them. To decide if something is a character box,
146
+ * we find its innermost group, and see if it is a single character.
147
+ */
148
+ var isCharacterBox = function(group) {
149
+ var baseElem = getBaseElem(group);
150
+
151
+ // These are all they types of groups which hold single characters
152
+ return baseElem.type === "mathord" ||
153
+ baseElem.type === "textord" ||
154
+ baseElem.type === "bin" ||
155
+ baseElem.type === "rel" ||
156
+ baseElem.type === "inner" ||
157
+ baseElem.type === "open" ||
158
+ baseElem.type === "close" ||
159
+ baseElem.type === "punct";
160
+ };
161
+
162
+ var makeNullDelimiter = function(options) {
163
+ return makeSpan([
164
+ "sizing", "reset-" + options.size, "size5",
165
+ options.style.reset(), Style.TEXT.cls(),
166
+ "nulldelimiter",
167
+ ]);
168
+ };
169
+
170
+ /**
171
+ * This is a map of group types to the function used to handle that type.
172
+ * Simpler types come at the beginning, while complicated types come afterwards.
173
+ */
174
+ var groupTypes = {};
175
+
176
+ groupTypes.mathord = function(group, options, prev) {
177
+ return buildCommon.makeOrd(group, options, "mathord");
178
+ };
179
+
180
+ groupTypes.textord = function(group, options, prev) {
181
+ return buildCommon.makeOrd(group, options, "textord");
182
+ };
183
+
184
+ groupTypes.bin = function(group, options, prev) {
185
+ var className = "mbin";
186
+ // Pull out the most recent element. Do some special handling to find
187
+ // things at the end of a \color group. Note that we don't use the same
188
+ // logic for ordgroups (which count as ords).
189
+ var prevAtom = prev;
190
+ while (prevAtom && prevAtom.type === "color") {
191
+ var atoms = prevAtom.value.value;
192
+ prevAtom = atoms[atoms.length - 1];
193
+ }
194
+ // See TeXbook pg. 442-446, Rules 5 and 6, and the text before Rule 19.
195
+ // Here, we determine whether the bin should turn into an ord. We
196
+ // currently only apply Rule 5.
197
+ if (!prev || utils.contains(["mbin", "mopen", "mrel", "mop", "mpunct"],
198
+ getTypeOfGroup(prevAtom))) {
199
+ group.type = "textord";
200
+ className = "mord";
201
+ }
202
+
203
+ return buildCommon.mathsym(
204
+ group.value, group.mode, options.getColor(), [className]);
205
+ };
206
+
207
+ groupTypes.rel = function(group, options, prev) {
208
+ return buildCommon.mathsym(
209
+ group.value, group.mode, options.getColor(), ["mrel"]);
210
+ };
211
+
212
+ groupTypes.open = function(group, options, prev) {
213
+ return buildCommon.mathsym(
214
+ group.value, group.mode, options.getColor(), ["mopen"]);
215
+ };
216
+
217
+ groupTypes.close = function(group, options, prev) {
218
+ return buildCommon.mathsym(
219
+ group.value, group.mode, options.getColor(), ["mclose"]);
220
+ };
221
+
222
+ groupTypes.inner = function(group, options, prev) {
223
+ return buildCommon.mathsym(
224
+ group.value, group.mode, options.getColor(), ["minner"]);
225
+ };
226
+
227
+ groupTypes.punct = function(group, options, prev) {
228
+ return buildCommon.mathsym(
229
+ group.value, group.mode, options.getColor(), ["mpunct"]);
230
+ };
231
+
232
+ groupTypes.ordgroup = function(group, options, prev) {
233
+ return makeSpan(
234
+ ["mord", options.style.cls()],
235
+ buildExpression(group.value, options.reset())
236
+ );
237
+ };
238
+
239
+ groupTypes.text = function(group, options, prev) {
240
+ return makeSpan(["text", "mord", options.style.cls()],
241
+ buildExpression(group.value.body, options.reset()));
242
+ };
243
+
244
+ groupTypes.color = function(group, options, prev) {
245
+ var elements = buildExpression(
246
+ group.value.value,
247
+ options.withColor(group.value.color),
248
+ prev
249
+ );
250
+
251
+ // \color isn't supposed to affect the type of the elements it contains.
252
+ // To accomplish this, we wrap the results in a fragment, so the inner
253
+ // elements will be able to directly interact with their neighbors. For
254
+ // example, `\color{red}{2 +} 3` has the same spacing as `2 + 3`
255
+ return new buildCommon.makeFragment(elements);
256
+ };
257
+
258
+ groupTypes.supsub = function(group, options, prev) {
259
+ // Superscript and subscripts are handled in the TeXbook on page
260
+ // 445-446, rules 18(a-f).
261
+
262
+ // Here is where we defer to the inner group if it should handle
263
+ // superscripts and subscripts itself.
264
+ if (shouldHandleSupSub(group.value.base, options)) {
265
+ return groupTypes[group.value.base.type](group, options, prev);
266
+ }
267
+
268
+ var base = buildGroup(group.value.base, options.reset());
269
+ var supmid;
270
+ var submid;
271
+ var sup;
272
+ var sub;
273
+
274
+ if (group.value.sup) {
275
+ sup = buildGroup(group.value.sup,
276
+ options.withStyle(options.style.sup()));
277
+ supmid = makeSpan(
278
+ [options.style.reset(), options.style.sup().cls()], [sup]);
279
+ }
280
+
281
+ if (group.value.sub) {
282
+ sub = buildGroup(group.value.sub,
283
+ options.withStyle(options.style.sub()));
284
+ submid = makeSpan(
285
+ [options.style.reset(), options.style.sub().cls()], [sub]);
286
+ }
287
+
288
+ // Rule 18a
289
+ var supShift;
290
+ var subShift;
291
+ if (isCharacterBox(group.value.base)) {
292
+ supShift = 0;
293
+ subShift = 0;
294
+ } else {
295
+ supShift = base.height - fontMetrics.metrics.supDrop;
296
+ subShift = base.depth + fontMetrics.metrics.subDrop;
297
+ }
298
+
299
+ // Rule 18c
300
+ var minSupShift;
301
+ if (options.style === Style.DISPLAY) {
302
+ minSupShift = fontMetrics.metrics.sup1;
303
+ } else if (options.style.cramped) {
304
+ minSupShift = fontMetrics.metrics.sup3;
305
+ } else {
306
+ minSupShift = fontMetrics.metrics.sup2;
307
+ }
308
+
309
+ // scriptspace is a font-size-independent size, so scale it
310
+ // appropriately
311
+ var multiplier = Style.TEXT.sizeMultiplier *
312
+ options.style.sizeMultiplier;
313
+ var scriptspace =
314
+ (0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em";
315
+
316
+ var supsub;
317
+ if (!group.value.sup) {
318
+ // Rule 18b
319
+ subShift = Math.max(
320
+ subShift, fontMetrics.metrics.sub1,
321
+ sub.height - 0.8 * fontMetrics.metrics.xHeight);
322
+
323
+ supsub = buildCommon.makeVList([
324
+ {type: "elem", elem: submid},
325
+ ], "shift", subShift, options);
326
+
327
+ supsub.children[0].style.marginRight = scriptspace;
328
+
329
+ // Subscripts shouldn't be shifted by the base's italic correction.
330
+ // Account for that by shifting the subscript back the appropriate
331
+ // amount. Note we only do this when the base is a single symbol.
332
+ if (base instanceof domTree.symbolNode) {
333
+ supsub.children[0].style.marginLeft = -base.italic + "em";
334
+ }
335
+ } else if (!group.value.sub) {
336
+ // Rule 18c, d
337
+ supShift = Math.max(supShift, minSupShift,
338
+ sup.depth + 0.25 * fontMetrics.metrics.xHeight);
339
+
340
+ supsub = buildCommon.makeVList([
341
+ {type: "elem", elem: supmid},
342
+ ], "shift", -supShift, options);
343
+
344
+ supsub.children[0].style.marginRight = scriptspace;
345
+ } else {
346
+ supShift = Math.max(
347
+ supShift, minSupShift,
348
+ sup.depth + 0.25 * fontMetrics.metrics.xHeight);
349
+ subShift = Math.max(subShift, fontMetrics.metrics.sub2);
350
+
351
+ var ruleWidth = fontMetrics.metrics.defaultRuleThickness;
352
+
353
+ // Rule 18e
354
+ if ((supShift - sup.depth) - (sub.height - subShift) <
355
+ 4 * ruleWidth) {
356
+ subShift = 4 * ruleWidth - (supShift - sup.depth) + sub.height;
357
+ var psi = 0.8 * fontMetrics.metrics.xHeight -
358
+ (supShift - sup.depth);
359
+ if (psi > 0) {
360
+ supShift += psi;
361
+ subShift -= psi;
362
+ }
363
+ }
364
+
365
+ supsub = buildCommon.makeVList([
366
+ {type: "elem", elem: submid, shift: subShift},
367
+ {type: "elem", elem: supmid, shift: -supShift},
368
+ ], "individualShift", null, options);
369
+
370
+ // See comment above about subscripts not being shifted
371
+ if (base instanceof domTree.symbolNode) {
372
+ supsub.children[0].style.marginLeft = -base.italic + "em";
373
+ }
374
+
375
+ supsub.children[0].style.marginRight = scriptspace;
376
+ supsub.children[1].style.marginRight = scriptspace;
377
+ }
378
+
379
+ return makeSpan([getTypeOfGroup(group.value.base)],
380
+ [base, supsub]);
381
+ };
382
+
383
+ groupTypes.genfrac = function(group, options, prev) {
384
+ // Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e).
385
+ // Figure out what style this fraction should be in based on the
386
+ // function used
387
+ var fstyle = options.style;
388
+ if (group.value.size === "display") {
389
+ fstyle = Style.DISPLAY;
390
+ } else if (group.value.size === "text") {
391
+ fstyle = Style.TEXT;
392
+ }
393
+
394
+ var nstyle = fstyle.fracNum();
395
+ var dstyle = fstyle.fracDen();
396
+
397
+ var numer = buildGroup(group.value.numer, options.withStyle(nstyle));
398
+ var numerreset = makeSpan([fstyle.reset(), nstyle.cls()], [numer]);
399
+
400
+ var denom = buildGroup(group.value.denom, options.withStyle(dstyle));
401
+ var denomreset = makeSpan([fstyle.reset(), dstyle.cls()], [denom]);
402
+
403
+ var ruleWidth;
404
+ if (group.value.hasBarLine) {
405
+ ruleWidth = fontMetrics.metrics.defaultRuleThickness /
406
+ options.style.sizeMultiplier;
407
+ } else {
408
+ ruleWidth = 0;
409
+ }
410
+
411
+ // Rule 15b
412
+ var numShift;
413
+ var clearance;
414
+ var denomShift;
415
+ if (fstyle.size === Style.DISPLAY.size) {
416
+ numShift = fontMetrics.metrics.num1;
417
+ if (ruleWidth > 0) {
418
+ clearance = 3 * ruleWidth;
419
+ } else {
420
+ clearance = 7 * fontMetrics.metrics.defaultRuleThickness;
421
+ }
422
+ denomShift = fontMetrics.metrics.denom1;
423
+ } else {
424
+ if (ruleWidth > 0) {
425
+ numShift = fontMetrics.metrics.num2;
426
+ clearance = ruleWidth;
427
+ } else {
428
+ numShift = fontMetrics.metrics.num3;
429
+ clearance = 3 * fontMetrics.metrics.defaultRuleThickness;
430
+ }
431
+ denomShift = fontMetrics.metrics.denom2;
432
+ }
433
+
434
+ var frac;
435
+ if (ruleWidth === 0) {
436
+ // Rule 15c
437
+ var candiateClearance =
438
+ (numShift - numer.depth) - (denom.height - denomShift);
439
+ if (candiateClearance < clearance) {
440
+ numShift += 0.5 * (clearance - candiateClearance);
441
+ denomShift += 0.5 * (clearance - candiateClearance);
442
+ }
443
+
444
+ frac = buildCommon.makeVList([
445
+ {type: "elem", elem: denomreset, shift: denomShift},
446
+ {type: "elem", elem: numerreset, shift: -numShift},
447
+ ], "individualShift", null, options);
448
+ } else {
449
+ // Rule 15d
450
+ var axisHeight = fontMetrics.metrics.axisHeight;
451
+
452
+ if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth) <
453
+ clearance) {
454
+ numShift +=
455
+ clearance - ((numShift - numer.depth) -
456
+ (axisHeight + 0.5 * ruleWidth));
457
+ }
458
+
459
+ if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift) <
460
+ clearance) {
461
+ denomShift +=
462
+ clearance - ((axisHeight - 0.5 * ruleWidth) -
463
+ (denom.height - denomShift));
464
+ }
465
+
466
+ var mid = makeSpan(
467
+ [options.style.reset(), Style.TEXT.cls(), "frac-line"]);
468
+ // Manually set the height of the line because its height is
469
+ // created in CSS
470
+ mid.height = ruleWidth;
471
+
472
+ var midShift = -(axisHeight - 0.5 * ruleWidth);
473
+
474
+ frac = buildCommon.makeVList([
475
+ {type: "elem", elem: denomreset, shift: denomShift},
476
+ {type: "elem", elem: mid, shift: midShift},
477
+ {type: "elem", elem: numerreset, shift: -numShift},
478
+ ], "individualShift", null, options);
479
+ }
480
+
481
+ // Since we manually change the style sometimes (with \dfrac or \tfrac),
482
+ // account for the possible size change here.
483
+ frac.height *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
484
+ frac.depth *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
485
+
486
+ // Rule 15e
487
+ var delimSize;
488
+ if (fstyle.size === Style.DISPLAY.size) {
489
+ delimSize = fontMetrics.metrics.delim1;
490
+ } else {
491
+ delimSize = fontMetrics.metrics.getDelim2(fstyle);
492
+ }
493
+
494
+ var leftDelim;
495
+ var rightDelim;
496
+ if (group.value.leftDelim == null) {
497
+ leftDelim = makeNullDelimiter(options);
498
+ } else {
499
+ leftDelim = delimiter.customSizedDelim(
500
+ group.value.leftDelim, delimSize, true,
501
+ options.withStyle(fstyle), group.mode);
502
+ }
503
+ if (group.value.rightDelim == null) {
504
+ rightDelim = makeNullDelimiter(options);
505
+ } else {
506
+ rightDelim = delimiter.customSizedDelim(
507
+ group.value.rightDelim, delimSize, true,
508
+ options.withStyle(fstyle), group.mode);
509
+ }
510
+
511
+ return makeSpan(
512
+ ["mord", options.style.reset(), fstyle.cls()],
513
+ [leftDelim, makeSpan(["mfrac"], [frac]), rightDelim],
514
+ options.getColor());
515
+ };
516
+
517
+ groupTypes.array = function(group, options, prev) {
518
+ var r;
519
+ var c;
520
+ var nr = group.value.body.length;
521
+ var nc = 0;
522
+ var body = new Array(nr);
523
+
524
+ // Horizontal spacing
525
+ var pt = 1 / fontMetrics.metrics.ptPerEm;
526
+ var arraycolsep = 5 * pt; // \arraycolsep in article.cls
527
+
528
+ // Vertical spacing
529
+ var baselineskip = 12 * pt; // see size10.clo
530
+ // Default \arraystretch from lttab.dtx
531
+ // TODO(gagern): may get redefined once we have user-defined macros
532
+ var arraystretch = utils.deflt(group.value.arraystretch, 1);
533
+ var arrayskip = arraystretch * baselineskip;
534
+ var arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
535
+ var arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
536
+
537
+ var totalHeight = 0;
538
+ for (r = 0; r < group.value.body.length; ++r) {
539
+ var inrow = group.value.body[r];
540
+ var height = arstrutHeight; // \@array adds an \@arstrut
541
+ var depth = arstrutDepth; // to each tow (via the template)
542
+
543
+ if (nc < inrow.length) {
544
+ nc = inrow.length;
545
+ }
546
+
547
+ var outrow = new Array(inrow.length);
548
+ for (c = 0; c < inrow.length; ++c) {
549
+ var elt = buildGroup(inrow[c], options);
550
+ if (depth < elt.depth) {
551
+ depth = elt.depth;
552
+ }
553
+ if (height < elt.height) {
554
+ height = elt.height;
555
+ }
556
+ outrow[c] = elt;
557
+ }
558
+
559
+ var gap = 0;
560
+ if (group.value.rowGaps[r]) {
561
+ gap = group.value.rowGaps[r].value;
562
+ switch (gap.unit) {
563
+ case "em":
564
+ gap = gap.number;
565
+ break;
566
+ case "ex":
567
+ gap = gap.number * fontMetrics.metrics.emPerEx;
568
+ break;
569
+ default:
570
+ console.error("Can't handle unit " + gap.unit);
571
+ gap = 0;
572
+ }
573
+ if (gap > 0) { // \@argarraycr
574
+ gap += arstrutDepth;
575
+ if (depth < gap) {
576
+ depth = gap; // \@xargarraycr
577
+ }
578
+ gap = 0;
579
+ }
580
+ }
581
+
582
+ outrow.height = height;
583
+ outrow.depth = depth;
584
+ totalHeight += height;
585
+ outrow.pos = totalHeight;
586
+ totalHeight += depth + gap; // \@yargarraycr
587
+ body[r] = outrow;
588
+ }
589
+
590
+ var offset = totalHeight / 2 + fontMetrics.metrics.axisHeight;
591
+ var colDescriptions = group.value.cols || [];
592
+ var cols = [];
593
+ var colSep;
594
+ var colDescrNum;
595
+ for (c = 0, colDescrNum = 0;
596
+ // Continue while either there are more columns or more column
597
+ // descriptions, so trailing separators don't get lost.
598
+ c < nc || colDescrNum < colDescriptions.length;
599
+ ++c, ++colDescrNum) {
600
+
601
+ var colDescr = colDescriptions[colDescrNum] || {};
602
+
603
+ var firstSeparator = true;
604
+ while (colDescr.type === "separator") {
605
+ // If there is more than one separator in a row, add a space
606
+ // between them.
607
+ if (!firstSeparator) {
608
+ colSep = makeSpan(["arraycolsep"], []);
609
+ colSep.style.width =
610
+ fontMetrics.metrics.doubleRuleSep + "em";
611
+ cols.push(colSep);
612
+ }
613
+
614
+ if (colDescr.separator === "|") {
615
+ var separator = makeSpan(
616
+ ["vertical-separator"],
617
+ []);
618
+ separator.style.height = totalHeight + "em";
619
+ separator.style.verticalAlign =
620
+ -(totalHeight - offset) + "em";
621
+
622
+ cols.push(separator);
623
+ } else {
624
+ throw new ParseError(
625
+ "Invalid separator type: " + colDescr.separator);
626
+ }
627
+
628
+ colDescrNum++;
629
+ colDescr = colDescriptions[colDescrNum] || {};
630
+ firstSeparator = false;
631
+ }
632
+
633
+ if (c >= nc) {
634
+ continue;
635
+ }
636
+
637
+ var sepwidth;
638
+ if (c > 0 || group.value.hskipBeforeAndAfter) {
639
+ sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
640
+ if (sepwidth !== 0) {
641
+ colSep = makeSpan(["arraycolsep"], []);
642
+ colSep.style.width = sepwidth + "em";
643
+ cols.push(colSep);
644
+ }
645
+ }
646
+
647
+ var col = [];
648
+ for (r = 0; r < nr; ++r) {
649
+ var row = body[r];
650
+ var elem = row[c];
651
+ if (!elem) {
652
+ continue;
653
+ }
654
+ var shift = row.pos - offset;
655
+ elem.depth = row.depth;
656
+ elem.height = row.height;
657
+ col.push({type: "elem", elem: elem, shift: shift});
658
+ }
659
+
660
+ col = buildCommon.makeVList(col, "individualShift", null, options);
661
+ col = makeSpan(
662
+ ["col-align-" + (colDescr.align || "c")],
663
+ [col]);
664
+ cols.push(col);
665
+
666
+ if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
667
+ sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
668
+ if (sepwidth !== 0) {
669
+ colSep = makeSpan(["arraycolsep"], []);
670
+ colSep.style.width = sepwidth + "em";
671
+ cols.push(colSep);
672
+ }
673
+ }
674
+ }
675
+ body = makeSpan(["mtable"], cols);
676
+ return makeSpan(["mord"], [body], options.getColor());
677
+ };
678
+
679
+ groupTypes.spacing = function(group, options, prev) {
680
+ if (group.value === "\\ " || group.value === "\\space" ||
681
+ group.value === " " || group.value === "~") {
682
+ // Spaces are generated by adding an actual space. Each of these
683
+ // things has an entry in the symbols table, so these will be turned
684
+ // into appropriate outputs.
685
+ return makeSpan(
686
+ ["mord", "mspace"],
687
+ [buildCommon.mathsym(group.value, group.mode)]
688
+ );
689
+ } else {
690
+ // Other kinds of spaces are of arbitrary width. We use CSS to
691
+ // generate these.
692
+ return makeSpan(
693
+ ["mord", "mspace",
694
+ buildCommon.spacingFunctions[group.value].className]);
695
+ }
696
+ };
697
+
698
+ groupTypes.llap = function(group, options, prev) {
699
+ var inner = makeSpan(
700
+ ["inner"], [buildGroup(group.value.body, options.reset())]);
701
+ var fix = makeSpan(["fix"], []);
702
+ return makeSpan(
703
+ ["llap", options.style.cls()], [inner, fix]);
704
+ };
705
+
706
+ groupTypes.rlap = function(group, options, prev) {
707
+ var inner = makeSpan(
708
+ ["inner"], [buildGroup(group.value.body, options.reset())]);
709
+ var fix = makeSpan(["fix"], []);
710
+ return makeSpan(
711
+ ["rlap", options.style.cls()], [inner, fix]);
712
+ };
713
+
714
+ groupTypes.op = function(group, options, prev) {
715
+ // Operators are handled in the TeXbook pg. 443-444, rule 13(a).
716
+ var supGroup;
717
+ var subGroup;
718
+ var hasLimits = false;
719
+ if (group.type === "supsub" ) {
720
+ // If we have limits, supsub will pass us its group to handle. Pull
721
+ // out the superscript and subscript and set the group to the op in
722
+ // its base.
723
+ supGroup = group.value.sup;
724
+ subGroup = group.value.sub;
725
+ group = group.value.base;
726
+ hasLimits = true;
727
+ }
728
+
729
+ // Most operators have a large successor symbol, but these don't.
730
+ var noSuccessor = [
731
+ "\\smallint",
732
+ ];
733
+
734
+ var large = false;
735
+ if (options.style.size === Style.DISPLAY.size &&
736
+ group.value.symbol &&
737
+ !utils.contains(noSuccessor, group.value.body)) {
738
+
739
+ // Most symbol operators get larger in displaystyle (rule 13)
740
+ large = true;
741
+ }
742
+
743
+ var base;
744
+ var baseShift = 0;
745
+ var slant = 0;
746
+ if (group.value.symbol) {
747
+ // If this is a symbol, create the symbol.
748
+ var style = large ? "Size2-Regular" : "Size1-Regular";
749
+ base = buildCommon.makeSymbol(
750
+ group.value.body, style, "math", options.getColor(),
751
+ ["op-symbol", large ? "large-op" : "small-op", "mop"]);
752
+
753
+ // Shift the symbol so its center lies on the axis (rule 13). It
754
+ // appears that our fonts have the centers of the symbols already
755
+ // almost on the axis, so these numbers are very small. Note we
756
+ // don't actually apply this here, but instead it is used either in
757
+ // the vlist creation or separately when there are no limits.
758
+ baseShift = (base.height - base.depth) / 2 -
759
+ fontMetrics.metrics.axisHeight *
760
+ options.style.sizeMultiplier;
761
+
762
+ // The slant of the symbol is just its italic correction.
763
+ slant = base.italic;
764
+ } else {
765
+ // Otherwise, this is a text operator. Build the text from the
766
+ // operator's name.
767
+ // TODO(emily): Add a space in the middle of some of these
768
+ // operators, like \limsup
769
+ var output = [];
770
+ for (var i = 1; i < group.value.body.length; i++) {
771
+ output.push(buildCommon.mathsym(group.value.body[i], group.mode));
772
+ }
773
+ base = makeSpan(["mop"], output, options.getColor());
774
+ }
775
+
776
+ if (hasLimits) {
777
+ // IE 8 clips \int if it is in a display: inline-block. We wrap it
778
+ // in a new span so it is an inline, and works.
779
+ base = makeSpan([], [base]);
780
+
781
+ var supmid;
782
+ var supKern;
783
+ var submid;
784
+ var subKern;
785
+ // We manually have to handle the superscripts and subscripts. This,
786
+ // aside from the kern calculations, is copied from supsub.
787
+ if (supGroup) {
788
+ var sup = buildGroup(
789
+ supGroup, options.withStyle(options.style.sup()));
790
+ supmid = makeSpan(
791
+ [options.style.reset(), options.style.sup().cls()], [sup]);
792
+
793
+ supKern = Math.max(
794
+ fontMetrics.metrics.bigOpSpacing1,
795
+ fontMetrics.metrics.bigOpSpacing3 - sup.depth);
796
+ }
797
+
798
+ if (subGroup) {
799
+ var sub = buildGroup(
800
+ subGroup, options.withStyle(options.style.sub()));
801
+ submid = makeSpan(
802
+ [options.style.reset(), options.style.sub().cls()],
803
+ [sub]);
804
+
805
+ subKern = Math.max(
806
+ fontMetrics.metrics.bigOpSpacing2,
807
+ fontMetrics.metrics.bigOpSpacing4 - sub.height);
808
+ }
809
+
810
+ // Build the final group as a vlist of the possible subscript, base,
811
+ // and possible superscript.
812
+ var finalGroup;
813
+ var top;
814
+ var bottom;
815
+ if (!supGroup) {
816
+ top = base.height - baseShift;
817
+
818
+ finalGroup = buildCommon.makeVList([
819
+ {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
820
+ {type: "elem", elem: submid},
821
+ {type: "kern", size: subKern},
822
+ {type: "elem", elem: base},
823
+ ], "top", top, options);
824
+
825
+ // Here, we shift the limits by the slant of the symbol. Note
826
+ // that we are supposed to shift the limits by 1/2 of the slant,
827
+ // but since we are centering the limits adding a full slant of
828
+ // margin will shift by 1/2 that.
829
+ finalGroup.children[0].style.marginLeft = -slant + "em";
830
+ } else if (!subGroup) {
831
+ bottom = base.depth + baseShift;
832
+
833
+ finalGroup = buildCommon.makeVList([
834
+ {type: "elem", elem: base},
835
+ {type: "kern", size: supKern},
836
+ {type: "elem", elem: supmid},
837
+ {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
838
+ ], "bottom", bottom, options);
839
+
840
+ // See comment above about slants
841
+ finalGroup.children[1].style.marginLeft = slant + "em";
842
+ } else if (!supGroup && !subGroup) {
843
+ // This case probably shouldn't occur (this would mean the
844
+ // supsub was sending us a group with no superscript or
845
+ // subscript) but be safe.
846
+ return base;
847
+ } else {
848
+ bottom = fontMetrics.metrics.bigOpSpacing5 +
849
+ submid.height + submid.depth +
850
+ subKern +
851
+ base.depth + baseShift;
852
+
853
+ finalGroup = buildCommon.makeVList([
854
+ {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
855
+ {type: "elem", elem: submid},
856
+ {type: "kern", size: subKern},
857
+ {type: "elem", elem: base},
858
+ {type: "kern", size: supKern},
859
+ {type: "elem", elem: supmid},
860
+ {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
861
+ ], "bottom", bottom, options);
862
+
863
+ // See comment above about slants
864
+ finalGroup.children[0].style.marginLeft = -slant + "em";
865
+ finalGroup.children[2].style.marginLeft = slant + "em";
866
+ }
867
+
868
+ return makeSpan(["mop", "op-limits"], [finalGroup]);
869
+ } else {
870
+ if (group.value.symbol) {
871
+ base.style.top = baseShift + "em";
872
+ }
873
+
874
+ return base;
875
+ }
876
+ };
877
+
878
+ groupTypes.katex = function(group, options, prev) {
879
+ // The KaTeX logo. The offsets for the K and a were chosen to look
880
+ // good, but the offsets for the T, E, and X were taken from the
881
+ // definition of \TeX in TeX (see TeXbook pg. 356)
882
+ var k = makeSpan(
883
+ ["k"], [buildCommon.mathsym("K", group.mode)]);
884
+ var a = makeSpan(
885
+ ["a"], [buildCommon.mathsym("A", group.mode)]);
886
+
887
+ a.height = (a.height + 0.2) * 0.75;
888
+ a.depth = (a.height - 0.2) * 0.75;
889
+
890
+ var t = makeSpan(
891
+ ["t"], [buildCommon.mathsym("T", group.mode)]);
892
+ var e = makeSpan(
893
+ ["e"], [buildCommon.mathsym("E", group.mode)]);
894
+
895
+ e.height = (e.height - 0.2155);
896
+ e.depth = (e.depth + 0.2155);
897
+
898
+ var x = makeSpan(
899
+ ["x"], [buildCommon.mathsym("X", group.mode)]);
900
+
901
+ return makeSpan(
902
+ ["katex-logo", "mord"], [k, a, t, e, x], options.getColor());
903
+ };
904
+
905
+ groupTypes.overline = function(group, options, prev) {
906
+ // Overlines are handled in the TeXbook pg 443, Rule 9.
907
+
908
+ // Build the inner group in the cramped style.
909
+ var innerGroup = buildGroup(group.value.body,
910
+ options.withStyle(options.style.cramp()));
911
+
912
+ var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
913
+ options.style.sizeMultiplier;
914
+
915
+ // Create the line above the body
916
+ var line = makeSpan(
917
+ [options.style.reset(), Style.TEXT.cls(), "overline-line"]);
918
+ line.height = ruleWidth;
919
+ line.maxFontSize = 1.0;
920
+
921
+ // Generate the vlist, with the appropriate kerns
922
+ var vlist = buildCommon.makeVList([
923
+ {type: "elem", elem: innerGroup},
924
+ {type: "kern", size: 3 * ruleWidth},
925
+ {type: "elem", elem: line},
926
+ {type: "kern", size: ruleWidth},
927
+ ], "firstBaseline", null, options);
928
+
929
+ return makeSpan(["overline", "mord"], [vlist], options.getColor());
930
+ };
931
+
932
+ groupTypes.underline = function(group, options, prev) {
933
+ // Underlines are handled in the TeXbook pg 443, Rule 10.
934
+
935
+ // Build the inner group.
936
+ var innerGroup = buildGroup(group.value.body, options);
937
+
938
+ var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
939
+ options.style.sizeMultiplier;
940
+
941
+ // Create the line above the body
942
+ var line = makeSpan(
943
+ [options.style.reset(), Style.TEXT.cls(), "underline-line"]);
944
+ line.height = ruleWidth;
945
+ line.maxFontSize = 1.0;
946
+
947
+ // Generate the vlist, with the appropriate kerns
948
+ var vlist = buildCommon.makeVList([
949
+ {type: "kern", size: ruleWidth},
950
+ {type: "elem", elem: line},
951
+ {type: "kern", size: 3 * ruleWidth},
952
+ {type: "elem", elem: innerGroup},
953
+ ], "top", innerGroup.height, options);
954
+
955
+ return makeSpan(["underline", "mord"], [vlist], options.getColor());
956
+ };
957
+
958
+ groupTypes.sqrt = function(group, options, prev) {
959
+ // Square roots are handled in the TeXbook pg. 443, Rule 11.
960
+
961
+ // First, we do the same steps as in overline to build the inner group
962
+ // and line
963
+ var inner = buildGroup(group.value.body,
964
+ options.withStyle(options.style.cramp()));
965
+
966
+ var ruleWidth = fontMetrics.metrics.defaultRuleThickness /
967
+ options.style.sizeMultiplier;
968
+
969
+ var line = makeSpan(
970
+ [options.style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
971
+ options.getColor());
972
+ line.height = ruleWidth;
973
+ line.maxFontSize = 1.0;
974
+
975
+ var phi = ruleWidth;
976
+ if (options.style.id < Style.TEXT.id) {
977
+ phi = fontMetrics.metrics.xHeight;
978
+ }
979
+
980
+ // Calculate the clearance between the body and line
981
+ var lineClearance = ruleWidth + phi / 4;
982
+
983
+ var innerHeight =
984
+ (inner.height + inner.depth) * options.style.sizeMultiplier;
985
+ var minDelimiterHeight = innerHeight + lineClearance + ruleWidth;
986
+
987
+ // Create a \surd delimiter of the required minimum size
988
+ var delim = makeSpan(["sqrt-sign"], [
989
+ delimiter.customSizedDelim("\\surd", minDelimiterHeight,
990
+ false, options, group.mode)],
991
+ options.getColor());
992
+
993
+ var delimDepth = (delim.height + delim.depth) - ruleWidth;
994
+
995
+ // Adjust the clearance based on the delimiter size
996
+ if (delimDepth > inner.height + inner.depth + lineClearance) {
997
+ lineClearance =
998
+ (lineClearance + delimDepth - inner.height - inner.depth) / 2;
999
+ }
1000
+
1001
+ // Shift the delimiter so that its top lines up with the top of the line
1002
+ var delimShift = -(inner.height + lineClearance + ruleWidth) + delim.height;
1003
+ delim.style.top = delimShift + "em";
1004
+ delim.height -= delimShift;
1005
+ delim.depth += delimShift;
1006
+
1007
+ // We add a special case here, because even when `inner` is empty, we
1008
+ // still get a line. So, we use a simple heuristic to decide if we
1009
+ // should omit the body entirely. (note this doesn't work for something
1010
+ // like `\sqrt{\rlap{x}}`, but if someone is doing that they deserve for
1011
+ // it not to work.
1012
+ var body;
1013
+ if (inner.height === 0 && inner.depth === 0) {
1014
+ body = makeSpan();
1015
+ } else {
1016
+ body = buildCommon.makeVList([
1017
+ {type: "elem", elem: inner},
1018
+ {type: "kern", size: lineClearance},
1019
+ {type: "elem", elem: line},
1020
+ {type: "kern", size: ruleWidth},
1021
+ ], "firstBaseline", null, options);
1022
+ }
1023
+
1024
+ if (!group.value.index) {
1025
+ return makeSpan(["sqrt", "mord"], [delim, body]);
1026
+ } else {
1027
+ // Handle the optional root index
1028
+
1029
+ // The index is always in scriptscript style
1030
+ var root = buildGroup(
1031
+ group.value.index,
1032
+ options.withStyle(Style.SCRIPTSCRIPT));
1033
+ var rootWrap = makeSpan(
1034
+ [options.style.reset(), Style.SCRIPTSCRIPT.cls()],
1035
+ [root]);
1036
+
1037
+ // Figure out the height and depth of the inner part
1038
+ var innerRootHeight = Math.max(delim.height, body.height);
1039
+ var innerRootDepth = Math.max(delim.depth, body.depth);
1040
+
1041
+ // The amount the index is shifted by. This is taken from the TeX
1042
+ // source, in the definition of `\r@@t`.
1043
+ var toShift = 0.6 * (innerRootHeight - innerRootDepth);
1044
+
1045
+ // Build a VList with the superscript shifted up correctly
1046
+ var rootVList = buildCommon.makeVList(
1047
+ [{type: "elem", elem: rootWrap}],
1048
+ "shift", -toShift, options);
1049
+ // Add a class surrounding it so we can add on the appropriate
1050
+ // kerning
1051
+ var rootVListWrap = makeSpan(["root"], [rootVList]);
1052
+
1053
+ return makeSpan(["sqrt", "mord"], [rootVListWrap, delim, body]);
1054
+ }
1055
+ };
1056
+
1057
+ groupTypes.sizing = function(group, options, prev) {
1058
+ // Handle sizing operators like \Huge. Real TeX doesn't actually allow
1059
+ // these functions inside of math expressions, so we do some special
1060
+ // handling.
1061
+ var inner = buildExpression(group.value.value,
1062
+ options.withSize(group.value.size), prev);
1063
+
1064
+ var span = makeSpan(["mord"],
1065
+ [makeSpan(["sizing", "reset-" + options.size, group.value.size,
1066
+ options.style.cls()],
1067
+ inner)]);
1068
+
1069
+ // Calculate the correct maxFontSize manually
1070
+ var fontSize = buildCommon.sizingMultiplier[group.value.size];
1071
+ span.maxFontSize = fontSize * options.style.sizeMultiplier;
1072
+
1073
+ return span;
1074
+ };
1075
+
1076
+ groupTypes.styling = function(group, options, prev) {
1077
+ // Style changes are handled in the TeXbook on pg. 442, Rule 3.
1078
+
1079
+ // Figure out what style we're changing to.
1080
+ var style = {
1081
+ "display": Style.DISPLAY,
1082
+ "text": Style.TEXT,
1083
+ "script": Style.SCRIPT,
1084
+ "scriptscript": Style.SCRIPTSCRIPT,
1085
+ };
1086
+
1087
+ var newStyle = style[group.value.style];
1088
+
1089
+ // Build the inner expression in the new style.
1090
+ var inner = buildExpression(
1091
+ group.value.value, options.withStyle(newStyle), prev);
1092
+
1093
+ return makeSpan([options.style.reset(), newStyle.cls()], inner);
1094
+ };
1095
+
1096
+ groupTypes.font = function(group, options, prev) {
1097
+ var font = group.value.font;
1098
+ return buildGroup(group.value.body, options.withFont(font), prev);
1099
+ };
1100
+
1101
+ groupTypes.delimsizing = function(group, options, prev) {
1102
+ var delim = group.value.value;
1103
+
1104
+ if (delim === ".") {
1105
+ // Empty delimiters still count as elements, even though they don't
1106
+ // show anything.
1107
+ return makeSpan([groupToType[group.value.delimType]]);
1108
+ }
1109
+
1110
+ // Use delimiter.sizedDelim to generate the delimiter.
1111
+ return makeSpan(
1112
+ [groupToType[group.value.delimType]],
1113
+ [delimiter.sizedDelim(
1114
+ delim, group.value.size, options, group.mode)]);
1115
+ };
1116
+
1117
+ groupTypes.leftright = function(group, options, prev) {
1118
+ // Build the inner expression
1119
+ var inner = buildExpression(group.value.body, options.reset());
1120
+
1121
+ var innerHeight = 0;
1122
+ var innerDepth = 0;
1123
+
1124
+ // Calculate its height and depth
1125
+ for (var i = 0; i < inner.length; i++) {
1126
+ innerHeight = Math.max(inner[i].height, innerHeight);
1127
+ innerDepth = Math.max(inner[i].depth, innerDepth);
1128
+ }
1129
+
1130
+ // The size of delimiters is the same, regardless of what style we are
1131
+ // in. Thus, to correctly calculate the size of delimiter we need around
1132
+ // a group, we scale down the inner size based on the size.
1133
+ innerHeight *= options.style.sizeMultiplier;
1134
+ innerDepth *= options.style.sizeMultiplier;
1135
+
1136
+ var leftDelim;
1137
+ if (group.value.left === ".") {
1138
+ // Empty delimiters in \left and \right make null delimiter spaces.
1139
+ leftDelim = makeNullDelimiter(options);
1140
+ } else {
1141
+ // Otherwise, use leftRightDelim to generate the correct sized
1142
+ // delimiter.
1143
+ leftDelim = delimiter.leftRightDelim(
1144
+ group.value.left, innerHeight, innerDepth, options,
1145
+ group.mode);
1146
+ }
1147
+ // Add it to the beginning of the expression
1148
+ inner.unshift(leftDelim);
1149
+
1150
+ var rightDelim;
1151
+ // Same for the right delimiter
1152
+ if (group.value.right === ".") {
1153
+ rightDelim = makeNullDelimiter(options);
1154
+ } else {
1155
+ rightDelim = delimiter.leftRightDelim(
1156
+ group.value.right, innerHeight, innerDepth, options,
1157
+ group.mode);
1158
+ }
1159
+ // Add it to the end of the expression.
1160
+ inner.push(rightDelim);
1161
+
1162
+ return makeSpan(
1163
+ ["minner", options.style.cls()], inner, options.getColor());
1164
+ };
1165
+
1166
+ groupTypes.rule = function(group, options, prev) {
1167
+ // Make an empty span for the rule
1168
+ var rule = makeSpan(["mord", "rule"], [], options.getColor());
1169
+
1170
+ // Calculate the shift, width, and height of the rule, and account for units
1171
+ var shift = 0;
1172
+ if (group.value.shift) {
1173
+ shift = group.value.shift.number;
1174
+ if (group.value.shift.unit === "ex") {
1175
+ shift *= fontMetrics.metrics.xHeight;
1176
+ }
1177
+ }
1178
+
1179
+ var width = group.value.width.number;
1180
+ if (group.value.width.unit === "ex") {
1181
+ width *= fontMetrics.metrics.xHeight;
1182
+ }
1183
+
1184
+ var height = group.value.height.number;
1185
+ if (group.value.height.unit === "ex") {
1186
+ height *= fontMetrics.metrics.xHeight;
1187
+ }
1188
+
1189
+ // The sizes of rules are absolute, so make it larger if we are in a
1190
+ // smaller style.
1191
+ shift /= options.style.sizeMultiplier;
1192
+ width /= options.style.sizeMultiplier;
1193
+ height /= options.style.sizeMultiplier;
1194
+
1195
+ // Style the rule to the right size
1196
+ rule.style.borderRightWidth = width + "em";
1197
+ rule.style.borderTopWidth = height + "em";
1198
+ rule.style.bottom = shift + "em";
1199
+
1200
+ // Record the height and width
1201
+ rule.width = width;
1202
+ rule.height = height + shift;
1203
+ rule.depth = -shift;
1204
+
1205
+ return rule;
1206
+ };
1207
+
1208
+ groupTypes.accent = function(group, options, prev) {
1209
+ // Accents are handled in the TeXbook pg. 443, rule 12.
1210
+ var base = group.value.base;
1211
+
1212
+ var supsubGroup;
1213
+ if (group.type === "supsub") {
1214
+ // If our base is a character box, and we have superscripts and
1215
+ // subscripts, the supsub will defer to us. In particular, we want
1216
+ // to attach the superscripts and subscripts to the inner body (so
1217
+ // that the position of the superscripts and subscripts won't be
1218
+ // affected by the height of the accent). We accomplish this by
1219
+ // sticking the base of the accent into the base of the supsub, and
1220
+ // rendering that, while keeping track of where the accent is.
1221
+
1222
+ // The supsub group is the group that was passed in
1223
+ var supsub = group;
1224
+ // The real accent group is the base of the supsub group
1225
+ group = supsub.value.base;
1226
+ // The character box is the base of the accent group
1227
+ base = group.value.base;
1228
+ // Stick the character box into the base of the supsub group
1229
+ supsub.value.base = base;
1230
+
1231
+ // Rerender the supsub group with its new base, and store that
1232
+ // result.
1233
+ supsubGroup = buildGroup(
1234
+ supsub, options.reset(), prev);
1235
+ }
1236
+
1237
+ // Build the base group
1238
+ var body = buildGroup(
1239
+ base, options.withStyle(options.style.cramp()));
1240
+
1241
+ // Calculate the skew of the accent. This is based on the line "If the
1242
+ // nucleus is not a single character, let s = 0; otherwise set s to the
1243
+ // kern amount for the nucleus followed by the \skewchar of its font."
1244
+ // Note that our skew metrics are just the kern between each character
1245
+ // and the skewchar.
1246
+ var skew;
1247
+ if (isCharacterBox(base)) {
1248
+ // If the base is a character box, then we want the skew of the
1249
+ // innermost character. To do that, we find the innermost character:
1250
+ var baseChar = getBaseElem(base);
1251
+ // Then, we render its group to get the symbol inside it
1252
+ var baseGroup = buildGroup(
1253
+ baseChar, options.withStyle(options.style.cramp()));
1254
+ // Finally, we pull the skew off of the symbol.
1255
+ skew = baseGroup.skew;
1256
+ // Note that we now throw away baseGroup, because the layers we
1257
+ // removed with getBaseElem might contain things like \color which
1258
+ // we can't get rid of.
1259
+ // TODO(emily): Find a better way to get the skew
1260
+ } else {
1261
+ skew = 0;
1262
+ }
1263
+
1264
+ // calculate the amount of space between the body and the accent
1265
+ var clearance = Math.min(body.height, fontMetrics.metrics.xHeight);
1266
+
1267
+ // Build the accent
1268
+ var accent = buildCommon.makeSymbol(
1269
+ group.value.accent, "Main-Regular", "math", options.getColor());
1270
+ // Remove the italic correction of the accent, because it only serves to
1271
+ // shift the accent over to a place we don't want.
1272
+ accent.italic = 0;
1273
+
1274
+ // The \vec character that the fonts use is a combining character, and
1275
+ // thus shows up much too far to the left. To account for this, we add a
1276
+ // specific class which shifts the accent over to where we want it.
1277
+ // TODO(emily): Fix this in a better way, like by changing the font
1278
+ var vecClass = group.value.accent === "\\vec" ? "accent-vec" : null;
1279
+
1280
+ var accentBody = makeSpan(["accent-body", vecClass], [
1281
+ makeSpan([], [accent])]);
1282
+
1283
+ accentBody = buildCommon.makeVList([
1284
+ {type: "elem", elem: body},
1285
+ {type: "kern", size: -clearance},
1286
+ {type: "elem", elem: accentBody},
1287
+ ], "firstBaseline", null, options);
1288
+
1289
+ // Shift the accent over by the skew. Note we shift by twice the skew
1290
+ // because we are centering the accent, so by adding 2*skew to the left,
1291
+ // we shift it to the right by 1*skew.
1292
+ accentBody.children[1].style.marginLeft = 2 * skew + "em";
1293
+
1294
+ var accentWrap = makeSpan(["mord", "accent"], [accentBody]);
1295
+
1296
+ if (supsubGroup) {
1297
+ // Here, we replace the "base" child of the supsub with our newly
1298
+ // generated accent.
1299
+ supsubGroup.children[0] = accentWrap;
1300
+
1301
+ // Since we don't rerun the height calculation after replacing the
1302
+ // accent, we manually recalculate height.
1303
+ supsubGroup.height = Math.max(accentWrap.height, supsubGroup.height);
1304
+
1305
+ // Accents should always be ords, even when their innards are not.
1306
+ supsubGroup.classes[0] = "mord";
1307
+
1308
+ return supsubGroup;
1309
+ } else {
1310
+ return accentWrap;
1311
+ }
1312
+ };
1313
+
1314
+ groupTypes.phantom = function(group, options, prev) {
1315
+ var elements = buildExpression(
1316
+ group.value.value,
1317
+ options.withPhantom(),
1318
+ prev
1319
+ );
1320
+
1321
+ // \phantom isn't supposed to affect the elements it contains.
1322
+ // See "color" for more details.
1323
+ return new buildCommon.makeFragment(elements);
1324
+ };
1325
+
1326
+ /**
1327
+ * buildGroup is the function that takes a group and calls the correct groupType
1328
+ * function for it. It also handles the interaction of size and style changes
1329
+ * between parents and children.
1330
+ */
1331
+ var buildGroup = function(group, options, prev) {
1332
+ if (!group) {
1333
+ return makeSpan();
1334
+ }
1335
+
1336
+ if (groupTypes[group.type]) {
1337
+ // Call the groupTypes function
1338
+ var groupNode = groupTypes[group.type](group, options, prev);
1339
+ var multiplier;
1340
+
1341
+ // If the style changed between the parent and the current group,
1342
+ // account for the size difference
1343
+ if (options.style !== options.parentStyle) {
1344
+ multiplier = options.style.sizeMultiplier /
1345
+ options.parentStyle.sizeMultiplier;
1346
+
1347
+ groupNode.height *= multiplier;
1348
+ groupNode.depth *= multiplier;
1349
+ }
1350
+
1351
+ // If the size changed between the parent and the current group, account
1352
+ // for that size difference.
1353
+ if (options.size !== options.parentSize) {
1354
+ multiplier = buildCommon.sizingMultiplier[options.size] /
1355
+ buildCommon.sizingMultiplier[options.parentSize];
1356
+
1357
+ groupNode.height *= multiplier;
1358
+ groupNode.depth *= multiplier;
1359
+ }
1360
+
1361
+ return groupNode;
1362
+ } else {
1363
+ throw new ParseError(
1364
+ "Got group of unknown type: '" + group.type + "'");
1365
+ }
1366
+ };
1367
+
1368
+ /**
1369
+ * Take an entire parse tree, and build it into an appropriate set of HTML
1370
+ * nodes.
1371
+ */
1372
+ var buildHTML = function(tree, options) {
1373
+ // buildExpression is destructive, so we need to make a clone
1374
+ // of the incoming tree so that it isn't accidentally changed
1375
+ tree = JSON.parse(JSON.stringify(tree));
1376
+
1377
+ // Build the expression contained in the tree
1378
+ var expression = buildExpression(tree, options);
1379
+ var body = makeSpan(["base", options.style.cls()], expression);
1380
+
1381
+ // Add struts, which ensure that the top of the HTML element falls at the
1382
+ // height of the expression, and the bottom of the HTML element falls at the
1383
+ // depth of the expression.
1384
+ var topStrut = makeSpan(["strut"]);
1385
+ var bottomStrut = makeSpan(["strut", "bottom"]);
1386
+
1387
+ topStrut.style.height = body.height + "em";
1388
+ bottomStrut.style.height = (body.height + body.depth) + "em";
1389
+ // We'd like to use `vertical-align: top` but in IE 9 this lowers the
1390
+ // baseline of the box to the bottom of this strut (instead staying in the
1391
+ // normal place) so we use an absolute value for vertical-align instead
1392
+ bottomStrut.style.verticalAlign = -body.depth + "em";
1393
+
1394
+ // Wrap the struts and body together
1395
+ var htmlNode = makeSpan(["katex-html"], [topStrut, bottomStrut, body]);
1396
+
1397
+ htmlNode.setAttribute("aria-hidden", "true");
1398
+
1399
+ return htmlNode;
1400
+ };
1401
+
1402
+ module.exports = buildHTML;
katex/src/buildMathML.js ADDED
@@ -0,0 +1,533 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file converts a parse tree into a cooresponding MathML tree. The main
3
+ * entry point is the `buildMathML` function, which takes a parse tree from the
4
+ * parser.
5
+ */
6
+
7
+ var buildCommon = require("./buildCommon");
8
+ var fontMetrics = require("./fontMetrics");
9
+ var mathMLTree = require("./mathMLTree");
10
+ var ParseError = require("./ParseError");
11
+ var symbols = require("./symbols");
12
+ var utils = require("./utils");
13
+
14
+ var makeSpan = buildCommon.makeSpan;
15
+ var fontMap = buildCommon.fontMap;
16
+
17
+ /**
18
+ * Takes a symbol and converts it into a MathML text node after performing
19
+ * optional replacement from symbols.js.
20
+ */
21
+ var makeText = function(text, mode) {
22
+ if (symbols[mode][text] && symbols[mode][text].replace) {
23
+ text = symbols[mode][text].replace;
24
+ }
25
+
26
+ return new mathMLTree.TextNode(text);
27
+ };
28
+
29
+ /**
30
+ * Returns the math variant as a string or null if none is required.
31
+ */
32
+ var getVariant = function(group, options) {
33
+ var font = options.font;
34
+ if (!font) {
35
+ return null;
36
+ }
37
+
38
+ var mode = group.mode;
39
+ if (font === "mathit") {
40
+ return "italic";
41
+ }
42
+
43
+ var value = group.value;
44
+ if (utils.contains(["\\imath", "\\jmath"], value)) {
45
+ return null;
46
+ }
47
+
48
+ if (symbols[mode][value] && symbols[mode][value].replace) {
49
+ value = symbols[mode][value].replace;
50
+ }
51
+
52
+ var fontName = fontMap[font].fontName;
53
+ if (fontMetrics.getCharacterMetrics(value, fontName)) {
54
+ return fontMap[options.font].variant;
55
+ }
56
+
57
+ return null;
58
+ };
59
+
60
+ /**
61
+ * Functions for handling the different types of groups found in the parse
62
+ * tree. Each function should take a parse group and return a MathML node.
63
+ */
64
+ var groupTypes = {};
65
+
66
+ groupTypes.mathord = function(group, options) {
67
+ var node = new mathMLTree.MathNode(
68
+ "mi",
69
+ [makeText(group.value, group.mode)]);
70
+
71
+ var variant = getVariant(group, options);
72
+ if (variant) {
73
+ node.setAttribute("mathvariant", variant);
74
+ }
75
+ return node;
76
+ };
77
+
78
+ groupTypes.textord = function(group, options) {
79
+ var text = makeText(group.value, group.mode);
80
+
81
+ var variant = getVariant(group, options) || "normal";
82
+
83
+ var node;
84
+ if (/[0-9]/.test(group.value)) {
85
+ // TODO(kevinb) merge adjacent <mn> nodes
86
+ // do it as a post processing step
87
+ node = new mathMLTree.MathNode("mn", [text]);
88
+ if (options.font) {
89
+ node.setAttribute("mathvariant", variant);
90
+ }
91
+ } else {
92
+ node = new mathMLTree.MathNode("mi", [text]);
93
+ node.setAttribute("mathvariant", variant);
94
+ }
95
+
96
+ return node;
97
+ };
98
+
99
+ groupTypes.bin = function(group) {
100
+ var node = new mathMLTree.MathNode(
101
+ "mo", [makeText(group.value, group.mode)]);
102
+
103
+ return node;
104
+ };
105
+
106
+ groupTypes.rel = function(group) {
107
+ var node = new mathMLTree.MathNode(
108
+ "mo", [makeText(group.value, group.mode)]);
109
+
110
+ return node;
111
+ };
112
+
113
+ groupTypes.open = function(group) {
114
+ var node = new mathMLTree.MathNode(
115
+ "mo", [makeText(group.value, group.mode)]);
116
+
117
+ return node;
118
+ };
119
+
120
+ groupTypes.close = function(group) {
121
+ var node = new mathMLTree.MathNode(
122
+ "mo", [makeText(group.value, group.mode)]);
123
+
124
+ return node;
125
+ };
126
+
127
+ groupTypes.inner = function(group) {
128
+ var node = new mathMLTree.MathNode(
129
+ "mo", [makeText(group.value, group.mode)]);
130
+
131
+ return node;
132
+ };
133
+
134
+ groupTypes.punct = function(group) {
135
+ var node = new mathMLTree.MathNode(
136
+ "mo", [makeText(group.value, group.mode)]);
137
+
138
+ node.setAttribute("separator", "true");
139
+
140
+ return node;
141
+ };
142
+
143
+ groupTypes.ordgroup = function(group, options) {
144
+ var inner = buildExpression(group.value, options);
145
+
146
+ var node = new mathMLTree.MathNode("mrow", inner);
147
+
148
+ return node;
149
+ };
150
+
151
+ groupTypes.text = function(group, options) {
152
+ var inner = buildExpression(group.value.body, options);
153
+
154
+ var node = new mathMLTree.MathNode("mtext", inner);
155
+
156
+ return node;
157
+ };
158
+
159
+ groupTypes.color = function(group, options) {
160
+ var inner = buildExpression(group.value.value, options);
161
+
162
+ var node = new mathMLTree.MathNode("mstyle", inner);
163
+
164
+ node.setAttribute("mathcolor", group.value.color);
165
+
166
+ return node;
167
+ };
168
+
169
+ groupTypes.supsub = function(group, options) {
170
+ var children = [buildGroup(group.value.base, options)];
171
+
172
+ if (group.value.sub) {
173
+ children.push(buildGroup(group.value.sub, options));
174
+ }
175
+
176
+ if (group.value.sup) {
177
+ children.push(buildGroup(group.value.sup, options));
178
+ }
179
+
180
+ var nodeType;
181
+ if (!group.value.sub) {
182
+ nodeType = "msup";
183
+ } else if (!group.value.sup) {
184
+ nodeType = "msub";
185
+ } else {
186
+ nodeType = "msubsup";
187
+ }
188
+
189
+ var node = new mathMLTree.MathNode(nodeType, children);
190
+
191
+ return node;
192
+ };
193
+
194
+ groupTypes.genfrac = function(group, options) {
195
+ var node = new mathMLTree.MathNode(
196
+ "mfrac",
197
+ [buildGroup(group.value.numer, options),
198
+ buildGroup(group.value.denom, options)]);
199
+
200
+ if (!group.value.hasBarLine) {
201
+ node.setAttribute("linethickness", "0px");
202
+ }
203
+
204
+ if (group.value.leftDelim != null || group.value.rightDelim != null) {
205
+ var withDelims = [];
206
+
207
+ if (group.value.leftDelim != null) {
208
+ var leftOp = new mathMLTree.MathNode(
209
+ "mo", [new mathMLTree.TextNode(group.value.leftDelim)]);
210
+
211
+ leftOp.setAttribute("fence", "true");
212
+
213
+ withDelims.push(leftOp);
214
+ }
215
+
216
+ withDelims.push(node);
217
+
218
+ if (group.value.rightDelim != null) {
219
+ var rightOp = new mathMLTree.MathNode(
220
+ "mo", [new mathMLTree.TextNode(group.value.rightDelim)]);
221
+
222
+ rightOp.setAttribute("fence", "true");
223
+
224
+ withDelims.push(rightOp);
225
+ }
226
+
227
+ var outerNode = new mathMLTree.MathNode("mrow", withDelims);
228
+
229
+ return outerNode;
230
+ }
231
+
232
+ return node;
233
+ };
234
+
235
+ groupTypes.array = function(group, options) {
236
+ return new mathMLTree.MathNode(
237
+ "mtable", group.value.body.map(function(row) {
238
+ return new mathMLTree.MathNode(
239
+ "mtr", row.map(function(cell) {
240
+ return new mathMLTree.MathNode(
241
+ "mtd", [buildGroup(cell, options)]);
242
+ }));
243
+ }));
244
+ };
245
+
246
+ groupTypes.sqrt = function(group, options) {
247
+ var node;
248
+ if (group.value.index) {
249
+ node = new mathMLTree.MathNode(
250
+ "mroot", [
251
+ buildGroup(group.value.body, options),
252
+ buildGroup(group.value.index, options),
253
+ ]);
254
+ } else {
255
+ node = new mathMLTree.MathNode(
256
+ "msqrt", [buildGroup(group.value.body, options)]);
257
+ }
258
+
259
+ return node;
260
+ };
261
+
262
+ groupTypes.leftright = function(group, options) {
263
+ var inner = buildExpression(group.value.body, options);
264
+
265
+ if (group.value.left !== ".") {
266
+ var leftNode = new mathMLTree.MathNode(
267
+ "mo", [makeText(group.value.left, group.mode)]);
268
+
269
+ leftNode.setAttribute("fence", "true");
270
+
271
+ inner.unshift(leftNode);
272
+ }
273
+
274
+ if (group.value.right !== ".") {
275
+ var rightNode = new mathMLTree.MathNode(
276
+ "mo", [makeText(group.value.right, group.mode)]);
277
+
278
+ rightNode.setAttribute("fence", "true");
279
+
280
+ inner.push(rightNode);
281
+ }
282
+
283
+ var outerNode = new mathMLTree.MathNode("mrow", inner);
284
+
285
+ return outerNode;
286
+ };
287
+
288
+ groupTypes.accent = function(group, options) {
289
+ var accentNode = new mathMLTree.MathNode(
290
+ "mo", [makeText(group.value.accent, group.mode)]);
291
+
292
+ var node = new mathMLTree.MathNode(
293
+ "mover",
294
+ [buildGroup(group.value.base, options),
295
+ accentNode]);
296
+
297
+ node.setAttribute("accent", "true");
298
+
299
+ return node;
300
+ };
301
+
302
+ groupTypes.spacing = function(group) {
303
+ var node;
304
+
305
+ if (group.value === "\\ " || group.value === "\\space" ||
306
+ group.value === " " || group.value === "~") {
307
+ node = new mathMLTree.MathNode(
308
+ "mtext", [new mathMLTree.TextNode("\u00a0")]);
309
+ } else {
310
+ node = new mathMLTree.MathNode("mspace");
311
+
312
+ node.setAttribute(
313
+ "width", buildCommon.spacingFunctions[group.value].size);
314
+ }
315
+
316
+ return node;
317
+ };
318
+
319
+ groupTypes.op = function(group) {
320
+ var node;
321
+
322
+ // TODO(emily): handle big operators using the `largeop` attribute
323
+
324
+ if (group.value.symbol) {
325
+ // This is a symbol. Just add the symbol.
326
+ node = new mathMLTree.MathNode(
327
+ "mo", [makeText(group.value.body, group.mode)]);
328
+ } else {
329
+ // This is a text operator. Add all of the characters from the
330
+ // operator's name.
331
+ // TODO(emily): Add a space in the middle of some of these
332
+ // operators, like \limsup.
333
+ node = new mathMLTree.MathNode(
334
+ "mi", [new mathMLTree.TextNode(group.value.body.slice(1))]);
335
+ }
336
+
337
+ return node;
338
+ };
339
+
340
+ groupTypes.katex = function(group) {
341
+ var node = new mathMLTree.MathNode(
342
+ "mtext", [new mathMLTree.TextNode("KaTeX")]);
343
+
344
+ return node;
345
+ };
346
+
347
+ groupTypes.font = function(group, options) {
348
+ var font = group.value.font;
349
+ return buildGroup(group.value.body, options.withFont(font));
350
+ };
351
+
352
+ groupTypes.delimsizing = function(group) {
353
+ var children = [];
354
+
355
+ if (group.value.value !== ".") {
356
+ children.push(makeText(group.value.value, group.mode));
357
+ }
358
+
359
+ var node = new mathMLTree.MathNode("mo", children);
360
+
361
+ if (group.value.delimType === "open" ||
362
+ group.value.delimType === "close") {
363
+ // Only some of the delimsizing functions act as fences, and they
364
+ // return "open" or "close" delimTypes.
365
+ node.setAttribute("fence", "true");
366
+ } else {
367
+ // Explicitly disable fencing if it's not a fence, to override the
368
+ // defaults.
369
+ node.setAttribute("fence", "false");
370
+ }
371
+
372
+ return node;
373
+ };
374
+
375
+ groupTypes.styling = function(group, options) {
376
+ var inner = buildExpression(group.value.value, options);
377
+
378
+ var node = new mathMLTree.MathNode("mstyle", inner);
379
+
380
+ var styleAttributes = {
381
+ "display": ["0", "true"],
382
+ "text": ["0", "false"],
383
+ "script": ["1", "false"],
384
+ "scriptscript": ["2", "false"],
385
+ };
386
+
387
+ var attr = styleAttributes[group.value.style];
388
+
389
+ node.setAttribute("scriptlevel", attr[0]);
390
+ node.setAttribute("displaystyle", attr[1]);
391
+
392
+ return node;
393
+ };
394
+
395
+ groupTypes.sizing = function(group, options) {
396
+ var inner = buildExpression(group.value.value, options);
397
+
398
+ var node = new mathMLTree.MathNode("mstyle", inner);
399
+
400
+ // TODO(emily): This doesn't produce the correct size for nested size
401
+ // changes, because we don't keep state of what style we're currently
402
+ // in, so we can't reset the size to normal before changing it. Now
403
+ // that we're passing an options parameter we should be able to fix
404
+ // this.
405
+ node.setAttribute(
406
+ "mathsize", buildCommon.sizingMultiplier[group.value.size] + "em");
407
+
408
+ return node;
409
+ };
410
+
411
+ groupTypes.overline = function(group, options) {
412
+ var operator = new mathMLTree.MathNode(
413
+ "mo", [new mathMLTree.TextNode("\u203e")]);
414
+ operator.setAttribute("stretchy", "true");
415
+
416
+ var node = new mathMLTree.MathNode(
417
+ "mover",
418
+ [buildGroup(group.value.body, options),
419
+ operator]);
420
+ node.setAttribute("accent", "true");
421
+
422
+ return node;
423
+ };
424
+
425
+ groupTypes.underline = function(group, options) {
426
+ var operator = new mathMLTree.MathNode(
427
+ "mo", [new mathMLTree.TextNode("\u203e")]);
428
+ operator.setAttribute("stretchy", "true");
429
+
430
+ var node = new mathMLTree.MathNode(
431
+ "munder",
432
+ [buildGroup(group.value.body, options),
433
+ operator]);
434
+ node.setAttribute("accentunder", "true");
435
+
436
+ return node;
437
+ };
438
+
439
+ groupTypes.rule = function(group) {
440
+ // TODO(emily): Figure out if there's an actual way to draw black boxes
441
+ // in MathML.
442
+ var node = new mathMLTree.MathNode("mrow");
443
+
444
+ return node;
445
+ };
446
+
447
+ groupTypes.llap = function(group, options) {
448
+ var node = new mathMLTree.MathNode(
449
+ "mpadded", [buildGroup(group.value.body, options)]);
450
+
451
+ node.setAttribute("lspace", "-1width");
452
+ node.setAttribute("width", "0px");
453
+
454
+ return node;
455
+ };
456
+
457
+ groupTypes.rlap = function(group, options) {
458
+ var node = new mathMLTree.MathNode(
459
+ "mpadded", [buildGroup(group.value.body, options)]);
460
+
461
+ node.setAttribute("width", "0px");
462
+
463
+ return node;
464
+ };
465
+
466
+ groupTypes.phantom = function(group, options, prev) {
467
+ var inner = buildExpression(group.value.value, options);
468
+ return new mathMLTree.MathNode("mphantom", inner);
469
+ };
470
+
471
+ /**
472
+ * Takes a list of nodes, builds them, and returns a list of the generated
473
+ * MathML nodes. A little simpler than the HTML version because we don't do any
474
+ * previous-node handling.
475
+ */
476
+ var buildExpression = function(expression, options) {
477
+ var groups = [];
478
+ for (var i = 0; i < expression.length; i++) {
479
+ var group = expression[i];
480
+ groups.push(buildGroup(group, options));
481
+ }
482
+ return groups;
483
+ };
484
+
485
+ /**
486
+ * Takes a group from the parser and calls the appropriate groupTypes function
487
+ * on it to produce a MathML node.
488
+ */
489
+ var buildGroup = function(group, options) {
490
+ if (!group) {
491
+ return new mathMLTree.MathNode("mrow");
492
+ }
493
+
494
+ if (groupTypes[group.type]) {
495
+ // Call the groupTypes function
496
+ return groupTypes[group.type](group, options);
497
+ } else {
498
+ throw new ParseError(
499
+ "Got group of unknown type: '" + group.type + "'");
500
+ }
501
+ };
502
+
503
+ /**
504
+ * Takes a full parse tree and settings and builds a MathML representation of
505
+ * it. In particular, we put the elements from building the parse tree into a
506
+ * <semantics> tag so we can also include that TeX source as an annotation.
507
+ *
508
+ * Note that we actually return a domTree element with a `<math>` inside it so
509
+ * we can do appropriate styling.
510
+ */
511
+ var buildMathML = function(tree, texExpression, options) {
512
+ var expression = buildExpression(tree, options);
513
+
514
+ // Wrap up the expression in an mrow so it is presented in the semantics
515
+ // tag correctly.
516
+ var wrapper = new mathMLTree.MathNode("mrow", expression);
517
+
518
+ // Build a TeX annotation of the source
519
+ var annotation = new mathMLTree.MathNode(
520
+ "annotation", [new mathMLTree.TextNode(texExpression)]);
521
+
522
+ annotation.setAttribute("encoding", "application/x-tex");
523
+
524
+ var semantics = new mathMLTree.MathNode(
525
+ "semantics", [wrapper, annotation]);
526
+
527
+ var math = new mathMLTree.MathNode("math", [semantics]);
528
+
529
+ // You can't style <math> nodes, so we wrap the node in a span.
530
+ return makeSpan(["katex-mathml"], [math]);
531
+ };
532
+
533
+ module.exports = buildMathML;
katex/src/buildTree.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var buildHTML = require("./buildHTML");
2
+ var buildMathML = require("./buildMathML");
3
+ var buildCommon = require("./buildCommon");
4
+ var Options = require("./Options");
5
+ var Settings = require("./Settings");
6
+ var Style = require("./Style");
7
+
8
+ var makeSpan = buildCommon.makeSpan;
9
+
10
+ var buildTree = function(tree, expression, settings) {
11
+ settings = settings || new Settings({});
12
+
13
+ var startStyle = Style.TEXT;
14
+ if (settings.displayMode) {
15
+ startStyle = Style.DISPLAY;
16
+ }
17
+
18
+ // Setup the default options
19
+ var options = new Options({
20
+ style: startStyle,
21
+ size: "size5",
22
+ });
23
+
24
+ // `buildHTML` sometimes messes with the parse tree (like turning bins ->
25
+ // ords), so we build the MathML version first.
26
+ var mathMLNode = buildMathML(tree, expression, options);
27
+ var htmlNode = buildHTML(tree, options);
28
+
29
+ var katexNode = makeSpan(["katex"], [
30
+ mathMLNode, htmlNode,
31
+ ]);
32
+
33
+ if (settings.displayMode) {
34
+ return makeSpan(["katex-display"], [katexNode]);
35
+ } else {
36
+ return katexNode;
37
+ }
38
+ };
39
+
40
+ module.exports = buildTree;
katex/src/delimiter.js ADDED
@@ -0,0 +1,542 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file deals with creating delimiters of various sizes. The TeXbook
3
+ * discusses these routines on page 441-442, in the "Another subroutine sets box
4
+ * x to a specified variable delimiter" paragraph.
5
+ *
6
+ * There are three main routines here. `makeSmallDelim` makes a delimiter in the
7
+ * normal font, but in either text, script, or scriptscript style.
8
+ * `makeLargeDelim` makes a delimiter in textstyle, but in one of the Size1,
9
+ * Size2, Size3, or Size4 fonts. `makeStackedDelim` makes a delimiter out of
10
+ * smaller pieces that are stacked on top of one another.
11
+ *
12
+ * The functions take a parameter `center`, which determines if the delimiter
13
+ * should be centered around the axis.
14
+ *
15
+ * Then, there are three exposed functions. `sizedDelim` makes a delimiter in
16
+ * one of the given sizes. This is used for things like `\bigl`.
17
+ * `customSizedDelim` makes a delimiter with a given total height+depth. It is
18
+ * called in places like `\sqrt`. `leftRightDelim` makes an appropriate
19
+ * delimiter which surrounds an expression of a given height an depth. It is
20
+ * used in `\left` and `\right`.
21
+ */
22
+
23
+ var ParseError = require("./ParseError");
24
+ var Style = require("./Style");
25
+
26
+ var buildCommon = require("./buildCommon");
27
+ var fontMetrics = require("./fontMetrics");
28
+ var symbols = require("./symbols");
29
+ var utils = require("./utils");
30
+
31
+ var makeSpan = buildCommon.makeSpan;
32
+
33
+ /**
34
+ * Get the metrics for a given symbol and font, after transformation (i.e.
35
+ * after following replacement from symbols.js)
36
+ */
37
+ var getMetrics = function(symbol, font) {
38
+ if (symbols.math[symbol] && symbols.math[symbol].replace) {
39
+ return fontMetrics.getCharacterMetrics(
40
+ symbols.math[symbol].replace, font);
41
+ } else {
42
+ return fontMetrics.getCharacterMetrics(
43
+ symbol, font);
44
+ }
45
+ };
46
+
47
+ /**
48
+ * Builds a symbol in the given font size (note size is an integer)
49
+ */
50
+ var mathrmSize = function(value, size, mode) {
51
+ return buildCommon.makeSymbol(value, "Size" + size + "-Regular", mode);
52
+ };
53
+
54
+ /**
55
+ * Puts a delimiter span in a given style, and adds appropriate height, depth,
56
+ * and maxFontSizes.
57
+ */
58
+ var styleWrap = function(delim, toStyle, options) {
59
+ var span = makeSpan(
60
+ ["style-wrap", options.style.reset(), toStyle.cls()], [delim]);
61
+
62
+ var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
63
+
64
+ span.height *= multiplier;
65
+ span.depth *= multiplier;
66
+ span.maxFontSize = toStyle.sizeMultiplier;
67
+
68
+ return span;
69
+ };
70
+
71
+ /**
72
+ * Makes a small delimiter. This is a delimiter that comes in the Main-Regular
73
+ * font, but is restyled to either be in textstyle, scriptstyle, or
74
+ * scriptscriptstyle.
75
+ */
76
+ var makeSmallDelim = function(delim, style, center, options, mode) {
77
+ var text = buildCommon.makeSymbol(delim, "Main-Regular", mode);
78
+
79
+ var span = styleWrap(text, style, options);
80
+
81
+ if (center) {
82
+ var shift =
83
+ (1 - options.style.sizeMultiplier / style.sizeMultiplier) *
84
+ fontMetrics.metrics.axisHeight;
85
+
86
+ span.style.top = shift + "em";
87
+ span.height -= shift;
88
+ span.depth += shift;
89
+ }
90
+
91
+ return span;
92
+ };
93
+
94
+ /**
95
+ * Makes a large delimiter. This is a delimiter that comes in the Size1, Size2,
96
+ * Size3, or Size4 fonts. It is always rendered in textstyle.
97
+ */
98
+ var makeLargeDelim = function(delim, size, center, options, mode) {
99
+ var inner = mathrmSize(delim, size, mode);
100
+
101
+ var span = styleWrap(
102
+ makeSpan(["delimsizing", "size" + size],
103
+ [inner], options.getColor()),
104
+ Style.TEXT, options);
105
+
106
+ if (center) {
107
+ var shift = (1 - options.style.sizeMultiplier) *
108
+ fontMetrics.metrics.axisHeight;
109
+
110
+ span.style.top = shift + "em";
111
+ span.height -= shift;
112
+ span.depth += shift;
113
+ }
114
+
115
+ return span;
116
+ };
117
+
118
+ /**
119
+ * Make an inner span with the given offset and in the given font. This is used
120
+ * in `makeStackedDelim` to make the stacking pieces for the delimiter.
121
+ */
122
+ var makeInner = function(symbol, font, mode) {
123
+ var sizeClass;
124
+ // Apply the correct CSS class to choose the right font.
125
+ if (font === "Size1-Regular") {
126
+ sizeClass = "delim-size1";
127
+ } else if (font === "Size4-Regular") {
128
+ sizeClass = "delim-size4";
129
+ }
130
+
131
+ var inner = makeSpan(
132
+ ["delimsizinginner", sizeClass],
133
+ [makeSpan([], [buildCommon.makeSymbol(symbol, font, mode)])]);
134
+
135
+ // Since this will be passed into `makeVList` in the end, wrap the element
136
+ // in the appropriate tag that VList uses.
137
+ return {type: "elem", elem: inner};
138
+ };
139
+
140
+ /**
141
+ * Make a stacked delimiter out of a given delimiter, with the total height at
142
+ * least `heightTotal`. This routine is mentioned on page 442 of the TeXbook.
143
+ */
144
+ var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
145
+ // There are four parts, the top, an optional middle, a repeated part, and a
146
+ // bottom.
147
+ var top;
148
+ var middle;
149
+ var repeat;
150
+ var bottom;
151
+ top = repeat = bottom = delim;
152
+ middle = null;
153
+ // Also keep track of what font the delimiters are in
154
+ var font = "Size1-Regular";
155
+
156
+ // We set the parts and font based on the symbol. Note that we use
157
+ // '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the
158
+ // repeats of the arrows
159
+ if (delim === "\\uparrow") {
160
+ repeat = bottom = "\u23d0";
161
+ } else if (delim === "\\Uparrow") {
162
+ repeat = bottom = "\u2016";
163
+ } else if (delim === "\\downarrow") {
164
+ top = repeat = "\u23d0";
165
+ } else if (delim === "\\Downarrow") {
166
+ top = repeat = "\u2016";
167
+ } else if (delim === "\\updownarrow") {
168
+ top = "\\uparrow";
169
+ repeat = "\u23d0";
170
+ bottom = "\\downarrow";
171
+ } else if (delim === "\\Updownarrow") {
172
+ top = "\\Uparrow";
173
+ repeat = "\u2016";
174
+ bottom = "\\Downarrow";
175
+ } else if (delim === "[" || delim === "\\lbrack") {
176
+ top = "\u23a1";
177
+ repeat = "\u23a2";
178
+ bottom = "\u23a3";
179
+ font = "Size4-Regular";
180
+ } else if (delim === "]" || delim === "\\rbrack") {
181
+ top = "\u23a4";
182
+ repeat = "\u23a5";
183
+ bottom = "\u23a6";
184
+ font = "Size4-Regular";
185
+ } else if (delim === "\\lfloor") {
186
+ repeat = top = "\u23a2";
187
+ bottom = "\u23a3";
188
+ font = "Size4-Regular";
189
+ } else if (delim === "\\lceil") {
190
+ top = "\u23a1";
191
+ repeat = bottom = "\u23a2";
192
+ font = "Size4-Regular";
193
+ } else if (delim === "\\rfloor") {
194
+ repeat = top = "\u23a5";
195
+ bottom = "\u23a6";
196
+ font = "Size4-Regular";
197
+ } else if (delim === "\\rceil") {
198
+ top = "\u23a4";
199
+ repeat = bottom = "\u23a5";
200
+ font = "Size4-Regular";
201
+ } else if (delim === "(") {
202
+ top = "\u239b";
203
+ repeat = "\u239c";
204
+ bottom = "\u239d";
205
+ font = "Size4-Regular";
206
+ } else if (delim === ")") {
207
+ top = "\u239e";
208
+ repeat = "\u239f";
209
+ bottom = "\u23a0";
210
+ font = "Size4-Regular";
211
+ } else if (delim === "\\{" || delim === "\\lbrace") {
212
+ top = "\u23a7";
213
+ middle = "\u23a8";
214
+ bottom = "\u23a9";
215
+ repeat = "\u23aa";
216
+ font = "Size4-Regular";
217
+ } else if (delim === "\\}" || delim === "\\rbrace") {
218
+ top = "\u23ab";
219
+ middle = "\u23ac";
220
+ bottom = "\u23ad";
221
+ repeat = "\u23aa";
222
+ font = "Size4-Regular";
223
+ } else if (delim === "\\lgroup") {
224
+ top = "\u23a7";
225
+ bottom = "\u23a9";
226
+ repeat = "\u23aa";
227
+ font = "Size4-Regular";
228
+ } else if (delim === "\\rgroup") {
229
+ top = "\u23ab";
230
+ bottom = "\u23ad";
231
+ repeat = "\u23aa";
232
+ font = "Size4-Regular";
233
+ } else if (delim === "\\lmoustache") {
234
+ top = "\u23a7";
235
+ bottom = "\u23ad";
236
+ repeat = "\u23aa";
237
+ font = "Size4-Regular";
238
+ } else if (delim === "\\rmoustache") {
239
+ top = "\u23ab";
240
+ bottom = "\u23a9";
241
+ repeat = "\u23aa";
242
+ font = "Size4-Regular";
243
+ } else if (delim === "\\surd") {
244
+ top = "\ue001";
245
+ bottom = "\u23b7";
246
+ repeat = "\ue000";
247
+ font = "Size4-Regular";
248
+ }
249
+
250
+ // Get the metrics of the four sections
251
+ var topMetrics = getMetrics(top, font);
252
+ var topHeightTotal = topMetrics.height + topMetrics.depth;
253
+ var repeatMetrics = getMetrics(repeat, font);
254
+ var repeatHeightTotal = repeatMetrics.height + repeatMetrics.depth;
255
+ var bottomMetrics = getMetrics(bottom, font);
256
+ var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth;
257
+ var middleHeightTotal = 0;
258
+ var middleFactor = 1;
259
+ if (middle !== null) {
260
+ var middleMetrics = getMetrics(middle, font);
261
+ middleHeightTotal = middleMetrics.height + middleMetrics.depth;
262
+ middleFactor = 2; // repeat symmetrically above and below middle
263
+ }
264
+
265
+ // Calcuate the minimal height that the delimiter can have.
266
+ // It is at least the size of the top, bottom, and optional middle combined.
267
+ var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal;
268
+
269
+ // Compute the number of copies of the repeat symbol we will need
270
+ var repeatCount = Math.ceil(
271
+ (heightTotal - minHeight) / (middleFactor * repeatHeightTotal));
272
+
273
+ // Compute the total height of the delimiter including all the symbols
274
+ var realHeightTotal =
275
+ minHeight + repeatCount * middleFactor * repeatHeightTotal;
276
+
277
+ // The center of the delimiter is placed at the center of the axis. Note
278
+ // that in this context, "center" means that the delimiter should be
279
+ // centered around the axis in the current style, while normally it is
280
+ // centered around the axis in textstyle.
281
+ var axisHeight = fontMetrics.metrics.axisHeight;
282
+ if (center) {
283
+ axisHeight *= options.style.sizeMultiplier;
284
+ }
285
+ // Calculate the depth
286
+ var depth = realHeightTotal / 2 - axisHeight;
287
+
288
+ // Now, we start building the pieces that will go into the vlist
289
+
290
+ // Keep a list of the inner pieces
291
+ var inners = [];
292
+
293
+ // Add the bottom symbol
294
+ inners.push(makeInner(bottom, font, mode));
295
+
296
+ var i;
297
+ if (middle === null) {
298
+ // Add that many symbols
299
+ for (i = 0; i < repeatCount; i++) {
300
+ inners.push(makeInner(repeat, font, mode));
301
+ }
302
+ } else {
303
+ // When there is a middle bit, we need the middle part and two repeated
304
+ // sections
305
+ for (i = 0; i < repeatCount; i++) {
306
+ inners.push(makeInner(repeat, font, mode));
307
+ }
308
+ inners.push(makeInner(middle, font, mode));
309
+ for (i = 0; i < repeatCount; i++) {
310
+ inners.push(makeInner(repeat, font, mode));
311
+ }
312
+ }
313
+
314
+ // Add the top symbol
315
+ inners.push(makeInner(top, font, mode));
316
+
317
+ // Finally, build the vlist
318
+ var inner = buildCommon.makeVList(inners, "bottom", depth, options);
319
+
320
+ return styleWrap(
321
+ makeSpan(["delimsizing", "mult"], [inner], options.getColor()),
322
+ Style.TEXT, options);
323
+ };
324
+
325
+ // There are three kinds of delimiters, delimiters that stack when they become
326
+ // too large
327
+ var stackLargeDelimiters = [
328
+ "(", ")", "[", "\\lbrack", "]", "\\rbrack",
329
+ "\\{", "\\lbrace", "\\}", "\\rbrace",
330
+ "\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
331
+ "\\surd",
332
+ ];
333
+
334
+ // delimiters that always stack
335
+ var stackAlwaysDelimiters = [
336
+ "\\uparrow", "\\downarrow", "\\updownarrow",
337
+ "\\Uparrow", "\\Downarrow", "\\Updownarrow",
338
+ "|", "\\|", "\\vert", "\\Vert",
339
+ "\\lvert", "\\rvert", "\\lVert", "\\rVert",
340
+ "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache",
341
+ ];
342
+
343
+ // and delimiters that never stack
344
+ var stackNeverDelimiters = [
345
+ "<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt",
346
+ ];
347
+
348
+ // Metrics of the different sizes. Found by looking at TeX's output of
349
+ // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
350
+ // Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
351
+ var sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
352
+
353
+ /**
354
+ * Used to create a delimiter of a specific size, where `size` is 1, 2, 3, or 4.
355
+ */
356
+ var makeSizedDelim = function(delim, size, options, mode) {
357
+ // < and > turn into \langle and \rangle in delimiters
358
+ if (delim === "<" || delim === "\\lt") {
359
+ delim = "\\langle";
360
+ } else if (delim === ">" || delim === "\\gt") {
361
+ delim = "\\rangle";
362
+ }
363
+
364
+ // Sized delimiters are never centered.
365
+ if (utils.contains(stackLargeDelimiters, delim) ||
366
+ utils.contains(stackNeverDelimiters, delim)) {
367
+ return makeLargeDelim(delim, size, false, options, mode);
368
+ } else if (utils.contains(stackAlwaysDelimiters, delim)) {
369
+ return makeStackedDelim(
370
+ delim, sizeToMaxHeight[size], false, options, mode);
371
+ } else {
372
+ throw new ParseError("Illegal delimiter: '" + delim + "'");
373
+ }
374
+ };
375
+
376
+ /**
377
+ * There are three different sequences of delimiter sizes that the delimiters
378
+ * follow depending on the kind of delimiter. This is used when creating custom
379
+ * sized delimiters to decide whether to create a small, large, or stacked
380
+ * delimiter.
381
+ *
382
+ * In real TeX, these sequences aren't explicitly defined, but are instead
383
+ * defined inside the font metrics. Since there are only three sequences that
384
+ * are possible for the delimiters that TeX defines, it is easier to just encode
385
+ * them explicitly here.
386
+ */
387
+
388
+ // Delimiters that never stack try small delimiters and large delimiters only
389
+ var stackNeverDelimiterSequence = [
390
+ {type: "small", style: Style.SCRIPTSCRIPT},
391
+ {type: "small", style: Style.SCRIPT},
392
+ {type: "small", style: Style.TEXT},
393
+ {type: "large", size: 1},
394
+ {type: "large", size: 2},
395
+ {type: "large", size: 3},
396
+ {type: "large", size: 4},
397
+ ];
398
+
399
+ // Delimiters that always stack try the small delimiters first, then stack
400
+ var stackAlwaysDelimiterSequence = [
401
+ {type: "small", style: Style.SCRIPTSCRIPT},
402
+ {type: "small", style: Style.SCRIPT},
403
+ {type: "small", style: Style.TEXT},
404
+ {type: "stack"},
405
+ ];
406
+
407
+ // Delimiters that stack when large try the small and then large delimiters, and
408
+ // stack afterwards
409
+ var stackLargeDelimiterSequence = [
410
+ {type: "small", style: Style.SCRIPTSCRIPT},
411
+ {type: "small", style: Style.SCRIPT},
412
+ {type: "small", style: Style.TEXT},
413
+ {type: "large", size: 1},
414
+ {type: "large", size: 2},
415
+ {type: "large", size: 3},
416
+ {type: "large", size: 4},
417
+ {type: "stack"},
418
+ ];
419
+
420
+ /**
421
+ * Get the font used in a delimiter based on what kind of delimiter it is.
422
+ */
423
+ var delimTypeToFont = function(type) {
424
+ if (type.type === "small") {
425
+ return "Main-Regular";
426
+ } else if (type.type === "large") {
427
+ return "Size" + type.size + "-Regular";
428
+ } else if (type.type === "stack") {
429
+ return "Size4-Regular";
430
+ }
431
+ };
432
+
433
+ /**
434
+ * Traverse a sequence of types of delimiters to decide what kind of delimiter
435
+ * should be used to create a delimiter of the given height+depth.
436
+ */
437
+ var traverseSequence = function(delim, height, sequence, options) {
438
+ // Here, we choose the index we should start at in the sequences. In smaller
439
+ // sizes (which correspond to larger numbers in style.size) we start earlier
440
+ // in the sequence. Thus, scriptscript starts at index 3-3=0, script starts
441
+ // at index 3-2=1, text starts at 3-1=2, and display starts at min(2,3-0)=2
442
+ var start = Math.min(2, 3 - options.style.size);
443
+ for (var i = start; i < sequence.length; i++) {
444
+ if (sequence[i].type === "stack") {
445
+ // This is always the last delimiter, so we just break the loop now.
446
+ break;
447
+ }
448
+
449
+ var metrics = getMetrics(delim, delimTypeToFont(sequence[i]));
450
+ var heightDepth = metrics.height + metrics.depth;
451
+
452
+ // Small delimiters are scaled down versions of the same font, so we
453
+ // account for the style change size.
454
+
455
+ if (sequence[i].type === "small") {
456
+ heightDepth *= sequence[i].style.sizeMultiplier;
457
+ }
458
+
459
+ // Check if the delimiter at this size works for the given height.
460
+ if (heightDepth > height) {
461
+ return sequence[i];
462
+ }
463
+ }
464
+
465
+ // If we reached the end of the sequence, return the last sequence element.
466
+ return sequence[sequence.length - 1];
467
+ };
468
+
469
+ /**
470
+ * Make a delimiter of a given height+depth, with optional centering. Here, we
471
+ * traverse the sequences, and create a delimiter that the sequence tells us to.
472
+ */
473
+ var makeCustomSizedDelim = function(delim, height, center, options, mode) {
474
+ if (delim === "<" || delim === "\\lt") {
475
+ delim = "\\langle";
476
+ } else if (delim === ">" || delim === "\\gt") {
477
+ delim = "\\rangle";
478
+ }
479
+
480
+ // Decide what sequence to use
481
+ var sequence;
482
+ if (utils.contains(stackNeverDelimiters, delim)) {
483
+ sequence = stackNeverDelimiterSequence;
484
+ } else if (utils.contains(stackLargeDelimiters, delim)) {
485
+ sequence = stackLargeDelimiterSequence;
486
+ } else {
487
+ sequence = stackAlwaysDelimiterSequence;
488
+ }
489
+
490
+ // Look through the sequence
491
+ var delimType = traverseSequence(delim, height, sequence, options);
492
+
493
+ // Depending on the sequence element we decided on, call the appropriate
494
+ // function.
495
+ if (delimType.type === "small") {
496
+ return makeSmallDelim(delim, delimType.style, center, options, mode);
497
+ } else if (delimType.type === "large") {
498
+ return makeLargeDelim(delim, delimType.size, center, options, mode);
499
+ } else if (delimType.type === "stack") {
500
+ return makeStackedDelim(delim, height, center, options, mode);
501
+ }
502
+ };
503
+
504
+ /**
505
+ * Make a delimiter for use with `\left` and `\right`, given a height and depth
506
+ * of an expression that the delimiters surround.
507
+ */
508
+ var makeLeftRightDelim = function(delim, height, depth, options, mode) {
509
+ // We always center \left/\right delimiters, so the axis is always shifted
510
+ var axisHeight =
511
+ fontMetrics.metrics.axisHeight * options.style.sizeMultiplier;
512
+
513
+ // Taken from TeX source, tex.web, function make_left_right
514
+ var delimiterFactor = 901;
515
+ var delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm;
516
+
517
+ var maxDistFromAxis = Math.max(
518
+ height - axisHeight, depth + axisHeight);
519
+
520
+ var totalHeight = Math.max(
521
+ // In real TeX, calculations are done using integral values which are
522
+ // 65536 per pt, or 655360 per em. So, the division here truncates in
523
+ // TeX but doesn't here, producing different results. If we wanted to
524
+ // exactly match TeX's calculation, we could do
525
+ // Math.floor(655360 * maxDistFromAxis / 500) *
526
+ // delimiterFactor / 655360
527
+ // (To see the difference, compare
528
+ // x^{x^{\left(\rule{0.1em}{0.68em}\right)}}
529
+ // in TeX and KaTeX)
530
+ maxDistFromAxis / 500 * delimiterFactor,
531
+ 2 * maxDistFromAxis - delimiterExtend);
532
+
533
+ // Finally, we defer to `makeCustomSizedDelim` with our calculated total
534
+ // height
535
+ return makeCustomSizedDelim(delim, totalHeight, true, options, mode);
536
+ };
537
+
538
+ module.exports = {
539
+ sizedDelim: makeSizedDelim,
540
+ customSizedDelim: makeCustomSizedDelim,
541
+ leftRightDelim: makeLeftRightDelim,
542
+ };
katex/src/domTree.js ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * These objects store the data about the DOM nodes we create, as well as some
3
+ * extra data. They can then be transformed into real DOM nodes with the
4
+ * `toNode` function or HTML markup using `toMarkup`. They are useful for both
5
+ * storing extra properties on the nodes, as well as providing a way to easily
6
+ * work with the DOM.
7
+ *
8
+ * Similar functions for working with MathML nodes exist in mathMLTree.js.
9
+ */
10
+
11
+ var utils = require("./utils");
12
+
13
+ /**
14
+ * Create an HTML className based on a list of classes. In addition to joining
15
+ * with spaces, we also remove null or empty classes.
16
+ */
17
+ var createClass = function(classes) {
18
+ classes = classes.slice();
19
+ for (var i = classes.length - 1; i >= 0; i--) {
20
+ if (!classes[i]) {
21
+ classes.splice(i, 1);
22
+ }
23
+ }
24
+
25
+ return classes.join(" ");
26
+ };
27
+
28
+ /**
29
+ * This node represents a span node, with a className, a list of children, and
30
+ * an inline style. It also contains information about its height, depth, and
31
+ * maxFontSize.
32
+ */
33
+ function span(classes, children, height, depth, maxFontSize, style) {
34
+ this.classes = classes || [];
35
+ this.children = children || [];
36
+ this.height = height || 0;
37
+ this.depth = depth || 0;
38
+ this.maxFontSize = maxFontSize || 0;
39
+ this.style = style || {};
40
+ this.attributes = {};
41
+ }
42
+
43
+ /**
44
+ * Sets an arbitrary attribute on the span. Warning: use this wisely. Not all
45
+ * browsers support attributes the same, and having too many custom attributes
46
+ * is probably bad.
47
+ */
48
+ span.prototype.setAttribute = function(attribute, value) {
49
+ this.attributes[attribute] = value;
50
+ };
51
+
52
+ /**
53
+ * Convert the span into an HTML node
54
+ */
55
+ span.prototype.toNode = function() {
56
+ var span = document.createElement("span");
57
+
58
+ // Apply the class
59
+ span.className = createClass(this.classes);
60
+
61
+ // Apply inline styles
62
+ for (var style in this.style) {
63
+ if (Object.prototype.hasOwnProperty.call(this.style, style)) {
64
+ span.style[style] = this.style[style];
65
+ }
66
+ }
67
+
68
+ // Apply attributes
69
+ for (var attr in this.attributes) {
70
+ if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
71
+ span.setAttribute(attr, this.attributes[attr]);
72
+ }
73
+ }
74
+
75
+ // Append the children, also as HTML nodes
76
+ for (var i = 0; i < this.children.length; i++) {
77
+ span.appendChild(this.children[i].toNode());
78
+ }
79
+
80
+ return span;
81
+ };
82
+
83
+ /**
84
+ * Convert the span into an HTML markup string
85
+ */
86
+ span.prototype.toMarkup = function() {
87
+ var markup = "<span";
88
+
89
+ // Add the class
90
+ if (this.classes.length) {
91
+ markup += " class=\"";
92
+ markup += utils.escape(createClass(this.classes));
93
+ markup += "\"";
94
+ }
95
+
96
+ var styles = "";
97
+
98
+ // Add the styles, after hyphenation
99
+ for (var style in this.style) {
100
+ if (this.style.hasOwnProperty(style)) {
101
+ styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
102
+ }
103
+ }
104
+
105
+ if (styles) {
106
+ markup += " style=\"" + utils.escape(styles) + "\"";
107
+ }
108
+
109
+ // Add the attributes
110
+ for (var attr in this.attributes) {
111
+ if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
112
+ markup += " " + attr + "=\"";
113
+ markup += utils.escape(this.attributes[attr]);
114
+ markup += "\"";
115
+ }
116
+ }
117
+
118
+ markup += ">";
119
+
120
+ // Add the markup of the children, also as markup
121
+ for (var i = 0; i < this.children.length; i++) {
122
+ markup += this.children[i].toMarkup();
123
+ }
124
+
125
+ markup += "</span>";
126
+
127
+ return markup;
128
+ };
129
+
130
+ /**
131
+ * This node represents a document fragment, which contains elements, but when
132
+ * placed into the DOM doesn't have any representation itself. Thus, it only
133
+ * contains children and doesn't have any HTML properties. It also keeps track
134
+ * of a height, depth, and maxFontSize.
135
+ */
136
+ function documentFragment(children, height, depth, maxFontSize) {
137
+ this.children = children || [];
138
+ this.height = height || 0;
139
+ this.depth = depth || 0;
140
+ this.maxFontSize = maxFontSize || 0;
141
+ }
142
+
143
+ /**
144
+ * Convert the fragment into a node
145
+ */
146
+ documentFragment.prototype.toNode = function() {
147
+ // Create a fragment
148
+ var frag = document.createDocumentFragment();
149
+
150
+ // Append the children
151
+ for (var i = 0; i < this.children.length; i++) {
152
+ frag.appendChild(this.children[i].toNode());
153
+ }
154
+
155
+ return frag;
156
+ };
157
+
158
+ /**
159
+ * Convert the fragment into HTML markup
160
+ */
161
+ documentFragment.prototype.toMarkup = function() {
162
+ var markup = "";
163
+
164
+ // Simply concatenate the markup for the children together
165
+ for (var i = 0; i < this.children.length; i++) {
166
+ markup += this.children[i].toMarkup();
167
+ }
168
+
169
+ return markup;
170
+ };
171
+
172
+ /**
173
+ * A symbol node contains information about a single symbol. It either renders
174
+ * to a single text node, or a span with a single text node in it, depending on
175
+ * whether it has CSS classes, styles, or needs italic correction.
176
+ */
177
+ function symbolNode(value, height, depth, italic, skew, classes, style) {
178
+ this.value = value || "";
179
+ this.height = height || 0;
180
+ this.depth = depth || 0;
181
+ this.italic = italic || 0;
182
+ this.skew = skew || 0;
183
+ this.classes = classes || [];
184
+ this.style = style || {};
185
+ this.maxFontSize = 0;
186
+ }
187
+
188
+ /**
189
+ * Creates a text node or span from a symbol node. Note that a span is only
190
+ * created if it is needed.
191
+ */
192
+ symbolNode.prototype.toNode = function() {
193
+ var node = document.createTextNode(this.value);
194
+ var span = null;
195
+
196
+ if (this.italic > 0) {
197
+ span = document.createElement("span");
198
+ span.style.marginRight = this.italic + "em";
199
+ }
200
+
201
+ if (this.classes.length > 0) {
202
+ span = span || document.createElement("span");
203
+ span.className = createClass(this.classes);
204
+ }
205
+
206
+ for (var style in this.style) {
207
+ if (this.style.hasOwnProperty(style)) {
208
+ span = span || document.createElement("span");
209
+ span.style[style] = this.style[style];
210
+ }
211
+ }
212
+
213
+ if (span) {
214
+ span.appendChild(node);
215
+ return span;
216
+ } else {
217
+ return node;
218
+ }
219
+ };
220
+
221
+ /**
222
+ * Creates markup for a symbol node.
223
+ */
224
+ symbolNode.prototype.toMarkup = function() {
225
+ // TODO(alpert): More duplication than I'd like from
226
+ // span.prototype.toMarkup and symbolNode.prototype.toNode...
227
+ var needsSpan = false;
228
+
229
+ var markup = "<span";
230
+
231
+ if (this.classes.length) {
232
+ needsSpan = true;
233
+ markup += " class=\"";
234
+ markup += utils.escape(createClass(this.classes));
235
+ markup += "\"";
236
+ }
237
+
238
+ var styles = "";
239
+
240
+ if (this.italic > 0) {
241
+ styles += "margin-right:" + this.italic + "em;";
242
+ }
243
+ for (var style in this.style) {
244
+ if (this.style.hasOwnProperty(style)) {
245
+ styles += utils.hyphenate(style) + ":" + this.style[style] + ";";
246
+ }
247
+ }
248
+
249
+ if (styles) {
250
+ needsSpan = true;
251
+ markup += " style=\"" + utils.escape(styles) + "\"";
252
+ }
253
+
254
+ var escaped = utils.escape(this.value);
255
+ if (needsSpan) {
256
+ markup += ">";
257
+ markup += escaped;
258
+ markup += "</span>";
259
+ return markup;
260
+ } else {
261
+ return escaped;
262
+ }
263
+ };
264
+
265
+ module.exports = {
266
+ span: span,
267
+ documentFragment: documentFragment,
268
+ symbolNode: symbolNode,
269
+ };
katex/src/environments.js ADDED
@@ -0,0 +1,298 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint no-constant-condition:0 */
2
+ var fontMetrics = require("./fontMetrics");
3
+ var parseData = require("./parseData");
4
+ var ParseError = require("./ParseError");
5
+
6
+ var ParseNode = parseData.ParseNode;
7
+
8
+ /**
9
+ * Parse the body of the environment, with rows delimited by \\ and
10
+ * columns delimited by &, and create a nested list in row-major order
11
+ * with one group per cell.
12
+ */
13
+ var q = 0 ;
14
+ function parseArray(parser, result) {
15
+ var row = [];
16
+ var body = [row];
17
+ var rowGaps = [];
18
+
19
+ while (true) {
20
+
21
+ // if (q == 1) console.error(parser.nextToken.text);
22
+ try {
23
+ var cell = parser.parseExpression(false, null);
24
+ } catch (e) {
25
+ // console.error(e);
26
+ exit();
27
+ }
28
+ // if (q == 1) exit();
29
+ row.push(new ParseNode("ordgroup", cell, parser.mode));
30
+ var next = parser.nextToken.text;
31
+ if (next === "&") {
32
+ parser.consume();
33
+ } else if (next === "\\end" || next == "}") {
34
+ break;
35
+ } else if (next === "\\\\" || next === "\\cr") {
36
+ var cr = parser.parseFunction();
37
+ rowGaps.push(cr.value.size);
38
+ row = [];
39
+ body.push(row);
40
+ } else {
41
+ // TODO: Clean up the following hack once #385 got merged
42
+ var pos = Math.min(parser.pos + 1, parser.lexer._input.length);
43
+ throw new ParseError("Expected & or \\\\ or \\end",
44
+ parser.lexer, pos);
45
+ }
46
+ }
47
+ result.body = body;
48
+ result.rowGaps = rowGaps;
49
+ // if (q == 1) exit();
50
+ var node = new ParseNode(result.type, result, parser.mode);
51
+ return node;
52
+ }
53
+
54
+ /*
55
+ * An environment definition is very similar to a function definition:
56
+ * it is declared with a name or a list of names, a set of properties
57
+ * and a handler containing the actual implementation.
58
+ *
59
+ * The properties include:
60
+ * - numArgs: The number of arguments after the \begin{name} function.
61
+ * - argTypes: (optional) Just like for a function
62
+ * - allowedInText: (optional) Whether or not the environment is allowed inside
63
+ * text mode (default false) (not enforced yet)
64
+ * - numOptionalArgs: (optional) Just like for a function
65
+ * A bare number instead of that object indicates the numArgs value.
66
+ *
67
+ * The handler function will receive two arguments
68
+ * - context: information and references provided by the parser
69
+ * - args: an array of arguments passed to \begin{name}
70
+ * The context contains the following properties:
71
+ * - envName: the name of the environment, one of the listed names.
72
+ * - parser: the parser object
73
+ * - lexer: the lexer object
74
+ * - positions: the positions associated with these arguments from args.
75
+ * The handler must return a ParseResult.
76
+ */
77
+
78
+ function defineEnvironment(names, props, handler) {
79
+ if (typeof names === "string") {
80
+ names = [names];
81
+ }
82
+ if (typeof props === "number") {
83
+ props = { numArgs: props };
84
+ }
85
+ // Set default values of environments
86
+ var data = {
87
+ numArgs: props.numArgs || 0,
88
+ argTypes: props.argTypes,
89
+ greediness: 1,
90
+ allowedInText: !!props.allowedInText,
91
+ numOptionalArgs: props.numOptionalArgs || 0,
92
+ handler: handler,
93
+ };
94
+ for (var i = 0; i < names.length; ++i) {
95
+ module.exports[names[i]] = data;
96
+ }
97
+ }
98
+
99
+ // Arrays are part of LaTeX, defined in lttab.dtx so its documentation
100
+ // is part of the source2e.pdf file of LaTeX2e source documentation.
101
+ defineEnvironment("array", {
102
+ numArgs: 1,
103
+ }, function(context, args) {
104
+ var colalign = args[0];
105
+ colalign = colalign.value.map ? colalign.value : [colalign];
106
+ var cols = colalign.map(function(node) {
107
+ var ca = node.value;
108
+ if ("lcr".indexOf(ca) !== -1) {
109
+ return {
110
+ type: "align",
111
+ align: ca,
112
+ };
113
+ } else if (ca === "|") {
114
+ return {
115
+ type: "separator",
116
+ separator: "|",
117
+ };
118
+ }
119
+ // throw new ParseError(
120
+ // "Unknown column alignment: " + node.value,
121
+ // context.lexer, context.positions[1]);
122
+ });
123
+ var res = {
124
+ type: "array",
125
+ style: "array",
126
+ cols: cols,
127
+ hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
128
+ };
129
+ res = parseArray(context.parser, res);
130
+ return res;
131
+ });
132
+
133
+ defineEnvironment("tabular", {
134
+ numArgs: 1,
135
+ }, function(context, args) {
136
+ var colalign = args[0];
137
+ colalign = colalign.value.map ? colalign.value : [colalign];
138
+ var cols = colalign.map(function(node) {
139
+ var ca = node.value;
140
+ if ("lcr".indexOf(ca) !== -1) {
141
+ return {
142
+ type: "align",
143
+ align: ca,
144
+ };
145
+ } else if (ca === "|") {
146
+ return {
147
+ type: "separator",
148
+ separator: "|",
149
+ };
150
+ }
151
+ // throw new ParseError(
152
+ // "Unknown column alignment: " + node.value,
153
+ // context.lexer, context.positions[1]);
154
+ });
155
+ var res = {
156
+ type: "array",
157
+ style: "tabular",
158
+ cols: cols,
159
+ hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
160
+ };
161
+ res = parseArray(context.parser, res);
162
+ return res;
163
+ });
164
+
165
+ // The matrix environments of amsmath builds on the array environment
166
+ // of LaTeX, which is discussed above.
167
+ defineEnvironment([
168
+ "matrix",
169
+ "pmatrix",
170
+ "bmatrix",
171
+ "Bmatrix",
172
+ "vmatrix",
173
+ "Vmatrix",
174
+ ], {
175
+ }, function(context) {
176
+ var delimiters = {
177
+ "matrix": null,
178
+ "pmatrix": ["(", ")"],
179
+ "bmatrix": ["[", "]"],
180
+ "Bmatrix": ["\\{", "\\}"],
181
+ "vmatrix": ["|", "|"],
182
+ "Vmatrix": ["\\Vert", "\\Vert"],
183
+ }[context.envName];
184
+ var res = {
185
+ type: "array",
186
+ style: "matrix",
187
+ hskipBeforeAndAfter: false, // \hskip -\arraycolsep in amsmath
188
+ };
189
+ q = 1;
190
+ res = parseArray(context.parser, res);
191
+
192
+ if (delimiters) {
193
+ res = new ParseNode("leftright", {
194
+ body: [res],
195
+ left: delimiters[0],
196
+ right: delimiters[1],
197
+ }, context.mode);
198
+ }
199
+ return res;
200
+ });
201
+
202
+ // A cases environment (in amsmath.sty) is almost equivalent to
203
+ // \def\arraystretch{1.2}%
204
+ // \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
205
+ defineEnvironment("picture", {
206
+ }, function(context) {
207
+ var res = {
208
+ type: "array",
209
+ style: "picture",
210
+ arraystretch: 1.2,
211
+ cols: [{
212
+ type: "align",
213
+ align: "l",
214
+ pregap: 0,
215
+ postgap: fontMetrics.metrics.quad,
216
+ }, {
217
+ type: "align",
218
+ align: "l",
219
+ pregap: 0,
220
+ postgap: 0,
221
+ }],
222
+ };
223
+ res = parseArray(context.parser, res);
224
+ res = new ParseNode("leftright", {
225
+ body: [res],
226
+ left: "\\{",
227
+ right: ".",
228
+ }, context.mode);
229
+ return res;
230
+ });
231
+
232
+ defineEnvironment("cases", {
233
+ }, function(context) {
234
+ var res = {
235
+ type: "array",
236
+ style: "cases",
237
+ arraystretch: 1.2,
238
+ cols: [{
239
+ type: "align",
240
+ align: "l",
241
+ pregap: 0,
242
+ postgap: fontMetrics.metrics.quad,
243
+ }, {
244
+ type: "align",
245
+ align: "l",
246
+ pregap: 0,
247
+ postgap: 0,
248
+ }],
249
+ };
250
+ res = parseArray(context.parser, res);
251
+ res = new ParseNode("leftright", {
252
+ body: [res],
253
+ left: "\\{",
254
+ right: ".",
255
+ }, context.mode);
256
+ return res;
257
+ });
258
+
259
+ // An aligned environment is like the align* environment
260
+ // except it operates within math mode.
261
+ // Note that we assume \nomallineskiplimit to be zero,
262
+ // so that \strut@ is the same as \strut.
263
+ defineEnvironment("aligned", {
264
+ }, function(context) {
265
+ var res = {
266
+ type: "array",
267
+ style: "aligned",
268
+ cols: [],
269
+ };
270
+ res = parseArray(context.parser, res);
271
+ var emptyGroup = new ParseNode("ordgroup", [], context.mode);
272
+ var numCols = 0;
273
+ res.value.body.forEach(function(row) {
274
+ var i;
275
+ for (i = 1; i < row.length; i += 2) {
276
+ row[i].value.unshift(emptyGroup);
277
+ }
278
+ if (numCols < row.length) {
279
+ numCols = row.length;
280
+ }
281
+ });
282
+ for (var i = 0; i < numCols; ++i) {
283
+ var align = "r";
284
+ var pregap = 0;
285
+ if (i % 2 === 1) {
286
+ align = "l";
287
+ } else if (i > 0) {
288
+ pregap = 2; // one \qquad between columns
289
+ }
290
+ res.value.cols[i] = {
291
+ type: "align",
292
+ align: align,
293
+ pregap: pregap,
294
+ postgap: 0,
295
+ };
296
+ }
297
+ return res;
298
+ });
katex/src/fontMetrics.js ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint no-unused-vars:0 */
2
+
3
+ var Style = require("./Style");
4
+
5
+ /**
6
+ * This file contains metrics regarding fonts and individual symbols. The sigma
7
+ * and xi variables, as well as the metricMap map contain data extracted from
8
+ * TeX, TeX font metrics, and the TTF files. These data are then exposed via the
9
+ * `metrics` variable and the getCharacterMetrics function.
10
+ */
11
+
12
+ // These font metrics are extracted from TeX by using
13
+ // \font\a=cmmi10
14
+ // \showthe\fontdimenX\a
15
+ // where X is the corresponding variable number. These correspond to the font
16
+ // parameters of the symbol fonts. In TeX, there are actually three sets of
17
+ // dimensions, one for each of textstyle, scriptstyle, and scriptscriptstyle,
18
+ // but we only use the textstyle ones, and scale certain dimensions accordingly.
19
+ // See the TeXbook, page 441.
20
+ var sigma1 = 0.025;
21
+ var sigma2 = 0;
22
+ var sigma3 = 0;
23
+ var sigma4 = 0;
24
+ var sigma5 = 0.431;
25
+ var sigma6 = 1;
26
+ var sigma7 = 0;
27
+ var sigma8 = 0.677;
28
+ var sigma9 = 0.394;
29
+ var sigma10 = 0.444;
30
+ var sigma11 = 0.686;
31
+ var sigma12 = 0.345;
32
+ var sigma13 = 0.413;
33
+ var sigma14 = 0.363;
34
+ var sigma15 = 0.289;
35
+ var sigma16 = 0.150;
36
+ var sigma17 = 0.247;
37
+ var sigma18 = 0.386;
38
+ var sigma19 = 0.050;
39
+ var sigma20 = 2.390;
40
+ var sigma21 = 1.01;
41
+ var sigma21Script = 0.81;
42
+ var sigma21ScriptScript = 0.71;
43
+ var sigma22 = 0.250;
44
+
45
+ // These font metrics are extracted from TeX by using
46
+ // \font\a=cmex10
47
+ // \showthe\fontdimenX\a
48
+ // where X is the corresponding variable number. These correspond to the font
49
+ // parameters of the extension fonts (family 3). See the TeXbook, page 441.
50
+ var xi1 = 0;
51
+ var xi2 = 0;
52
+ var xi3 = 0;
53
+ var xi4 = 0;
54
+ var xi5 = 0.431;
55
+ var xi6 = 1;
56
+ var xi7 = 0;
57
+ var xi8 = 0.04;
58
+ var xi9 = 0.111;
59
+ var xi10 = 0.166;
60
+ var xi11 = 0.2;
61
+ var xi12 = 0.6;
62
+ var xi13 = 0.1;
63
+
64
+ // This value determines how large a pt is, for metrics which are defined in
65
+ // terms of pts.
66
+ // This value is also used in katex.less; if you change it make sure the values
67
+ // match.
68
+ var ptPerEm = 10.0;
69
+
70
+ // The space between adjacent `|` columns in an array definition. From
71
+ // `\showthe\doublerulesep` in LaTeX.
72
+ var doubleRuleSep = 2.0 / ptPerEm;
73
+
74
+ /**
75
+ * This is just a mapping from common names to real metrics
76
+ */
77
+ var metrics = {
78
+ xHeight: sigma5,
79
+ quad: sigma6,
80
+ num1: sigma8,
81
+ num2: sigma9,
82
+ num3: sigma10,
83
+ denom1: sigma11,
84
+ denom2: sigma12,
85
+ sup1: sigma13,
86
+ sup2: sigma14,
87
+ sup3: sigma15,
88
+ sub1: sigma16,
89
+ sub2: sigma17,
90
+ supDrop: sigma18,
91
+ subDrop: sigma19,
92
+ axisHeight: sigma22,
93
+ defaultRuleThickness: xi8,
94
+ bigOpSpacing1: xi9,
95
+ bigOpSpacing2: xi10,
96
+ bigOpSpacing3: xi11,
97
+ bigOpSpacing4: xi12,
98
+ bigOpSpacing5: xi13,
99
+ ptPerEm: ptPerEm,
100
+ emPerEx: sigma5 / sigma6,
101
+ doubleRuleSep: doubleRuleSep,
102
+
103
+ // TODO(alpert): Missing parallel structure here. We should probably add
104
+ // style-specific metrics for all of these.
105
+ delim1: sigma20,
106
+ getDelim2: function(style) {
107
+ if (style.size === Style.TEXT.size) {
108
+ return sigma21;
109
+ } else if (style.size === Style.SCRIPT.size) {
110
+ return sigma21Script;
111
+ } else if (style.size === Style.SCRIPTSCRIPT.size) {
112
+ return sigma21ScriptScript;
113
+ }
114
+ throw new Error("Unexpected style size: " + style.size);
115
+ },
116
+ };
117
+
118
+ // This map contains a mapping from font name and character code to character
119
+ // metrics, including height, depth, italic correction, and skew (kern from the
120
+ // character to the corresponding \skewchar)
121
+ // This map is generated via `make metrics`. It should not be changed manually.
122
+ var metricMap = require("./fontMetricsData");
123
+
124
+ /**
125
+ * This function is a convenience function for looking up information in the
126
+ * metricMap table. It takes a character as a string, and a style.
127
+ *
128
+ * Note: the `width` property may be undefined if fontMetricsData.js wasn't
129
+ * built using `Make extended_metrics`.
130
+ */
131
+ var getCharacterMetrics = function(character, style) {
132
+ var metrics = metricMap[style][character.charCodeAt(0)];
133
+ if (metrics) {
134
+ return {
135
+ depth: metrics[0],
136
+ height: metrics[1],
137
+ italic: metrics[2],
138
+ skew: metrics[3],
139
+ width: metrics[4],
140
+ };
141
+ }
142
+ };
143
+
144
+ module.exports = {
145
+ metrics: metrics,
146
+ getCharacterMetrics: getCharacterMetrics,
147
+ };
katex/src/fontMetricsData.js ADDED
@@ -0,0 +1,1752 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ "AMS-Regular": {
3
+ "65": [0, 0.68889, 0, 0],
4
+ "66": [0, 0.68889, 0, 0],
5
+ "67": [0, 0.68889, 0, 0],
6
+ "68": [0, 0.68889, 0, 0],
7
+ "69": [0, 0.68889, 0, 0],
8
+ "70": [0, 0.68889, 0, 0],
9
+ "71": [0, 0.68889, 0, 0],
10
+ "72": [0, 0.68889, 0, 0],
11
+ "73": [0, 0.68889, 0, 0],
12
+ "74": [0.16667, 0.68889, 0, 0],
13
+ "75": [0, 0.68889, 0, 0],
14
+ "76": [0, 0.68889, 0, 0],
15
+ "77": [0, 0.68889, 0, 0],
16
+ "78": [0, 0.68889, 0, 0],
17
+ "79": [0.16667, 0.68889, 0, 0],
18
+ "80": [0, 0.68889, 0, 0],
19
+ "81": [0.16667, 0.68889, 0, 0],
20
+ "82": [0, 0.68889, 0, 0],
21
+ "83": [0, 0.68889, 0, 0],
22
+ "84": [0, 0.68889, 0, 0],
23
+ "85": [0, 0.68889, 0, 0],
24
+ "86": [0, 0.68889, 0, 0],
25
+ "87": [0, 0.68889, 0, 0],
26
+ "88": [0, 0.68889, 0, 0],
27
+ "89": [0, 0.68889, 0, 0],
28
+ "90": [0, 0.68889, 0, 0],
29
+ "107": [0, 0.68889, 0, 0],
30
+ "165": [0, 0.675, 0.025, 0],
31
+ "174": [0.15559, 0.69224, 0, 0],
32
+ "240": [0, 0.68889, 0, 0],
33
+ "295": [0, 0.68889, 0, 0],
34
+ "710": [0, 0.825, 0, 0],
35
+ "732": [0, 0.9, 0, 0],
36
+ "770": [0, 0.825, 0, 0],
37
+ "771": [0, 0.9, 0, 0],
38
+ "989": [0.08167, 0.58167, 0, 0],
39
+ "1008": [0, 0.43056, 0.04028, 0],
40
+ "8245": [0, 0.54986, 0, 0],
41
+ "8463": [0, 0.68889, 0, 0],
42
+ "8487": [0, 0.68889, 0, 0],
43
+ "8498": [0, 0.68889, 0, 0],
44
+ "8502": [0, 0.68889, 0, 0],
45
+ "8503": [0, 0.68889, 0, 0],
46
+ "8504": [0, 0.68889, 0, 0],
47
+ "8513": [0, 0.68889, 0, 0],
48
+ "8592": [-0.03598, 0.46402, 0, 0],
49
+ "8594": [-0.03598, 0.46402, 0, 0],
50
+ "8602": [-0.13313, 0.36687, 0, 0],
51
+ "8603": [-0.13313, 0.36687, 0, 0],
52
+ "8606": [0.01354, 0.52239, 0, 0],
53
+ "8608": [0.01354, 0.52239, 0, 0],
54
+ "8610": [0.01354, 0.52239, 0, 0],
55
+ "8611": [0.01354, 0.52239, 0, 0],
56
+ "8619": [0, 0.54986, 0, 0],
57
+ "8620": [0, 0.54986, 0, 0],
58
+ "8621": [-0.13313, 0.37788, 0, 0],
59
+ "8622": [-0.13313, 0.36687, 0, 0],
60
+ "8624": [0, 0.69224, 0, 0],
61
+ "8625": [0, 0.69224, 0, 0],
62
+ "8630": [0, 0.43056, 0, 0],
63
+ "8631": [0, 0.43056, 0, 0],
64
+ "8634": [0.08198, 0.58198, 0, 0],
65
+ "8635": [0.08198, 0.58198, 0, 0],
66
+ "8638": [0.19444, 0.69224, 0, 0],
67
+ "8639": [0.19444, 0.69224, 0, 0],
68
+ "8642": [0.19444, 0.69224, 0, 0],
69
+ "8643": [0.19444, 0.69224, 0, 0],
70
+ "8644": [0.1808, 0.675, 0, 0],
71
+ "8646": [0.1808, 0.675, 0, 0],
72
+ "8647": [0.1808, 0.675, 0, 0],
73
+ "8648": [0.19444, 0.69224, 0, 0],
74
+ "8649": [0.1808, 0.675, 0, 0],
75
+ "8650": [0.19444, 0.69224, 0, 0],
76
+ "8651": [0.01354, 0.52239, 0, 0],
77
+ "8652": [0.01354, 0.52239, 0, 0],
78
+ "8653": [-0.13313, 0.36687, 0, 0],
79
+ "8654": [-0.13313, 0.36687, 0, 0],
80
+ "8655": [-0.13313, 0.36687, 0, 0],
81
+ "8666": [0.13667, 0.63667, 0, 0],
82
+ "8667": [0.13667, 0.63667, 0, 0],
83
+ "8669": [-0.13313, 0.37788, 0, 0],
84
+ "8672": [-0.064, 0.437, 0, 0],
85
+ "8674": [-0.064, 0.437, 0, 0],
86
+ "8705": [0, 0.825, 0, 0],
87
+ "8708": [0, 0.68889, 0, 0],
88
+ "8709": [0.08167, 0.58167, 0, 0],
89
+ "8717": [0, 0.43056, 0, 0],
90
+ "8722": [-0.03598, 0.46402, 0, 0],
91
+ "8724": [0.08198, 0.69224, 0, 0],
92
+ "8726": [0.08167, 0.58167, 0, 0],
93
+ "8733": [0, 0.69224, 0, 0],
94
+ "8736": [0, 0.69224, 0, 0],
95
+ "8737": [0, 0.69224, 0, 0],
96
+ "8738": [0.03517, 0.52239, 0, 0],
97
+ "8739": [0.08167, 0.58167, 0, 0],
98
+ "8740": [0.25142, 0.74111, 0, 0],
99
+ "8741": [0.08167, 0.58167, 0, 0],
100
+ "8742": [0.25142, 0.74111, 0, 0],
101
+ "8756": [0, 0.69224, 0, 0],
102
+ "8757": [0, 0.69224, 0, 0],
103
+ "8764": [-0.13313, 0.36687, 0, 0],
104
+ "8765": [-0.13313, 0.37788, 0, 0],
105
+ "8769": [-0.13313, 0.36687, 0, 0],
106
+ "8770": [-0.03625, 0.46375, 0, 0],
107
+ "8774": [0.30274, 0.79383, 0, 0],
108
+ "8776": [-0.01688, 0.48312, 0, 0],
109
+ "8778": [0.08167, 0.58167, 0, 0],
110
+ "8782": [0.06062, 0.54986, 0, 0],
111
+ "8783": [0.06062, 0.54986, 0, 0],
112
+ "8785": [0.08198, 0.58198, 0, 0],
113
+ "8786": [0.08198, 0.58198, 0, 0],
114
+ "8787": [0.08198, 0.58198, 0, 0],
115
+ "8790": [0, 0.69224, 0, 0],
116
+ "8791": [0.22958, 0.72958, 0, 0],
117
+ "8796": [0.08198, 0.91667, 0, 0],
118
+ "8806": [0.25583, 0.75583, 0, 0],
119
+ "8807": [0.25583, 0.75583, 0, 0],
120
+ "8808": [0.25142, 0.75726, 0, 0],
121
+ "8809": [0.25142, 0.75726, 0, 0],
122
+ "8812": [0.25583, 0.75583, 0, 0],
123
+ "8814": [0.20576, 0.70576, 0, 0],
124
+ "8815": [0.20576, 0.70576, 0, 0],
125
+ "8816": [0.30274, 0.79383, 0, 0],
126
+ "8817": [0.30274, 0.79383, 0, 0],
127
+ "8818": [0.22958, 0.72958, 0, 0],
128
+ "8819": [0.22958, 0.72958, 0, 0],
129
+ "8822": [0.1808, 0.675, 0, 0],
130
+ "8823": [0.1808, 0.675, 0, 0],
131
+ "8828": [0.13667, 0.63667, 0, 0],
132
+ "8829": [0.13667, 0.63667, 0, 0],
133
+ "8830": [0.22958, 0.72958, 0, 0],
134
+ "8831": [0.22958, 0.72958, 0, 0],
135
+ "8832": [0.20576, 0.70576, 0, 0],
136
+ "8833": [0.20576, 0.70576, 0, 0],
137
+ "8840": [0.30274, 0.79383, 0, 0],
138
+ "8841": [0.30274, 0.79383, 0, 0],
139
+ "8842": [0.13597, 0.63597, 0, 0],
140
+ "8843": [0.13597, 0.63597, 0, 0],
141
+ "8847": [0.03517, 0.54986, 0, 0],
142
+ "8848": [0.03517, 0.54986, 0, 0],
143
+ "8858": [0.08198, 0.58198, 0, 0],
144
+ "8859": [0.08198, 0.58198, 0, 0],
145
+ "8861": [0.08198, 0.58198, 0, 0],
146
+ "8862": [0, 0.675, 0, 0],
147
+ "8863": [0, 0.675, 0, 0],
148
+ "8864": [0, 0.675, 0, 0],
149
+ "8865": [0, 0.675, 0, 0],
150
+ "8872": [0, 0.69224, 0, 0],
151
+ "8873": [0, 0.69224, 0, 0],
152
+ "8874": [0, 0.69224, 0, 0],
153
+ "8876": [0, 0.68889, 0, 0],
154
+ "8877": [0, 0.68889, 0, 0],
155
+ "8878": [0, 0.68889, 0, 0],
156
+ "8879": [0, 0.68889, 0, 0],
157
+ "8882": [0.03517, 0.54986, 0, 0],
158
+ "8883": [0.03517, 0.54986, 0, 0],
159
+ "8884": [0.13667, 0.63667, 0, 0],
160
+ "8885": [0.13667, 0.63667, 0, 0],
161
+ "8888": [0, 0.54986, 0, 0],
162
+ "8890": [0.19444, 0.43056, 0, 0],
163
+ "8891": [0.19444, 0.69224, 0, 0],
164
+ "8892": [0.19444, 0.69224, 0, 0],
165
+ "8901": [0, 0.54986, 0, 0],
166
+ "8903": [0.08167, 0.58167, 0, 0],
167
+ "8905": [0.08167, 0.58167, 0, 0],
168
+ "8906": [0.08167, 0.58167, 0, 0],
169
+ "8907": [0, 0.69224, 0, 0],
170
+ "8908": [0, 0.69224, 0, 0],
171
+ "8909": [-0.03598, 0.46402, 0, 0],
172
+ "8910": [0, 0.54986, 0, 0],
173
+ "8911": [0, 0.54986, 0, 0],
174
+ "8912": [0.03517, 0.54986, 0, 0],
175
+ "8913": [0.03517, 0.54986, 0, 0],
176
+ "8914": [0, 0.54986, 0, 0],
177
+ "8915": [0, 0.54986, 0, 0],
178
+ "8916": [0, 0.69224, 0, 0],
179
+ "8918": [0.0391, 0.5391, 0, 0],
180
+ "8919": [0.0391, 0.5391, 0, 0],
181
+ "8920": [0.03517, 0.54986, 0, 0],
182
+ "8921": [0.03517, 0.54986, 0, 0],
183
+ "8922": [0.38569, 0.88569, 0, 0],
184
+ "8923": [0.38569, 0.88569, 0, 0],
185
+ "8926": [0.13667, 0.63667, 0, 0],
186
+ "8927": [0.13667, 0.63667, 0, 0],
187
+ "8928": [0.30274, 0.79383, 0, 0],
188
+ "8929": [0.30274, 0.79383, 0, 0],
189
+ "8934": [0.23222, 0.74111, 0, 0],
190
+ "8935": [0.23222, 0.74111, 0, 0],
191
+ "8936": [0.23222, 0.74111, 0, 0],
192
+ "8937": [0.23222, 0.74111, 0, 0],
193
+ "8938": [0.20576, 0.70576, 0, 0],
194
+ "8939": [0.20576, 0.70576, 0, 0],
195
+ "8940": [0.30274, 0.79383, 0, 0],
196
+ "8941": [0.30274, 0.79383, 0, 0],
197
+ "8994": [0.19444, 0.69224, 0, 0],
198
+ "8995": [0.19444, 0.69224, 0, 0],
199
+ "9416": [0.15559, 0.69224, 0, 0],
200
+ "9484": [0, 0.69224, 0, 0],
201
+ "9488": [0, 0.69224, 0, 0],
202
+ "9492": [0, 0.37788, 0, 0],
203
+ "9496": [0, 0.37788, 0, 0],
204
+ "9585": [0.19444, 0.68889, 0, 0],
205
+ "9586": [0.19444, 0.74111, 0, 0],
206
+ "9632": [0, 0.675, 0, 0],
207
+ "9633": [0, 0.675, 0, 0],
208
+ "9650": [0, 0.54986, 0, 0],
209
+ "9651": [0, 0.54986, 0, 0],
210
+ "9654": [0.03517, 0.54986, 0, 0],
211
+ "9660": [0, 0.54986, 0, 0],
212
+ "9661": [0, 0.54986, 0, 0],
213
+ "9664": [0.03517, 0.54986, 0, 0],
214
+ "9674": [0.11111, 0.69224, 0, 0],
215
+ "9733": [0.19444, 0.69224, 0, 0],
216
+ "10003": [0, 0.69224, 0, 0],
217
+ "10016": [0, 0.69224, 0, 0],
218
+ "10731": [0.11111, 0.69224, 0, 0],
219
+ "10846": [0.19444, 0.75583, 0, 0],
220
+ "10877": [0.13667, 0.63667, 0, 0],
221
+ "10878": [0.13667, 0.63667, 0, 0],
222
+ "10885": [0.25583, 0.75583, 0, 0],
223
+ "10886": [0.25583, 0.75583, 0, 0],
224
+ "10887": [0.13597, 0.63597, 0, 0],
225
+ "10888": [0.13597, 0.63597, 0, 0],
226
+ "10889": [0.26167, 0.75726, 0, 0],
227
+ "10890": [0.26167, 0.75726, 0, 0],
228
+ "10891": [0.48256, 0.98256, 0, 0],
229
+ "10892": [0.48256, 0.98256, 0, 0],
230
+ "10901": [0.13667, 0.63667, 0, 0],
231
+ "10902": [0.13667, 0.63667, 0, 0],
232
+ "10933": [0.25142, 0.75726, 0, 0],
233
+ "10934": [0.25142, 0.75726, 0, 0],
234
+ "10935": [0.26167, 0.75726, 0, 0],
235
+ "10936": [0.26167, 0.75726, 0, 0],
236
+ "10937": [0.26167, 0.75726, 0, 0],
237
+ "10938": [0.26167, 0.75726, 0, 0],
238
+ "10949": [0.25583, 0.75583, 0, 0],
239
+ "10950": [0.25583, 0.75583, 0, 0],
240
+ "10955": [0.28481, 0.79383, 0, 0],
241
+ "10956": [0.28481, 0.79383, 0, 0],
242
+ "57350": [0.08167, 0.58167, 0, 0],
243
+ "57351": [0.08167, 0.58167, 0, 0],
244
+ "57352": [0.08167, 0.58167, 0, 0],
245
+ "57353": [0, 0.43056, 0.04028, 0],
246
+ "57356": [0.25142, 0.75726, 0, 0],
247
+ "57357": [0.25142, 0.75726, 0, 0],
248
+ "57358": [0.41951, 0.91951, 0, 0],
249
+ "57359": [0.30274, 0.79383, 0, 0],
250
+ "57360": [0.30274, 0.79383, 0, 0],
251
+ "57361": [0.41951, 0.91951, 0, 0],
252
+ "57366": [0.25142, 0.75726, 0, 0],
253
+ "57367": [0.25142, 0.75726, 0, 0],
254
+ "57368": [0.25142, 0.75726, 0, 0],
255
+ "57369": [0.25142, 0.75726, 0, 0],
256
+ "57370": [0.13597, 0.63597, 0, 0],
257
+ "57371": [0.13597, 0.63597, 0, 0],
258
+ },
259
+ "Caligraphic-Regular": {
260
+ "48": [0, 0.43056, 0, 0],
261
+ "49": [0, 0.43056, 0, 0],
262
+ "50": [0, 0.43056, 0, 0],
263
+ "51": [0.19444, 0.43056, 0, 0],
264
+ "52": [0.19444, 0.43056, 0, 0],
265
+ "53": [0.19444, 0.43056, 0, 0],
266
+ "54": [0, 0.64444, 0, 0],
267
+ "55": [0.19444, 0.43056, 0, 0],
268
+ "56": [0, 0.64444, 0, 0],
269
+ "57": [0.19444, 0.43056, 0, 0],
270
+ "65": [0, 0.68333, 0, 0.19445],
271
+ "66": [0, 0.68333, 0.03041, 0.13889],
272
+ "67": [0, 0.68333, 0.05834, 0.13889],
273
+ "68": [0, 0.68333, 0.02778, 0.08334],
274
+ "69": [0, 0.68333, 0.08944, 0.11111],
275
+ "70": [0, 0.68333, 0.09931, 0.11111],
276
+ "71": [0.09722, 0.68333, 0.0593, 0.11111],
277
+ "72": [0, 0.68333, 0.00965, 0.11111],
278
+ "73": [0, 0.68333, 0.07382, 0],
279
+ "74": [0.09722, 0.68333, 0.18472, 0.16667],
280
+ "75": [0, 0.68333, 0.01445, 0.05556],
281
+ "76": [0, 0.68333, 0, 0.13889],
282
+ "77": [0, 0.68333, 0, 0.13889],
283
+ "78": [0, 0.68333, 0.14736, 0.08334],
284
+ "79": [0, 0.68333, 0.02778, 0.11111],
285
+ "80": [0, 0.68333, 0.08222, 0.08334],
286
+ "81": [0.09722, 0.68333, 0, 0.11111],
287
+ "82": [0, 0.68333, 0, 0.08334],
288
+ "83": [0, 0.68333, 0.075, 0.13889],
289
+ "84": [0, 0.68333, 0.25417, 0],
290
+ "85": [0, 0.68333, 0.09931, 0.08334],
291
+ "86": [0, 0.68333, 0.08222, 0],
292
+ "87": [0, 0.68333, 0.08222, 0.08334],
293
+ "88": [0, 0.68333, 0.14643, 0.13889],
294
+ "89": [0.09722, 0.68333, 0.08222, 0.08334],
295
+ "90": [0, 0.68333, 0.07944, 0.13889],
296
+ },
297
+ "Fraktur-Regular": {
298
+ "33": [0, 0.69141, 0, 0],
299
+ "34": [0, 0.69141, 0, 0],
300
+ "38": [0, 0.69141, 0, 0],
301
+ "39": [0, 0.69141, 0, 0],
302
+ "40": [0.24982, 0.74947, 0, 0],
303
+ "41": [0.24982, 0.74947, 0, 0],
304
+ "42": [0, 0.62119, 0, 0],
305
+ "43": [0.08319, 0.58283, 0, 0],
306
+ "44": [0, 0.10803, 0, 0],
307
+ "45": [0.08319, 0.58283, 0, 0],
308
+ "46": [0, 0.10803, 0, 0],
309
+ "47": [0.24982, 0.74947, 0, 0],
310
+ "48": [0, 0.47534, 0, 0],
311
+ "49": [0, 0.47534, 0, 0],
312
+ "50": [0, 0.47534, 0, 0],
313
+ "51": [0.18906, 0.47534, 0, 0],
314
+ "52": [0.18906, 0.47534, 0, 0],
315
+ "53": [0.18906, 0.47534, 0, 0],
316
+ "54": [0, 0.69141, 0, 0],
317
+ "55": [0.18906, 0.47534, 0, 0],
318
+ "56": [0, 0.69141, 0, 0],
319
+ "57": [0.18906, 0.47534, 0, 0],
320
+ "58": [0, 0.47534, 0, 0],
321
+ "59": [0.12604, 0.47534, 0, 0],
322
+ "61": [-0.13099, 0.36866, 0, 0],
323
+ "63": [0, 0.69141, 0, 0],
324
+ "65": [0, 0.69141, 0, 0],
325
+ "66": [0, 0.69141, 0, 0],
326
+ "67": [0, 0.69141, 0, 0],
327
+ "68": [0, 0.69141, 0, 0],
328
+ "69": [0, 0.69141, 0, 0],
329
+ "70": [0.12604, 0.69141, 0, 0],
330
+ "71": [0, 0.69141, 0, 0],
331
+ "72": [0.06302, 0.69141, 0, 0],
332
+ "73": [0, 0.69141, 0, 0],
333
+ "74": [0.12604, 0.69141, 0, 0],
334
+ "75": [0, 0.69141, 0, 0],
335
+ "76": [0, 0.69141, 0, 0],
336
+ "77": [0, 0.69141, 0, 0],
337
+ "78": [0, 0.69141, 0, 0],
338
+ "79": [0, 0.69141, 0, 0],
339
+ "80": [0.18906, 0.69141, 0, 0],
340
+ "81": [0.03781, 0.69141, 0, 0],
341
+ "82": [0, 0.69141, 0, 0],
342
+ "83": [0, 0.69141, 0, 0],
343
+ "84": [0, 0.69141, 0, 0],
344
+ "85": [0, 0.69141, 0, 0],
345
+ "86": [0, 0.69141, 0, 0],
346
+ "87": [0, 0.69141, 0, 0],
347
+ "88": [0, 0.69141, 0, 0],
348
+ "89": [0.18906, 0.69141, 0, 0],
349
+ "90": [0.12604, 0.69141, 0, 0],
350
+ "91": [0.24982, 0.74947, 0, 0],
351
+ "93": [0.24982, 0.74947, 0, 0],
352
+ "94": [0, 0.69141, 0, 0],
353
+ "97": [0, 0.47534, 0, 0],
354
+ "98": [0, 0.69141, 0, 0],
355
+ "99": [0, 0.47534, 0, 0],
356
+ "100": [0, 0.62119, 0, 0],
357
+ "101": [0, 0.47534, 0, 0],
358
+ "102": [0.18906, 0.69141, 0, 0],
359
+ "103": [0.18906, 0.47534, 0, 0],
360
+ "104": [0.18906, 0.69141, 0, 0],
361
+ "105": [0, 0.69141, 0, 0],
362
+ "106": [0, 0.69141, 0, 0],
363
+ "107": [0, 0.69141, 0, 0],
364
+ "108": [0, 0.69141, 0, 0],
365
+ "109": [0, 0.47534, 0, 0],
366
+ "110": [0, 0.47534, 0, 0],
367
+ "111": [0, 0.47534, 0, 0],
368
+ "112": [0.18906, 0.52396, 0, 0],
369
+ "113": [0.18906, 0.47534, 0, 0],
370
+ "114": [0, 0.47534, 0, 0],
371
+ "115": [0, 0.47534, 0, 0],
372
+ "116": [0, 0.62119, 0, 0],
373
+ "117": [0, 0.47534, 0, 0],
374
+ "118": [0, 0.52396, 0, 0],
375
+ "119": [0, 0.52396, 0, 0],
376
+ "120": [0.18906, 0.47534, 0, 0],
377
+ "121": [0.18906, 0.47534, 0, 0],
378
+ "122": [0.18906, 0.47534, 0, 0],
379
+ "8216": [0, 0.69141, 0, 0],
380
+ "8217": [0, 0.69141, 0, 0],
381
+ "58112": [0, 0.62119, 0, 0],
382
+ "58113": [0, 0.62119, 0, 0],
383
+ "58114": [0.18906, 0.69141, 0, 0],
384
+ "58115": [0.18906, 0.69141, 0, 0],
385
+ "58116": [0.18906, 0.47534, 0, 0],
386
+ "58117": [0, 0.69141, 0, 0],
387
+ "58118": [0, 0.62119, 0, 0],
388
+ "58119": [0, 0.47534, 0, 0],
389
+ },
390
+ "Main-Bold": {
391
+ "33": [0, 0.69444, 0, 0],
392
+ "34": [0, 0.69444, 0, 0],
393
+ "35": [0.19444, 0.69444, 0, 0],
394
+ "36": [0.05556, 0.75, 0, 0],
395
+ "37": [0.05556, 0.75, 0, 0],
396
+ "38": [0, 0.69444, 0, 0],
397
+ "39": [0, 0.69444, 0, 0],
398
+ "40": [0.25, 0.75, 0, 0],
399
+ "41": [0.25, 0.75, 0, 0],
400
+ "42": [0, 0.75, 0, 0],
401
+ "43": [0.13333, 0.63333, 0, 0],
402
+ "44": [0.19444, 0.15556, 0, 0],
403
+ "45": [0, 0.44444, 0, 0],
404
+ "46": [0, 0.15556, 0, 0],
405
+ "47": [0.25, 0.75, 0, 0],
406
+ "48": [0, 0.64444, 0, 0],
407
+ "49": [0, 0.64444, 0, 0],
408
+ "50": [0, 0.64444, 0, 0],
409
+ "51": [0, 0.64444, 0, 0],
410
+ "52": [0, 0.64444, 0, 0],
411
+ "53": [0, 0.64444, 0, 0],
412
+ "54": [0, 0.64444, 0, 0],
413
+ "55": [0, 0.64444, 0, 0],
414
+ "56": [0, 0.64444, 0, 0],
415
+ "57": [0, 0.64444, 0, 0],
416
+ "58": [0, 0.44444, 0, 0],
417
+ "59": [0.19444, 0.44444, 0, 0],
418
+ "60": [0.08556, 0.58556, 0, 0],
419
+ "61": [-0.10889, 0.39111, 0, 0],
420
+ "62": [0.08556, 0.58556, 0, 0],
421
+ "63": [0, 0.69444, 0, 0],
422
+ "64": [0, 0.69444, 0, 0],
423
+ "65": [0, 0.68611, 0, 0],
424
+ "66": [0, 0.68611, 0, 0],
425
+ "67": [0, 0.68611, 0, 0],
426
+ "68": [0, 0.68611, 0, 0],
427
+ "69": [0, 0.68611, 0, 0],
428
+ "70": [0, 0.68611, 0, 0],
429
+ "71": [0, 0.68611, 0, 0],
430
+ "72": [0, 0.68611, 0, 0],
431
+ "73": [0, 0.68611, 0, 0],
432
+ "74": [0, 0.68611, 0, 0],
433
+ "75": [0, 0.68611, 0, 0],
434
+ "76": [0, 0.68611, 0, 0],
435
+ "77": [0, 0.68611, 0, 0],
436
+ "78": [0, 0.68611, 0, 0],
437
+ "79": [0, 0.68611, 0, 0],
438
+ "80": [0, 0.68611, 0, 0],
439
+ "81": [0.19444, 0.68611, 0, 0],
440
+ "82": [0, 0.68611, 0, 0],
441
+ "83": [0, 0.68611, 0, 0],
442
+ "84": [0, 0.68611, 0, 0],
443
+ "85": [0, 0.68611, 0, 0],
444
+ "86": [0, 0.68611, 0.01597, 0],
445
+ "87": [0, 0.68611, 0.01597, 0],
446
+ "88": [0, 0.68611, 0, 0],
447
+ "89": [0, 0.68611, 0.02875, 0],
448
+ "90": [0, 0.68611, 0, 0],
449
+ "91": [0.25, 0.75, 0, 0],
450
+ "92": [0.25, 0.75, 0, 0],
451
+ "93": [0.25, 0.75, 0, 0],
452
+ "94": [0, 0.69444, 0, 0],
453
+ "95": [0.31, 0.13444, 0.03194, 0],
454
+ "96": [0, 0.69444, 0, 0],
455
+ "97": [0, 0.44444, 0, 0],
456
+ "98": [0, 0.69444, 0, 0],
457
+ "99": [0, 0.44444, 0, 0],
458
+ "100": [0, 0.69444, 0, 0],
459
+ "101": [0, 0.44444, 0, 0],
460
+ "102": [0, 0.69444, 0.10903, 0],
461
+ "103": [0.19444, 0.44444, 0.01597, 0],
462
+ "104": [0, 0.69444, 0, 0],
463
+ "105": [0, 0.69444, 0, 0],
464
+ "106": [0.19444, 0.69444, 0, 0],
465
+ "107": [0, 0.69444, 0, 0],
466
+ "108": [0, 0.69444, 0, 0],
467
+ "109": [0, 0.44444, 0, 0],
468
+ "110": [0, 0.44444, 0, 0],
469
+ "111": [0, 0.44444, 0, 0],
470
+ "112": [0.19444, 0.44444, 0, 0],
471
+ "113": [0.19444, 0.44444, 0, 0],
472
+ "114": [0, 0.44444, 0, 0],
473
+ "115": [0, 0.44444, 0, 0],
474
+ "116": [0, 0.63492, 0, 0],
475
+ "117": [0, 0.44444, 0, 0],
476
+ "118": [0, 0.44444, 0.01597, 0],
477
+ "119": [0, 0.44444, 0.01597, 0],
478
+ "120": [0, 0.44444, 0, 0],
479
+ "121": [0.19444, 0.44444, 0.01597, 0],
480
+ "122": [0, 0.44444, 0, 0],
481
+ "123": [0.25, 0.75, 0, 0],
482
+ "124": [0.25, 0.75, 0, 0],
483
+ "125": [0.25, 0.75, 0, 0],
484
+ "126": [0.35, 0.34444, 0, 0],
485
+ "168": [0, 0.69444, 0, 0],
486
+ "172": [0, 0.44444, 0, 0],
487
+ "175": [0, 0.59611, 0, 0],
488
+ "176": [0, 0.69444, 0, 0],
489
+ "177": [0.13333, 0.63333, 0, 0],
490
+ "180": [0, 0.69444, 0, 0],
491
+ "215": [0.13333, 0.63333, 0, 0],
492
+ "247": [0.13333, 0.63333, 0, 0],
493
+ "305": [0, 0.44444, 0, 0],
494
+ "567": [0.19444, 0.44444, 0, 0],
495
+ "710": [0, 0.69444, 0, 0],
496
+ "711": [0, 0.63194, 0, 0],
497
+ "713": [0, 0.59611, 0, 0],
498
+ "714": [0, 0.69444, 0, 0],
499
+ "715": [0, 0.69444, 0, 0],
500
+ "728": [0, 0.69444, 0, 0],
501
+ "729": [0, 0.69444, 0, 0],
502
+ "730": [0, 0.69444, 0, 0],
503
+ "732": [0, 0.69444, 0, 0],
504
+ "768": [0, 0.69444, 0, 0],
505
+ "769": [0, 0.69444, 0, 0],
506
+ "770": [0, 0.69444, 0, 0],
507
+ "771": [0, 0.69444, 0, 0],
508
+ "772": [0, 0.59611, 0, 0],
509
+ "774": [0, 0.69444, 0, 0],
510
+ "775": [0, 0.69444, 0, 0],
511
+ "776": [0, 0.69444, 0, 0],
512
+ "778": [0, 0.69444, 0, 0],
513
+ "779": [0, 0.69444, 0, 0],
514
+ "780": [0, 0.63194, 0, 0],
515
+ "824": [0.19444, 0.69444, 0, 0],
516
+ "915": [0, 0.68611, 0, 0],
517
+ "916": [0, 0.68611, 0, 0],
518
+ "920": [0, 0.68611, 0, 0],
519
+ "923": [0, 0.68611, 0, 0],
520
+ "926": [0, 0.68611, 0, 0],
521
+ "928": [0, 0.68611, 0, 0],
522
+ "931": [0, 0.68611, 0, 0],
523
+ "933": [0, 0.68611, 0, 0],
524
+ "934": [0, 0.68611, 0, 0],
525
+ "936": [0, 0.68611, 0, 0],
526
+ "937": [0, 0.68611, 0, 0],
527
+ "8211": [0, 0.44444, 0.03194, 0],
528
+ "8212": [0, 0.44444, 0.03194, 0],
529
+ "8216": [0, 0.69444, 0, 0],
530
+ "8217": [0, 0.69444, 0, 0],
531
+ "8220": [0, 0.69444, 0, 0],
532
+ "8221": [0, 0.69444, 0, 0],
533
+ "8224": [0.19444, 0.69444, 0, 0],
534
+ "8225": [0.19444, 0.69444, 0, 0],
535
+ "8242": [0, 0.55556, 0, 0],
536
+ "8407": [0, 0.72444, 0.15486, 0],
537
+ "8463": [0, 0.69444, 0, 0],
538
+ "8465": [0, 0.69444, 0, 0],
539
+ "8467": [0, 0.69444, 0, 0],
540
+ "8472": [0.19444, 0.44444, 0, 0],
541
+ "8476": [0, 0.69444, 0, 0],
542
+ "8501": [0, 0.69444, 0, 0],
543
+ "8592": [-0.10889, 0.39111, 0, 0],
544
+ "8593": [0.19444, 0.69444, 0, 0],
545
+ "8594": [-0.10889, 0.39111, 0, 0],
546
+ "8595": [0.19444, 0.69444, 0, 0],
547
+ "8596": [-0.10889, 0.39111, 0, 0],
548
+ "8597": [0.25, 0.75, 0, 0],
549
+ "8598": [0.19444, 0.69444, 0, 0],
550
+ "8599": [0.19444, 0.69444, 0, 0],
551
+ "8600": [0.19444, 0.69444, 0, 0],
552
+ "8601": [0.19444, 0.69444, 0, 0],
553
+ "8636": [-0.10889, 0.39111, 0, 0],
554
+ "8637": [-0.10889, 0.39111, 0, 0],
555
+ "8640": [-0.10889, 0.39111, 0, 0],
556
+ "8641": [-0.10889, 0.39111, 0, 0],
557
+ "8656": [-0.10889, 0.39111, 0, 0],
558
+ "8657": [0.19444, 0.69444, 0, 0],
559
+ "8658": [-0.10889, 0.39111, 0, 0],
560
+ "8659": [0.19444, 0.69444, 0, 0],
561
+ "8660": [-0.10889, 0.39111, 0, 0],
562
+ "8661": [0.25, 0.75, 0, 0],
563
+ "8704": [0, 0.69444, 0, 0],
564
+ "8706": [0, 0.69444, 0.06389, 0],
565
+ "8707": [0, 0.69444, 0, 0],
566
+ "8709": [0.05556, 0.75, 0, 0],
567
+ "8711": [0, 0.68611, 0, 0],
568
+ "8712": [0.08556, 0.58556, 0, 0],
569
+ "8715": [0.08556, 0.58556, 0, 0],
570
+ "8722": [0.13333, 0.63333, 0, 0],
571
+ "8723": [0.13333, 0.63333, 0, 0],
572
+ "8725": [0.25, 0.75, 0, 0],
573
+ "8726": [0.25, 0.75, 0, 0],
574
+ "8727": [-0.02778, 0.47222, 0, 0],
575
+ "8728": [-0.02639, 0.47361, 0, 0],
576
+ "8729": [-0.02639, 0.47361, 0, 0],
577
+ "8730": [0.18, 0.82, 0, 0],
578
+ "8733": [0, 0.44444, 0, 0],
579
+ "8734": [0, 0.44444, 0, 0],
580
+ "8736": [0, 0.69224, 0, 0],
581
+ "8739": [0.25, 0.75, 0, 0],
582
+ "8741": [0.25, 0.75, 0, 0],
583
+ "8743": [0, 0.55556, 0, 0],
584
+ "8744": [0, 0.55556, 0, 0],
585
+ "8745": [0, 0.55556, 0, 0],
586
+ "8746": [0, 0.55556, 0, 0],
587
+ "8747": [0.19444, 0.69444, 0.12778, 0],
588
+ "8764": [-0.10889, 0.39111, 0, 0],
589
+ "8768": [0.19444, 0.69444, 0, 0],
590
+ "8771": [0.00222, 0.50222, 0, 0],
591
+ "8776": [0.02444, 0.52444, 0, 0],
592
+ "8781": [0.00222, 0.50222, 0, 0],
593
+ "8801": [0.00222, 0.50222, 0, 0],
594
+ "8804": [0.19667, 0.69667, 0, 0],
595
+ "8805": [0.19667, 0.69667, 0, 0],
596
+ "8810": [0.08556, 0.58556, 0, 0],
597
+ "8811": [0.08556, 0.58556, 0, 0],
598
+ "8826": [0.08556, 0.58556, 0, 0],
599
+ "8827": [0.08556, 0.58556, 0, 0],
600
+ "8834": [0.08556, 0.58556, 0, 0],
601
+ "8835": [0.08556, 0.58556, 0, 0],
602
+ "8838": [0.19667, 0.69667, 0, 0],
603
+ "8839": [0.19667, 0.69667, 0, 0],
604
+ "8846": [0, 0.55556, 0, 0],
605
+ "8849": [0.19667, 0.69667, 0, 0],
606
+ "8850": [0.19667, 0.69667, 0, 0],
607
+ "8851": [0, 0.55556, 0, 0],
608
+ "8852": [0, 0.55556, 0, 0],
609
+ "8853": [0.13333, 0.63333, 0, 0],
610
+ "8854": [0.13333, 0.63333, 0, 0],
611
+ "8855": [0.13333, 0.63333, 0, 0],
612
+ "8856": [0.13333, 0.63333, 0, 0],
613
+ "8857": [0.13333, 0.63333, 0, 0],
614
+ "8866": [0, 0.69444, 0, 0],
615
+ "8867": [0, 0.69444, 0, 0],
616
+ "8868": [0, 0.69444, 0, 0],
617
+ "8869": [0, 0.69444, 0, 0],
618
+ "8900": [-0.02639, 0.47361, 0, 0],
619
+ "8901": [-0.02639, 0.47361, 0, 0],
620
+ "8902": [-0.02778, 0.47222, 0, 0],
621
+ "8968": [0.25, 0.75, 0, 0],
622
+ "8969": [0.25, 0.75, 0, 0],
623
+ "8970": [0.25, 0.75, 0, 0],
624
+ "8971": [0.25, 0.75, 0, 0],
625
+ "8994": [-0.13889, 0.36111, 0, 0],
626
+ "8995": [-0.13889, 0.36111, 0, 0],
627
+ "9651": [0.19444, 0.69444, 0, 0],
628
+ "9657": [-0.02778, 0.47222, 0, 0],
629
+ "9661": [0.19444, 0.69444, 0, 0],
630
+ "9667": [-0.02778, 0.47222, 0, 0],
631
+ "9711": [0.19444, 0.69444, 0, 0],
632
+ "9824": [0.12963, 0.69444, 0, 0],
633
+ "9825": [0.12963, 0.69444, 0, 0],
634
+ "9826": [0.12963, 0.69444, 0, 0],
635
+ "9827": [0.12963, 0.69444, 0, 0],
636
+ "9837": [0, 0.75, 0, 0],
637
+ "9838": [0.19444, 0.69444, 0, 0],
638
+ "9839": [0.19444, 0.69444, 0, 0],
639
+ "10216": [0.25, 0.75, 0, 0],
640
+ "10217": [0.25, 0.75, 0, 0],
641
+ "10815": [0, 0.68611, 0, 0],
642
+ "10927": [0.19667, 0.69667, 0, 0],
643
+ "10928": [0.19667, 0.69667, 0, 0],
644
+ },
645
+ "Main-Italic": {
646
+ "33": [0, 0.69444, 0.12417, 0],
647
+ "34": [0, 0.69444, 0.06961, 0],
648
+ "35": [0.19444, 0.69444, 0.06616, 0],
649
+ "37": [0.05556, 0.75, 0.13639, 0],
650
+ "38": [0, 0.69444, 0.09694, 0],
651
+ "39": [0, 0.69444, 0.12417, 0],
652
+ "40": [0.25, 0.75, 0.16194, 0],
653
+ "41": [0.25, 0.75, 0.03694, 0],
654
+ "42": [0, 0.75, 0.14917, 0],
655
+ "43": [0.05667, 0.56167, 0.03694, 0],
656
+ "44": [0.19444, 0.10556, 0, 0],
657
+ "45": [0, 0.43056, 0.02826, 0],
658
+ "46": [0, 0.10556, 0, 0],
659
+ "47": [0.25, 0.75, 0.16194, 0],
660
+ "48": [0, 0.64444, 0.13556, 0],
661
+ "49": [0, 0.64444, 0.13556, 0],
662
+ "50": [0, 0.64444, 0.13556, 0],
663
+ "51": [0, 0.64444, 0.13556, 0],
664
+ "52": [0.19444, 0.64444, 0.13556, 0],
665
+ "53": [0, 0.64444, 0.13556, 0],
666
+ "54": [0, 0.64444, 0.13556, 0],
667
+ "55": [0.19444, 0.64444, 0.13556, 0],
668
+ "56": [0, 0.64444, 0.13556, 0],
669
+ "57": [0, 0.64444, 0.13556, 0],
670
+ "58": [0, 0.43056, 0.0582, 0],
671
+ "59": [0.19444, 0.43056, 0.0582, 0],
672
+ "61": [-0.13313, 0.36687, 0.06616, 0],
673
+ "63": [0, 0.69444, 0.1225, 0],
674
+ "64": [0, 0.69444, 0.09597, 0],
675
+ "65": [0, 0.68333, 0, 0],
676
+ "66": [0, 0.68333, 0.10257, 0],
677
+ "67": [0, 0.68333, 0.14528, 0],
678
+ "68": [0, 0.68333, 0.09403, 0],
679
+ "69": [0, 0.68333, 0.12028, 0],
680
+ "70": [0, 0.68333, 0.13305, 0],
681
+ "71": [0, 0.68333, 0.08722, 0],
682
+ "72": [0, 0.68333, 0.16389, 0],
683
+ "73": [0, 0.68333, 0.15806, 0],
684
+ "74": [0, 0.68333, 0.14028, 0],
685
+ "75": [0, 0.68333, 0.14528, 0],
686
+ "76": [0, 0.68333, 0, 0],
687
+ "77": [0, 0.68333, 0.16389, 0],
688
+ "78": [0, 0.68333, 0.16389, 0],
689
+ "79": [0, 0.68333, 0.09403, 0],
690
+ "80": [0, 0.68333, 0.10257, 0],
691
+ "81": [0.19444, 0.68333, 0.09403, 0],
692
+ "82": [0, 0.68333, 0.03868, 0],
693
+ "83": [0, 0.68333, 0.11972, 0],
694
+ "84": [0, 0.68333, 0.13305, 0],
695
+ "85": [0, 0.68333, 0.16389, 0],
696
+ "86": [0, 0.68333, 0.18361, 0],
697
+ "87": [0, 0.68333, 0.18361, 0],
698
+ "88": [0, 0.68333, 0.15806, 0],
699
+ "89": [0, 0.68333, 0.19383, 0],
700
+ "90": [0, 0.68333, 0.14528, 0],
701
+ "91": [0.25, 0.75, 0.1875, 0],
702
+ "93": [0.25, 0.75, 0.10528, 0],
703
+ "94": [0, 0.69444, 0.06646, 0],
704
+ "95": [0.31, 0.12056, 0.09208, 0],
705
+ "97": [0, 0.43056, 0.07671, 0],
706
+ "98": [0, 0.69444, 0.06312, 0],
707
+ "99": [0, 0.43056, 0.05653, 0],
708
+ "100": [0, 0.69444, 0.10333, 0],
709
+ "101": [0, 0.43056, 0.07514, 0],
710
+ "102": [0.19444, 0.69444, 0.21194, 0],
711
+ "103": [0.19444, 0.43056, 0.08847, 0],
712
+ "104": [0, 0.69444, 0.07671, 0],
713
+ "105": [0, 0.65536, 0.1019, 0],
714
+ "106": [0.19444, 0.65536, 0.14467, 0],
715
+ "107": [0, 0.69444, 0.10764, 0],
716
+ "108": [0, 0.69444, 0.10333, 0],
717
+ "109": [0, 0.43056, 0.07671, 0],
718
+ "110": [0, 0.43056, 0.07671, 0],
719
+ "111": [0, 0.43056, 0.06312, 0],
720
+ "112": [0.19444, 0.43056, 0.06312, 0],
721
+ "113": [0.19444, 0.43056, 0.08847, 0],
722
+ "114": [0, 0.43056, 0.10764, 0],
723
+ "115": [0, 0.43056, 0.08208, 0],
724
+ "116": [0, 0.61508, 0.09486, 0],
725
+ "117": [0, 0.43056, 0.07671, 0],
726
+ "118": [0, 0.43056, 0.10764, 0],
727
+ "119": [0, 0.43056, 0.10764, 0],
728
+ "120": [0, 0.43056, 0.12042, 0],
729
+ "121": [0.19444, 0.43056, 0.08847, 0],
730
+ "122": [0, 0.43056, 0.12292, 0],
731
+ "126": [0.35, 0.31786, 0.11585, 0],
732
+ "163": [0, 0.69444, 0, 0],
733
+ "305": [0, 0.43056, 0, 0.02778],
734
+ "567": [0.19444, 0.43056, 0, 0.08334],
735
+ "768": [0, 0.69444, 0, 0],
736
+ "769": [0, 0.69444, 0.09694, 0],
737
+ "770": [0, 0.69444, 0.06646, 0],
738
+ "771": [0, 0.66786, 0.11585, 0],
739
+ "772": [0, 0.56167, 0.10333, 0],
740
+ "774": [0, 0.69444, 0.10806, 0],
741
+ "775": [0, 0.66786, 0.11752, 0],
742
+ "776": [0, 0.66786, 0.10474, 0],
743
+ "778": [0, 0.69444, 0, 0],
744
+ "779": [0, 0.69444, 0.1225, 0],
745
+ "780": [0, 0.62847, 0.08295, 0],
746
+ "915": [0, 0.68333, 0.13305, 0],
747
+ "916": [0, 0.68333, 0, 0],
748
+ "920": [0, 0.68333, 0.09403, 0],
749
+ "923": [0, 0.68333, 0, 0],
750
+ "926": [0, 0.68333, 0.15294, 0],
751
+ "928": [0, 0.68333, 0.16389, 0],
752
+ "931": [0, 0.68333, 0.12028, 0],
753
+ "933": [0, 0.68333, 0.11111, 0],
754
+ "934": [0, 0.68333, 0.05986, 0],
755
+ "936": [0, 0.68333, 0.11111, 0],
756
+ "937": [0, 0.68333, 0.10257, 0],
757
+ "8211": [0, 0.43056, 0.09208, 0],
758
+ "8212": [0, 0.43056, 0.09208, 0],
759
+ "8216": [0, 0.69444, 0.12417, 0],
760
+ "8217": [0, 0.69444, 0.12417, 0],
761
+ "8220": [0, 0.69444, 0.1685, 0],
762
+ "8221": [0, 0.69444, 0.06961, 0],
763
+ "8463": [0, 0.68889, 0, 0],
764
+ },
765
+ "Main-Regular": {
766
+ "32": [0, 0, 0, 0],
767
+ "33": [0, 0.69444, 0, 0],
768
+ "34": [0, 0.69444, 0, 0],
769
+ "35": [0.19444, 0.69444, 0, 0],
770
+ "36": [0.05556, 0.75, 0, 0],
771
+ "37": [0.05556, 0.75, 0, 0],
772
+ "38": [0, 0.69444, 0, 0],
773
+ "39": [0, 0.69444, 0, 0],
774
+ "40": [0.25, 0.75, 0, 0],
775
+ "41": [0.25, 0.75, 0, 0],
776
+ "42": [0, 0.75, 0, 0],
777
+ "43": [0.08333, 0.58333, 0, 0],
778
+ "44": [0.19444, 0.10556, 0, 0],
779
+ "45": [0, 0.43056, 0, 0],
780
+ "46": [0, 0.10556, 0, 0],
781
+ "47": [0.25, 0.75, 0, 0],
782
+ "48": [0, 0.64444, 0, 0],
783
+ "49": [0, 0.64444, 0, 0],
784
+ "50": [0, 0.64444, 0, 0],
785
+ "51": [0, 0.64444, 0, 0],
786
+ "52": [0, 0.64444, 0, 0],
787
+ "53": [0, 0.64444, 0, 0],
788
+ "54": [0, 0.64444, 0, 0],
789
+ "55": [0, 0.64444, 0, 0],
790
+ "56": [0, 0.64444, 0, 0],
791
+ "57": [0, 0.64444, 0, 0],
792
+ "58": [0, 0.43056, 0, 0],
793
+ "59": [0.19444, 0.43056, 0, 0],
794
+ "60": [0.0391, 0.5391, 0, 0],
795
+ "61": [-0.13313, 0.36687, 0, 0],
796
+ "62": [0.0391, 0.5391, 0, 0],
797
+ "63": [0, 0.69444, 0, 0],
798
+ "64": [0, 0.69444, 0, 0],
799
+ "65": [0, 0.68333, 0, 0],
800
+ "66": [0, 0.68333, 0, 0],
801
+ "67": [0, 0.68333, 0, 0],
802
+ "68": [0, 0.68333, 0, 0],
803
+ "69": [0, 0.68333, 0, 0],
804
+ "70": [0, 0.68333, 0, 0],
805
+ "71": [0, 0.68333, 0, 0],
806
+ "72": [0, 0.68333, 0, 0],
807
+ "73": [0, 0.68333, 0, 0],
808
+ "74": [0, 0.68333, 0, 0],
809
+ "75": [0, 0.68333, 0, 0],
810
+ "76": [0, 0.68333, 0, 0],
811
+ "77": [0, 0.68333, 0, 0],
812
+ "78": [0, 0.68333, 0, 0],
813
+ "79": [0, 0.68333, 0, 0],
814
+ "80": [0, 0.68333, 0, 0],
815
+ "81": [0.19444, 0.68333, 0, 0],
816
+ "82": [0, 0.68333, 0, 0],
817
+ "83": [0, 0.68333, 0, 0],
818
+ "84": [0, 0.68333, 0, 0],
819
+ "85": [0, 0.68333, 0, 0],
820
+ "86": [0, 0.68333, 0.01389, 0],
821
+ "87": [0, 0.68333, 0.01389, 0],
822
+ "88": [0, 0.68333, 0, 0],
823
+ "89": [0, 0.68333, 0.025, 0],
824
+ "90": [0, 0.68333, 0, 0],
825
+ "91": [0.25, 0.75, 0, 0],
826
+ "92": [0.25, 0.75, 0, 0],
827
+ "93": [0.25, 0.75, 0, 0],
828
+ "94": [0, 0.69444, 0, 0],
829
+ "95": [0.31, 0.12056, 0.02778, 0],
830
+ "96": [0, 0.69444, 0, 0],
831
+ "97": [0, 0.43056, 0, 0],
832
+ "98": [0, 0.69444, 0, 0],
833
+ "99": [0, 0.43056, 0, 0],
834
+ "100": [0, 0.69444, 0, 0],
835
+ "101": [0, 0.43056, 0, 0],
836
+ "102": [0, 0.69444, 0.07778, 0],
837
+ "103": [0.19444, 0.43056, 0.01389, 0],
838
+ "104": [0, 0.69444, 0, 0],
839
+ "105": [0, 0.66786, 0, 0],
840
+ "106": [0.19444, 0.66786, 0, 0],
841
+ "107": [0, 0.69444, 0, 0],
842
+ "108": [0, 0.69444, 0, 0],
843
+ "109": [0, 0.43056, 0, 0],
844
+ "110": [0, 0.43056, 0, 0],
845
+ "111": [0, 0.43056, 0, 0],
846
+ "112": [0.19444, 0.43056, 0, 0],
847
+ "113": [0.19444, 0.43056, 0, 0],
848
+ "114": [0, 0.43056, 0, 0],
849
+ "115": [0, 0.43056, 0, 0],
850
+ "116": [0, 0.61508, 0, 0],
851
+ "117": [0, 0.43056, 0, 0],
852
+ "118": [0, 0.43056, 0.01389, 0],
853
+ "119": [0, 0.43056, 0.01389, 0],
854
+ "120": [0, 0.43056, 0, 0],
855
+ "121": [0.19444, 0.43056, 0.01389, 0],
856
+ "122": [0, 0.43056, 0, 0],
857
+ "123": [0.25, 0.75, 0, 0],
858
+ "124": [0.25, 0.75, 0, 0],
859
+ "125": [0.25, 0.75, 0, 0],
860
+ "126": [0.35, 0.31786, 0, 0],
861
+ "160": [0, 0, 0, 0],
862
+ "168": [0, 0.66786, 0, 0],
863
+ "172": [0, 0.43056, 0, 0],
864
+ "175": [0, 0.56778, 0, 0],
865
+ "176": [0, 0.69444, 0, 0],
866
+ "177": [0.08333, 0.58333, 0, 0],
867
+ "180": [0, 0.69444, 0, 0],
868
+ "215": [0.08333, 0.58333, 0, 0],
869
+ "247": [0.08333, 0.58333, 0, 0],
870
+ "305": [0, 0.43056, 0, 0],
871
+ "567": [0.19444, 0.43056, 0, 0],
872
+ "710": [0, 0.69444, 0, 0],
873
+ "711": [0, 0.62847, 0, 0],
874
+ "713": [0, 0.56778, 0, 0],
875
+ "714": [0, 0.69444, 0, 0],
876
+ "715": [0, 0.69444, 0, 0],
877
+ "728": [0, 0.69444, 0, 0],
878
+ "729": [0, 0.66786, 0, 0],
879
+ "730": [0, 0.69444, 0, 0],
880
+ "732": [0, 0.66786, 0, 0],
881
+ "768": [0, 0.69444, 0, 0],
882
+ "769": [0, 0.69444, 0, 0],
883
+ "770": [0, 0.69444, 0, 0],
884
+ "771": [0, 0.66786, 0, 0],
885
+ "772": [0, 0.56778, 0, 0],
886
+ "774": [0, 0.69444, 0, 0],
887
+ "775": [0, 0.66786, 0, 0],
888
+ "776": [0, 0.66786, 0, 0],
889
+ "778": [0, 0.69444, 0, 0],
890
+ "779": [0, 0.69444, 0, 0],
891
+ "780": [0, 0.62847, 0, 0],
892
+ "824": [0.19444, 0.69444, 0, 0],
893
+ "915": [0, 0.68333, 0, 0],
894
+ "916": [0, 0.68333, 0, 0],
895
+ "920": [0, 0.68333, 0, 0],
896
+ "923": [0, 0.68333, 0, 0],
897
+ "926": [0, 0.68333, 0, 0],
898
+ "928": [0, 0.68333, 0, 0],
899
+ "931": [0, 0.68333, 0, 0],
900
+ "933": [0, 0.68333, 0, 0],
901
+ "934": [0, 0.68333, 0, 0],
902
+ "936": [0, 0.68333, 0, 0],
903
+ "937": [0, 0.68333, 0, 0],
904
+ "8211": [0, 0.43056, 0.02778, 0],
905
+ "8212": [0, 0.43056, 0.02778, 0],
906
+ "8216": [0, 0.69444, 0, 0],
907
+ "8217": [0, 0.69444, 0, 0],
908
+ "8220": [0, 0.69444, 0, 0],
909
+ "8221": [0, 0.69444, 0, 0],
910
+ "8224": [0.19444, 0.69444, 0, 0],
911
+ "8225": [0.19444, 0.69444, 0, 0],
912
+ "8230": [0, 0.12, 0, 0],
913
+ "8242": [0, 0.55556, 0, 0],
914
+ "8407": [0, 0.71444, 0.15382, 0],
915
+ "8463": [0, 0.68889, 0, 0],
916
+ "8465": [0, 0.69444, 0, 0],
917
+ "8467": [0, 0.69444, 0, 0.11111],
918
+ "8472": [0.19444, 0.43056, 0, 0.11111],
919
+ "8476": [0, 0.69444, 0, 0],
920
+ "8501": [0, 0.69444, 0, 0],
921
+ "8592": [-0.13313, 0.36687, 0, 0],
922
+ "8593": [0.19444, 0.69444, 0, 0],
923
+ "8594": [-0.13313, 0.36687, 0, 0],
924
+ "8595": [0.19444, 0.69444, 0, 0],
925
+ "8596": [-0.13313, 0.36687, 0, 0],
926
+ "8597": [0.25, 0.75, 0, 0],
927
+ "8598": [0.19444, 0.69444, 0, 0],
928
+ "8599": [0.19444, 0.69444, 0, 0],
929
+ "8600": [0.19444, 0.69444, 0, 0],
930
+ "8601": [0.19444, 0.69444, 0, 0],
931
+ "8614": [0.011, 0.511, 0, 0],
932
+ "8617": [0.011, 0.511, 0, 0],
933
+ "8618": [0.011, 0.511, 0, 0],
934
+ "8636": [-0.13313, 0.36687, 0, 0],
935
+ "8637": [-0.13313, 0.36687, 0, 0],
936
+ "8640": [-0.13313, 0.36687, 0, 0],
937
+ "8641": [-0.13313, 0.36687, 0, 0],
938
+ "8652": [0.011, 0.671, 0, 0],
939
+ "8656": [-0.13313, 0.36687, 0, 0],
940
+ "8657": [0.19444, 0.69444, 0, 0],
941
+ "8658": [-0.13313, 0.36687, 0, 0],
942
+ "8659": [0.19444, 0.69444, 0, 0],
943
+ "8660": [-0.13313, 0.36687, 0, 0],
944
+ "8661": [0.25, 0.75, 0, 0],
945
+ "8704": [0, 0.69444, 0, 0],
946
+ "8706": [0, 0.69444, 0.05556, 0.08334],
947
+ "8707": [0, 0.69444, 0, 0],
948
+ "8709": [0.05556, 0.75, 0, 0],
949
+ "8711": [0, 0.68333, 0, 0],
950
+ "8712": [0.0391, 0.5391, 0, 0],
951
+ "8715": [0.0391, 0.5391, 0, 0],
952
+ "8722": [0.08333, 0.58333, 0, 0],
953
+ "8723": [0.08333, 0.58333, 0, 0],
954
+ "8725": [0.25, 0.75, 0, 0],
955
+ "8726": [0.25, 0.75, 0, 0],
956
+ "8727": [-0.03472, 0.46528, 0, 0],
957
+ "8728": [-0.05555, 0.44445, 0, 0],
958
+ "8729": [-0.05555, 0.44445, 0, 0],
959
+ "8730": [0.2, 0.8, 0, 0],
960
+ "8733": [0, 0.43056, 0, 0],
961
+ "8734": [0, 0.43056, 0, 0],
962
+ "8736": [0, 0.69224, 0, 0],
963
+ "8739": [0.25, 0.75, 0, 0],
964
+ "8741": [0.25, 0.75, 0, 0],
965
+ "8743": [0, 0.55556, 0, 0],
966
+ "8744": [0, 0.55556, 0, 0],
967
+ "8745": [0, 0.55556, 0, 0],
968
+ "8746": [0, 0.55556, 0, 0],
969
+ "8747": [0.19444, 0.69444, 0.11111, 0],
970
+ "8764": [-0.13313, 0.36687, 0, 0],
971
+ "8768": [0.19444, 0.69444, 0, 0],
972
+ "8771": [-0.03625, 0.46375, 0, 0],
973
+ "8773": [-0.022, 0.589, 0, 0],
974
+ "8776": [-0.01688, 0.48312, 0, 0],
975
+ "8781": [-0.03625, 0.46375, 0, 0],
976
+ "8784": [-0.133, 0.67, 0, 0],
977
+ "8800": [0.215, 0.716, 0, 0],
978
+ "8801": [-0.03625, 0.46375, 0, 0],
979
+ "8804": [0.13597, 0.63597, 0, 0],
980
+ "8805": [0.13597, 0.63597, 0, 0],
981
+ "8810": [0.0391, 0.5391, 0, 0],
982
+ "8811": [0.0391, 0.5391, 0, 0],
983
+ "8826": [0.0391, 0.5391, 0, 0],
984
+ "8827": [0.0391, 0.5391, 0, 0],
985
+ "8834": [0.0391, 0.5391, 0, 0],
986
+ "8835": [0.0391, 0.5391, 0, 0],
987
+ "8838": [0.13597, 0.63597, 0, 0],
988
+ "8839": [0.13597, 0.63597, 0, 0],
989
+ "8846": [0, 0.55556, 0, 0],
990
+ "8849": [0.13597, 0.63597, 0, 0],
991
+ "8850": [0.13597, 0.63597, 0, 0],
992
+ "8851": [0, 0.55556, 0, 0],
993
+ "8852": [0, 0.55556, 0, 0],
994
+ "8853": [0.08333, 0.58333, 0, 0],
995
+ "8854": [0.08333, 0.58333, 0, 0],
996
+ "8855": [0.08333, 0.58333, 0, 0],
997
+ "8856": [0.08333, 0.58333, 0, 0],
998
+ "8857": [0.08333, 0.58333, 0, 0],
999
+ "8866": [0, 0.69444, 0, 0],
1000
+ "8867": [0, 0.69444, 0, 0],
1001
+ "8868": [0, 0.69444, 0, 0],
1002
+ "8869": [0, 0.69444, 0, 0],
1003
+ "8872": [0.249, 0.75, 0, 0],
1004
+ "8900": [-0.05555, 0.44445, 0, 0],
1005
+ "8901": [-0.05555, 0.44445, 0, 0],
1006
+ "8902": [-0.03472, 0.46528, 0, 0],
1007
+ "8904": [0.005, 0.505, 0, 0],
1008
+ "8942": [0.03, 0.9, 0, 0],
1009
+ "8943": [-0.19, 0.31, 0, 0],
1010
+ "8945": [-0.1, 0.82, 0, 0],
1011
+ "8968": [0.25, 0.75, 0, 0],
1012
+ "8969": [0.25, 0.75, 0, 0],
1013
+ "8970": [0.25, 0.75, 0, 0],
1014
+ "8971": [0.25, 0.75, 0, 0],
1015
+ "8994": [-0.14236, 0.35764, 0, 0],
1016
+ "8995": [-0.14236, 0.35764, 0, 0],
1017
+ "9136": [0.244, 0.744, 0, 0],
1018
+ "9137": [0.244, 0.744, 0, 0],
1019
+ "9651": [0.19444, 0.69444, 0, 0],
1020
+ "9657": [-0.03472, 0.46528, 0, 0],
1021
+ "9661": [0.19444, 0.69444, 0, 0],
1022
+ "9667": [-0.03472, 0.46528, 0, 0],
1023
+ "9711": [0.19444, 0.69444, 0, 0],
1024
+ "9824": [0.12963, 0.69444, 0, 0],
1025
+ "9825": [0.12963, 0.69444, 0, 0],
1026
+ "9826": [0.12963, 0.69444, 0, 0],
1027
+ "9827": [0.12963, 0.69444, 0, 0],
1028
+ "9837": [0, 0.75, 0, 0],
1029
+ "9838": [0.19444, 0.69444, 0, 0],
1030
+ "9839": [0.19444, 0.69444, 0, 0],
1031
+ "10216": [0.25, 0.75, 0, 0],
1032
+ "10217": [0.25, 0.75, 0, 0],
1033
+ "10222": [0.244, 0.744, 0, 0],
1034
+ "10223": [0.244, 0.744, 0, 0],
1035
+ "10229": [0.011, 0.511, 0, 0],
1036
+ "10230": [0.011, 0.511, 0, 0],
1037
+ "10231": [0.011, 0.511, 0, 0],
1038
+ "10232": [0.024, 0.525, 0, 0],
1039
+ "10233": [0.024, 0.525, 0, 0],
1040
+ "10234": [0.024, 0.525, 0, 0],
1041
+ "10236": [0.011, 0.511, 0, 0],
1042
+ "10815": [0, 0.68333, 0, 0],
1043
+ "10927": [0.13597, 0.63597, 0, 0],
1044
+ "10928": [0.13597, 0.63597, 0, 0],
1045
+ },
1046
+ "Math-BoldItalic": {
1047
+ "47": [0.19444, 0.69444, 0, 0],
1048
+ "65": [0, 0.68611, 0, 0],
1049
+ "66": [0, 0.68611, 0.04835, 0],
1050
+ "67": [0, 0.68611, 0.06979, 0],
1051
+ "68": [0, 0.68611, 0.03194, 0],
1052
+ "69": [0, 0.68611, 0.05451, 0],
1053
+ "70": [0, 0.68611, 0.15972, 0],
1054
+ "71": [0, 0.68611, 0, 0],
1055
+ "72": [0, 0.68611, 0.08229, 0],
1056
+ "73": [0, 0.68611, 0.07778, 0],
1057
+ "74": [0, 0.68611, 0.10069, 0],
1058
+ "75": [0, 0.68611, 0.06979, 0],
1059
+ "76": [0, 0.68611, 0, 0],
1060
+ "77": [0, 0.68611, 0.11424, 0],
1061
+ "78": [0, 0.68611, 0.11424, 0],
1062
+ "79": [0, 0.68611, 0.03194, 0],
1063
+ "80": [0, 0.68611, 0.15972, 0],
1064
+ "81": [0.19444, 0.68611, 0, 0],
1065
+ "82": [0, 0.68611, 0.00421, 0],
1066
+ "83": [0, 0.68611, 0.05382, 0],
1067
+ "84": [0, 0.68611, 0.15972, 0],
1068
+ "85": [0, 0.68611, 0.11424, 0],
1069
+ "86": [0, 0.68611, 0.25555, 0],
1070
+ "87": [0, 0.68611, 0.15972, 0],
1071
+ "88": [0, 0.68611, 0.07778, 0],
1072
+ "89": [0, 0.68611, 0.25555, 0],
1073
+ "90": [0, 0.68611, 0.06979, 0],
1074
+ "97": [0, 0.44444, 0, 0],
1075
+ "98": [0, 0.69444, 0, 0],
1076
+ "99": [0, 0.44444, 0, 0],
1077
+ "100": [0, 0.69444, 0, 0],
1078
+ "101": [0, 0.44444, 0, 0],
1079
+ "102": [0.19444, 0.69444, 0.11042, 0],
1080
+ "103": [0.19444, 0.44444, 0.03704, 0],
1081
+ "104": [0, 0.69444, 0, 0],
1082
+ "105": [0, 0.69326, 0, 0],
1083
+ "106": [0.19444, 0.69326, 0.0622, 0],
1084
+ "107": [0, 0.69444, 0.01852, 0],
1085
+ "108": [0, 0.69444, 0.0088, 0],
1086
+ "109": [0, 0.44444, 0, 0],
1087
+ "110": [0, 0.44444, 0, 0],
1088
+ "111": [0, 0.44444, 0, 0],
1089
+ "112": [0.19444, 0.44444, 0, 0],
1090
+ "113": [0.19444, 0.44444, 0.03704, 0],
1091
+ "114": [0, 0.44444, 0.03194, 0],
1092
+ "115": [0, 0.44444, 0, 0],
1093
+ "116": [0, 0.63492, 0, 0],
1094
+ "117": [0, 0.44444, 0, 0],
1095
+ "118": [0, 0.44444, 0.03704, 0],
1096
+ "119": [0, 0.44444, 0.02778, 0],
1097
+ "120": [0, 0.44444, 0, 0],
1098
+ "121": [0.19444, 0.44444, 0.03704, 0],
1099
+ "122": [0, 0.44444, 0.04213, 0],
1100
+ "915": [0, 0.68611, 0.15972, 0],
1101
+ "916": [0, 0.68611, 0, 0],
1102
+ "920": [0, 0.68611, 0.03194, 0],
1103
+ "923": [0, 0.68611, 0, 0],
1104
+ "926": [0, 0.68611, 0.07458, 0],
1105
+ "928": [0, 0.68611, 0.08229, 0],
1106
+ "931": [0, 0.68611, 0.05451, 0],
1107
+ "933": [0, 0.68611, 0.15972, 0],
1108
+ "934": [0, 0.68611, 0, 0],
1109
+ "936": [0, 0.68611, 0.11653, 0],
1110
+ "937": [0, 0.68611, 0.04835, 0],
1111
+ "945": [0, 0.44444, 0, 0],
1112
+ "946": [0.19444, 0.69444, 0.03403, 0],
1113
+ "947": [0.19444, 0.44444, 0.06389, 0],
1114
+ "948": [0, 0.69444, 0.03819, 0],
1115
+ "949": [0, 0.44444, 0, 0],
1116
+ "950": [0.19444, 0.69444, 0.06215, 0],
1117
+ "951": [0.19444, 0.44444, 0.03704, 0],
1118
+ "952": [0, 0.69444, 0.03194, 0],
1119
+ "953": [0, 0.44444, 0, 0],
1120
+ "954": [0, 0.44444, 0, 0],
1121
+ "955": [0, 0.69444, 0, 0],
1122
+ "956": [0.19444, 0.44444, 0, 0],
1123
+ "957": [0, 0.44444, 0.06898, 0],
1124
+ "958": [0.19444, 0.69444, 0.03021, 0],
1125
+ "959": [0, 0.44444, 0, 0],
1126
+ "960": [0, 0.44444, 0.03704, 0],
1127
+ "961": [0.19444, 0.44444, 0, 0],
1128
+ "962": [0.09722, 0.44444, 0.07917, 0],
1129
+ "963": [0, 0.44444, 0.03704, 0],
1130
+ "964": [0, 0.44444, 0.13472, 0],
1131
+ "965": [0, 0.44444, 0.03704, 0],
1132
+ "966": [0.19444, 0.44444, 0, 0],
1133
+ "967": [0.19444, 0.44444, 0, 0],
1134
+ "968": [0.19444, 0.69444, 0.03704, 0],
1135
+ "969": [0, 0.44444, 0.03704, 0],
1136
+ "977": [0, 0.69444, 0, 0],
1137
+ "981": [0.19444, 0.69444, 0, 0],
1138
+ "982": [0, 0.44444, 0.03194, 0],
1139
+ "1009": [0.19444, 0.44444, 0, 0],
1140
+ "1013": [0, 0.44444, 0, 0],
1141
+ },
1142
+ "Math-Italic": {
1143
+ "47": [0.19444, 0.69444, 0, 0],
1144
+ "65": [0, 0.68333, 0, 0.13889],
1145
+ "66": [0, 0.68333, 0.05017, 0.08334],
1146
+ "67": [0, 0.68333, 0.07153, 0.08334],
1147
+ "68": [0, 0.68333, 0.02778, 0.05556],
1148
+ "69": [0, 0.68333, 0.05764, 0.08334],
1149
+ "70": [0, 0.68333, 0.13889, 0.08334],
1150
+ "71": [0, 0.68333, 0, 0.08334],
1151
+ "72": [0, 0.68333, 0.08125, 0.05556],
1152
+ "73": [0, 0.68333, 0.07847, 0.11111],
1153
+ "74": [0, 0.68333, 0.09618, 0.16667],
1154
+ "75": [0, 0.68333, 0.07153, 0.05556],
1155
+ "76": [0, 0.68333, 0, 0.02778],
1156
+ "77": [0, 0.68333, 0.10903, 0.08334],
1157
+ "78": [0, 0.68333, 0.10903, 0.08334],
1158
+ "79": [0, 0.68333, 0.02778, 0.08334],
1159
+ "80": [0, 0.68333, 0.13889, 0.08334],
1160
+ "81": [0.19444, 0.68333, 0, 0.08334],
1161
+ "82": [0, 0.68333, 0.00773, 0.08334],
1162
+ "83": [0, 0.68333, 0.05764, 0.08334],
1163
+ "84": [0, 0.68333, 0.13889, 0.08334],
1164
+ "85": [0, 0.68333, 0.10903, 0.02778],
1165
+ "86": [0, 0.68333, 0.22222, 0],
1166
+ "87": [0, 0.68333, 0.13889, 0],
1167
+ "88": [0, 0.68333, 0.07847, 0.08334],
1168
+ "89": [0, 0.68333, 0.22222, 0],
1169
+ "90": [0, 0.68333, 0.07153, 0.08334],
1170
+ "97": [0, 0.43056, 0, 0],
1171
+ "98": [0, 0.69444, 0, 0],
1172
+ "99": [0, 0.43056, 0, 0.05556],
1173
+ "100": [0, 0.69444, 0, 0.16667],
1174
+ "101": [0, 0.43056, 0, 0.05556],
1175
+ "102": [0.19444, 0.69444, 0.10764, 0.16667],
1176
+ "103": [0.19444, 0.43056, 0.03588, 0.02778],
1177
+ "104": [0, 0.69444, 0, 0],
1178
+ "105": [0, 0.65952, 0, 0],
1179
+ "106": [0.19444, 0.65952, 0.05724, 0],
1180
+ "107": [0, 0.69444, 0.03148, 0],
1181
+ "108": [0, 0.69444, 0.01968, 0.08334],
1182
+ "109": [0, 0.43056, 0, 0],
1183
+ "110": [0, 0.43056, 0, 0],
1184
+ "111": [0, 0.43056, 0, 0.05556],
1185
+ "112": [0.19444, 0.43056, 0, 0.08334],
1186
+ "113": [0.19444, 0.43056, 0.03588, 0.08334],
1187
+ "114": [0, 0.43056, 0.02778, 0.05556],
1188
+ "115": [0, 0.43056, 0, 0.05556],
1189
+ "116": [0, 0.61508, 0, 0.08334],
1190
+ "117": [0, 0.43056, 0, 0.02778],
1191
+ "118": [0, 0.43056, 0.03588, 0.02778],
1192
+ "119": [0, 0.43056, 0.02691, 0.08334],
1193
+ "120": [0, 0.43056, 0, 0.02778],
1194
+ "121": [0.19444, 0.43056, 0.03588, 0.05556],
1195
+ "122": [0, 0.43056, 0.04398, 0.05556],
1196
+ "915": [0, 0.68333, 0.13889, 0.08334],
1197
+ "916": [0, 0.68333, 0, 0.16667],
1198
+ "920": [0, 0.68333, 0.02778, 0.08334],
1199
+ "923": [0, 0.68333, 0, 0.16667],
1200
+ "926": [0, 0.68333, 0.07569, 0.08334],
1201
+ "928": [0, 0.68333, 0.08125, 0.05556],
1202
+ "931": [0, 0.68333, 0.05764, 0.08334],
1203
+ "933": [0, 0.68333, 0.13889, 0.05556],
1204
+ "934": [0, 0.68333, 0, 0.08334],
1205
+ "936": [0, 0.68333, 0.11, 0.05556],
1206
+ "937": [0, 0.68333, 0.05017, 0.08334],
1207
+ "945": [0, 0.43056, 0.0037, 0.02778],
1208
+ "946": [0.19444, 0.69444, 0.05278, 0.08334],
1209
+ "947": [0.19444, 0.43056, 0.05556, 0],
1210
+ "948": [0, 0.69444, 0.03785, 0.05556],
1211
+ "949": [0, 0.43056, 0, 0.08334],
1212
+ "950": [0.19444, 0.69444, 0.07378, 0.08334],
1213
+ "951": [0.19444, 0.43056, 0.03588, 0.05556],
1214
+ "952": [0, 0.69444, 0.02778, 0.08334],
1215
+ "953": [0, 0.43056, 0, 0.05556],
1216
+ "954": [0, 0.43056, 0, 0],
1217
+ "955": [0, 0.69444, 0, 0],
1218
+ "956": [0.19444, 0.43056, 0, 0.02778],
1219
+ "957": [0, 0.43056, 0.06366, 0.02778],
1220
+ "958": [0.19444, 0.69444, 0.04601, 0.11111],
1221
+ "959": [0, 0.43056, 0, 0.05556],
1222
+ "960": [0, 0.43056, 0.03588, 0],
1223
+ "961": [0.19444, 0.43056, 0, 0.08334],
1224
+ "962": [0.09722, 0.43056, 0.07986, 0.08334],
1225
+ "963": [0, 0.43056, 0.03588, 0],
1226
+ "964": [0, 0.43056, 0.1132, 0.02778],
1227
+ "965": [0, 0.43056, 0.03588, 0.02778],
1228
+ "966": [0.19444, 0.43056, 0, 0.08334],
1229
+ "967": [0.19444, 0.43056, 0, 0.05556],
1230
+ "968": [0.19444, 0.69444, 0.03588, 0.11111],
1231
+ "969": [0, 0.43056, 0.03588, 0],
1232
+ "977": [0, 0.69444, 0, 0.08334],
1233
+ "981": [0.19444, 0.69444, 0, 0.08334],
1234
+ "982": [0, 0.43056, 0.02778, 0],
1235
+ "1009": [0.19444, 0.43056, 0, 0.08334],
1236
+ "1013": [0, 0.43056, 0, 0.05556],
1237
+ },
1238
+ "Math-Regular": {
1239
+ "65": [0, 0.68333, 0, 0.13889],
1240
+ "66": [0, 0.68333, 0.05017, 0.08334],
1241
+ "67": [0, 0.68333, 0.07153, 0.08334],
1242
+ "68": [0, 0.68333, 0.02778, 0.05556],
1243
+ "69": [0, 0.68333, 0.05764, 0.08334],
1244
+ "70": [0, 0.68333, 0.13889, 0.08334],
1245
+ "71": [0, 0.68333, 0, 0.08334],
1246
+ "72": [0, 0.68333, 0.08125, 0.05556],
1247
+ "73": [0, 0.68333, 0.07847, 0.11111],
1248
+ "74": [0, 0.68333, 0.09618, 0.16667],
1249
+ "75": [0, 0.68333, 0.07153, 0.05556],
1250
+ "76": [0, 0.68333, 0, 0.02778],
1251
+ "77": [0, 0.68333, 0.10903, 0.08334],
1252
+ "78": [0, 0.68333, 0.10903, 0.08334],
1253
+ "79": [0, 0.68333, 0.02778, 0.08334],
1254
+ "80": [0, 0.68333, 0.13889, 0.08334],
1255
+ "81": [0.19444, 0.68333, 0, 0.08334],
1256
+ "82": [0, 0.68333, 0.00773, 0.08334],
1257
+ "83": [0, 0.68333, 0.05764, 0.08334],
1258
+ "84": [0, 0.68333, 0.13889, 0.08334],
1259
+ "85": [0, 0.68333, 0.10903, 0.02778],
1260
+ "86": [0, 0.68333, 0.22222, 0],
1261
+ "87": [0, 0.68333, 0.13889, 0],
1262
+ "88": [0, 0.68333, 0.07847, 0.08334],
1263
+ "89": [0, 0.68333, 0.22222, 0],
1264
+ "90": [0, 0.68333, 0.07153, 0.08334],
1265
+ "97": [0, 0.43056, 0, 0],
1266
+ "98": [0, 0.69444, 0, 0],
1267
+ "99": [0, 0.43056, 0, 0.05556],
1268
+ "100": [0, 0.69444, 0, 0.16667],
1269
+ "101": [0, 0.43056, 0, 0.05556],
1270
+ "102": [0.19444, 0.69444, 0.10764, 0.16667],
1271
+ "103": [0.19444, 0.43056, 0.03588, 0.02778],
1272
+ "104": [0, 0.69444, 0, 0],
1273
+ "105": [0, 0.65952, 0, 0],
1274
+ "106": [0.19444, 0.65952, 0.05724, 0],
1275
+ "107": [0, 0.69444, 0.03148, 0],
1276
+ "108": [0, 0.69444, 0.01968, 0.08334],
1277
+ "109": [0, 0.43056, 0, 0],
1278
+ "110": [0, 0.43056, 0, 0],
1279
+ "111": [0, 0.43056, 0, 0.05556],
1280
+ "112": [0.19444, 0.43056, 0, 0.08334],
1281
+ "113": [0.19444, 0.43056, 0.03588, 0.08334],
1282
+ "114": [0, 0.43056, 0.02778, 0.05556],
1283
+ "115": [0, 0.43056, 0, 0.05556],
1284
+ "116": [0, 0.61508, 0, 0.08334],
1285
+ "117": [0, 0.43056, 0, 0.02778],
1286
+ "118": [0, 0.43056, 0.03588, 0.02778],
1287
+ "119": [0, 0.43056, 0.02691, 0.08334],
1288
+ "120": [0, 0.43056, 0, 0.02778],
1289
+ "121": [0.19444, 0.43056, 0.03588, 0.05556],
1290
+ "122": [0, 0.43056, 0.04398, 0.05556],
1291
+ "915": [0, 0.68333, 0.13889, 0.08334],
1292
+ "916": [0, 0.68333, 0, 0.16667],
1293
+ "920": [0, 0.68333, 0.02778, 0.08334],
1294
+ "923": [0, 0.68333, 0, 0.16667],
1295
+ "926": [0, 0.68333, 0.07569, 0.08334],
1296
+ "928": [0, 0.68333, 0.08125, 0.05556],
1297
+ "931": [0, 0.68333, 0.05764, 0.08334],
1298
+ "933": [0, 0.68333, 0.13889, 0.05556],
1299
+ "934": [0, 0.68333, 0, 0.08334],
1300
+ "936": [0, 0.68333, 0.11, 0.05556],
1301
+ "937": [0, 0.68333, 0.05017, 0.08334],
1302
+ "945": [0, 0.43056, 0.0037, 0.02778],
1303
+ "946": [0.19444, 0.69444, 0.05278, 0.08334],
1304
+ "947": [0.19444, 0.43056, 0.05556, 0],
1305
+ "948": [0, 0.69444, 0.03785, 0.05556],
1306
+ "949": [0, 0.43056, 0, 0.08334],
1307
+ "950": [0.19444, 0.69444, 0.07378, 0.08334],
1308
+ "951": [0.19444, 0.43056, 0.03588, 0.05556],
1309
+ "952": [0, 0.69444, 0.02778, 0.08334],
1310
+ "953": [0, 0.43056, 0, 0.05556],
1311
+ "954": [0, 0.43056, 0, 0],
1312
+ "955": [0, 0.69444, 0, 0],
1313
+ "956": [0.19444, 0.43056, 0, 0.02778],
1314
+ "957": [0, 0.43056, 0.06366, 0.02778],
1315
+ "958": [0.19444, 0.69444, 0.04601, 0.11111],
1316
+ "959": [0, 0.43056, 0, 0.05556],
1317
+ "960": [0, 0.43056, 0.03588, 0],
1318
+ "961": [0.19444, 0.43056, 0, 0.08334],
1319
+ "962": [0.09722, 0.43056, 0.07986, 0.08334],
1320
+ "963": [0, 0.43056, 0.03588, 0],
1321
+ "964": [0, 0.43056, 0.1132, 0.02778],
1322
+ "965": [0, 0.43056, 0.03588, 0.02778],
1323
+ "966": [0.19444, 0.43056, 0, 0.08334],
1324
+ "967": [0.19444, 0.43056, 0, 0.05556],
1325
+ "968": [0.19444, 0.69444, 0.03588, 0.11111],
1326
+ "969": [0, 0.43056, 0.03588, 0],
1327
+ "977": [0, 0.69444, 0, 0.08334],
1328
+ "981": [0.19444, 0.69444, 0, 0.08334],
1329
+ "982": [0, 0.43056, 0.02778, 0],
1330
+ "1009": [0.19444, 0.43056, 0, 0.08334],
1331
+ "1013": [0, 0.43056, 0, 0.05556],
1332
+ },
1333
+ "SansSerif-Regular": {
1334
+ "33": [0, 0.69444, 0, 0],
1335
+ "34": [0, 0.69444, 0, 0],
1336
+ "35": [0.19444, 0.69444, 0, 0],
1337
+ "36": [0.05556, 0.75, 0, 0],
1338
+ "37": [0.05556, 0.75, 0, 0],
1339
+ "38": [0, 0.69444, 0, 0],
1340
+ "39": [0, 0.69444, 0, 0],
1341
+ "40": [0.25, 0.75, 0, 0],
1342
+ "41": [0.25, 0.75, 0, 0],
1343
+ "42": [0, 0.75, 0, 0],
1344
+ "43": [0.08333, 0.58333, 0, 0],
1345
+ "44": [0.125, 0.08333, 0, 0],
1346
+ "45": [0, 0.44444, 0, 0],
1347
+ "46": [0, 0.08333, 0, 0],
1348
+ "47": [0.25, 0.75, 0, 0],
1349
+ "48": [0, 0.65556, 0, 0],
1350
+ "49": [0, 0.65556, 0, 0],
1351
+ "50": [0, 0.65556, 0, 0],
1352
+ "51": [0, 0.65556, 0, 0],
1353
+ "52": [0, 0.65556, 0, 0],
1354
+ "53": [0, 0.65556, 0, 0],
1355
+ "54": [0, 0.65556, 0, 0],
1356
+ "55": [0, 0.65556, 0, 0],
1357
+ "56": [0, 0.65556, 0, 0],
1358
+ "57": [0, 0.65556, 0, 0],
1359
+ "58": [0, 0.44444, 0, 0],
1360
+ "59": [0.125, 0.44444, 0, 0],
1361
+ "61": [-0.13, 0.37, 0, 0],
1362
+ "63": [0, 0.69444, 0, 0],
1363
+ "64": [0, 0.69444, 0, 0],
1364
+ "65": [0, 0.69444, 0, 0],
1365
+ "66": [0, 0.69444, 0, 0],
1366
+ "67": [0, 0.69444, 0, 0],
1367
+ "68": [0, 0.69444, 0, 0],
1368
+ "69": [0, 0.69444, 0, 0],
1369
+ "70": [0, 0.69444, 0, 0],
1370
+ "71": [0, 0.69444, 0, 0],
1371
+ "72": [0, 0.69444, 0, 0],
1372
+ "73": [0, 0.69444, 0, 0],
1373
+ "74": [0, 0.69444, 0, 0],
1374
+ "75": [0, 0.69444, 0, 0],
1375
+ "76": [0, 0.69444, 0, 0],
1376
+ "77": [0, 0.69444, 0, 0],
1377
+ "78": [0, 0.69444, 0, 0],
1378
+ "79": [0, 0.69444, 0, 0],
1379
+ "80": [0, 0.69444, 0, 0],
1380
+ "81": [0.125, 0.69444, 0, 0],
1381
+ "82": [0, 0.69444, 0, 0],
1382
+ "83": [0, 0.69444, 0, 0],
1383
+ "84": [0, 0.69444, 0, 0],
1384
+ "85": [0, 0.69444, 0, 0],
1385
+ "86": [0, 0.69444, 0.01389, 0],
1386
+ "87": [0, 0.69444, 0.01389, 0],
1387
+ "88": [0, 0.69444, 0, 0],
1388
+ "89": [0, 0.69444, 0.025, 0],
1389
+ "90": [0, 0.69444, 0, 0],
1390
+ "91": [0.25, 0.75, 0, 0],
1391
+ "93": [0.25, 0.75, 0, 0],
1392
+ "94": [0, 0.69444, 0, 0],
1393
+ "95": [0.35, 0.09444, 0.02778, 0],
1394
+ "97": [0, 0.44444, 0, 0],
1395
+ "98": [0, 0.69444, 0, 0],
1396
+ "99": [0, 0.44444, 0, 0],
1397
+ "100": [0, 0.69444, 0, 0],
1398
+ "101": [0, 0.44444, 0, 0],
1399
+ "102": [0, 0.69444, 0.06944, 0],
1400
+ "103": [0.19444, 0.44444, 0.01389, 0],
1401
+ "104": [0, 0.69444, 0, 0],
1402
+ "105": [0, 0.67937, 0, 0],
1403
+ "106": [0.19444, 0.67937, 0, 0],
1404
+ "107": [0, 0.69444, 0, 0],
1405
+ "108": [0, 0.69444, 0, 0],
1406
+ "109": [0, 0.44444, 0, 0],
1407
+ "110": [0, 0.44444, 0, 0],
1408
+ "111": [0, 0.44444, 0, 0],
1409
+ "112": [0.19444, 0.44444, 0, 0],
1410
+ "113": [0.19444, 0.44444, 0, 0],
1411
+ "114": [0, 0.44444, 0.01389, 0],
1412
+ "115": [0, 0.44444, 0, 0],
1413
+ "116": [0, 0.57143, 0, 0],
1414
+ "117": [0, 0.44444, 0, 0],
1415
+ "118": [0, 0.44444, 0.01389, 0],
1416
+ "119": [0, 0.44444, 0.01389, 0],
1417
+ "120": [0, 0.44444, 0, 0],
1418
+ "121": [0.19444, 0.44444, 0.01389, 0],
1419
+ "122": [0, 0.44444, 0, 0],
1420
+ "126": [0.35, 0.32659, 0, 0],
1421
+ "305": [0, 0.44444, 0, 0],
1422
+ "567": [0.19444, 0.44444, 0, 0],
1423
+ "768": [0, 0.69444, 0, 0],
1424
+ "769": [0, 0.69444, 0, 0],
1425
+ "770": [0, 0.69444, 0, 0],
1426
+ "771": [0, 0.67659, 0, 0],
1427
+ "772": [0, 0.60889, 0, 0],
1428
+ "774": [0, 0.69444, 0, 0],
1429
+ "775": [0, 0.67937, 0, 0],
1430
+ "776": [0, 0.67937, 0, 0],
1431
+ "778": [0, 0.69444, 0, 0],
1432
+ "779": [0, 0.69444, 0, 0],
1433
+ "780": [0, 0.63194, 0, 0],
1434
+ "915": [0, 0.69444, 0, 0],
1435
+ "916": [0, 0.69444, 0, 0],
1436
+ "920": [0, 0.69444, 0, 0],
1437
+ "923": [0, 0.69444, 0, 0],
1438
+ "926": [0, 0.69444, 0, 0],
1439
+ "928": [0, 0.69444, 0, 0],
1440
+ "931": [0, 0.69444, 0, 0],
1441
+ "933": [0, 0.69444, 0, 0],
1442
+ "934": [0, 0.69444, 0, 0],
1443
+ "936": [0, 0.69444, 0, 0],
1444
+ "937": [0, 0.69444, 0, 0],
1445
+ "8211": [0, 0.44444, 0.02778, 0],
1446
+ "8212": [0, 0.44444, 0.02778, 0],
1447
+ "8216": [0, 0.69444, 0, 0],
1448
+ "8217": [0, 0.69444, 0, 0],
1449
+ "8220": [0, 0.69444, 0, 0],
1450
+ "8221": [0, 0.69444, 0, 0],
1451
+ },
1452
+ "Script-Regular": {
1453
+ "65": [0, 0.7, 0.22925, 0],
1454
+ "66": [0, 0.7, 0.04087, 0],
1455
+ "67": [0, 0.7, 0.1689, 0],
1456
+ "68": [0, 0.7, 0.09371, 0],
1457
+ "69": [0, 0.7, 0.18583, 0],
1458
+ "70": [0, 0.7, 0.13634, 0],
1459
+ "71": [0, 0.7, 0.17322, 0],
1460
+ "72": [0, 0.7, 0.29694, 0],
1461
+ "73": [0, 0.7, 0.19189, 0],
1462
+ "74": [0.27778, 0.7, 0.19189, 0],
1463
+ "75": [0, 0.7, 0.31259, 0],
1464
+ "76": [0, 0.7, 0.19189, 0],
1465
+ "77": [0, 0.7, 0.15981, 0],
1466
+ "78": [0, 0.7, 0.3525, 0],
1467
+ "79": [0, 0.7, 0.08078, 0],
1468
+ "80": [0, 0.7, 0.08078, 0],
1469
+ "81": [0, 0.7, 0.03305, 0],
1470
+ "82": [0, 0.7, 0.06259, 0],
1471
+ "83": [0, 0.7, 0.19189, 0],
1472
+ "84": [0, 0.7, 0.29087, 0],
1473
+ "85": [0, 0.7, 0.25815, 0],
1474
+ "86": [0, 0.7, 0.27523, 0],
1475
+ "87": [0, 0.7, 0.27523, 0],
1476
+ "88": [0, 0.7, 0.26006, 0],
1477
+ "89": [0, 0.7, 0.2939, 0],
1478
+ "90": [0, 0.7, 0.24037, 0],
1479
+ },
1480
+ "Size1-Regular": {
1481
+ "40": [0.35001, 0.85, 0, 0],
1482
+ "41": [0.35001, 0.85, 0, 0],
1483
+ "47": [0.35001, 0.85, 0, 0],
1484
+ "91": [0.35001, 0.85, 0, 0],
1485
+ "92": [0.35001, 0.85, 0, 0],
1486
+ "93": [0.35001, 0.85, 0, 0],
1487
+ "123": [0.35001, 0.85, 0, 0],
1488
+ "125": [0.35001, 0.85, 0, 0],
1489
+ "710": [0, 0.72222, 0, 0],
1490
+ "732": [0, 0.72222, 0, 0],
1491
+ "770": [0, 0.72222, 0, 0],
1492
+ "771": [0, 0.72222, 0, 0],
1493
+ "8214": [-0.00099, 0.601, 0, 0],
1494
+ "8593": [1e-05, 0.6, 0, 0],
1495
+ "8595": [1e-05, 0.6, 0, 0],
1496
+ "8657": [1e-05, 0.6, 0, 0],
1497
+ "8659": [1e-05, 0.6, 0, 0],
1498
+ "8719": [0.25001, 0.75, 0, 0],
1499
+ "8720": [0.25001, 0.75, 0, 0],
1500
+ "8721": [0.25001, 0.75, 0, 0],
1501
+ "8730": [0.35001, 0.85, 0, 0],
1502
+ "8739": [-0.00599, 0.606, 0, 0],
1503
+ "8741": [-0.00599, 0.606, 0, 0],
1504
+ "8747": [0.30612, 0.805, 0.19445, 0],
1505
+ "8748": [0.306, 0.805, 0.19445, 0],
1506
+ "8749": [0.306, 0.805, 0.19445, 0],
1507
+ "8750": [0.30612, 0.805, 0.19445, 0],
1508
+ "8896": [0.25001, 0.75, 0, 0],
1509
+ "8897": [0.25001, 0.75, 0, 0],
1510
+ "8898": [0.25001, 0.75, 0, 0],
1511
+ "8899": [0.25001, 0.75, 0, 0],
1512
+ "8968": [0.35001, 0.85, 0, 0],
1513
+ "8969": [0.35001, 0.85, 0, 0],
1514
+ "8970": [0.35001, 0.85, 0, 0],
1515
+ "8971": [0.35001, 0.85, 0, 0],
1516
+ "9168": [-0.00099, 0.601, 0, 0],
1517
+ "10216": [0.35001, 0.85, 0, 0],
1518
+ "10217": [0.35001, 0.85, 0, 0],
1519
+ "10752": [0.25001, 0.75, 0, 0],
1520
+ "10753": [0.25001, 0.75, 0, 0],
1521
+ "10754": [0.25001, 0.75, 0, 0],
1522
+ "10756": [0.25001, 0.75, 0, 0],
1523
+ "10758": [0.25001, 0.75, 0, 0],
1524
+ },
1525
+ "Size2-Regular": {
1526
+ "40": [0.65002, 1.15, 0, 0],
1527
+ "41": [0.65002, 1.15, 0, 0],
1528
+ "47": [0.65002, 1.15, 0, 0],
1529
+ "91": [0.65002, 1.15, 0, 0],
1530
+ "92": [0.65002, 1.15, 0, 0],
1531
+ "93": [0.65002, 1.15, 0, 0],
1532
+ "123": [0.65002, 1.15, 0, 0],
1533
+ "125": [0.65002, 1.15, 0, 0],
1534
+ "710": [0, 0.75, 0, 0],
1535
+ "732": [0, 0.75, 0, 0],
1536
+ "770": [0, 0.75, 0, 0],
1537
+ "771": [0, 0.75, 0, 0],
1538
+ "8719": [0.55001, 1.05, 0, 0],
1539
+ "8720": [0.55001, 1.05, 0, 0],
1540
+ "8721": [0.55001, 1.05, 0, 0],
1541
+ "8730": [0.65002, 1.15, 0, 0],
1542
+ "8747": [0.86225, 1.36, 0.44445, 0],
1543
+ "8748": [0.862, 1.36, 0.44445, 0],
1544
+ "8749": [0.862, 1.36, 0.44445, 0],
1545
+ "8750": [0.86225, 1.36, 0.44445, 0],
1546
+ "8896": [0.55001, 1.05, 0, 0],
1547
+ "8897": [0.55001, 1.05, 0, 0],
1548
+ "8898": [0.55001, 1.05, 0, 0],
1549
+ "8899": [0.55001, 1.05, 0, 0],
1550
+ "8968": [0.65002, 1.15, 0, 0],
1551
+ "8969": [0.65002, 1.15, 0, 0],
1552
+ "8970": [0.65002, 1.15, 0, 0],
1553
+ "8971": [0.65002, 1.15, 0, 0],
1554
+ "10216": [0.65002, 1.15, 0, 0],
1555
+ "10217": [0.65002, 1.15, 0, 0],
1556
+ "10752": [0.55001, 1.05, 0, 0],
1557
+ "10753": [0.55001, 1.05, 0, 0],
1558
+ "10754": [0.55001, 1.05, 0, 0],
1559
+ "10756": [0.55001, 1.05, 0, 0],
1560
+ "10758": [0.55001, 1.05, 0, 0],
1561
+ },
1562
+ "Size3-Regular": {
1563
+ "40": [0.95003, 1.45, 0, 0],
1564
+ "41": [0.95003, 1.45, 0, 0],
1565
+ "47": [0.95003, 1.45, 0, 0],
1566
+ "91": [0.95003, 1.45, 0, 0],
1567
+ "92": [0.95003, 1.45, 0, 0],
1568
+ "93": [0.95003, 1.45, 0, 0],
1569
+ "123": [0.95003, 1.45, 0, 0],
1570
+ "125": [0.95003, 1.45, 0, 0],
1571
+ "710": [0, 0.75, 0, 0],
1572
+ "732": [0, 0.75, 0, 0],
1573
+ "770": [0, 0.75, 0, 0],
1574
+ "771": [0, 0.75, 0, 0],
1575
+ "8730": [0.95003, 1.45, 0, 0],
1576
+ "8968": [0.95003, 1.45, 0, 0],
1577
+ "8969": [0.95003, 1.45, 0, 0],
1578
+ "8970": [0.95003, 1.45, 0, 0],
1579
+ "8971": [0.95003, 1.45, 0, 0],
1580
+ "10216": [0.95003, 1.45, 0, 0],
1581
+ "10217": [0.95003, 1.45, 0, 0],
1582
+ },
1583
+ "Size4-Regular": {
1584
+ "40": [1.25003, 1.75, 0, 0],
1585
+ "41": [1.25003, 1.75, 0, 0],
1586
+ "47": [1.25003, 1.75, 0, 0],
1587
+ "91": [1.25003, 1.75, 0, 0],
1588
+ "92": [1.25003, 1.75, 0, 0],
1589
+ "93": [1.25003, 1.75, 0, 0],
1590
+ "123": [1.25003, 1.75, 0, 0],
1591
+ "125": [1.25003, 1.75, 0, 0],
1592
+ "710": [0, 0.825, 0, 0],
1593
+ "732": [0, 0.825, 0, 0],
1594
+ "770": [0, 0.825, 0, 0],
1595
+ "771": [0, 0.825, 0, 0],
1596
+ "8730": [1.25003, 1.75, 0, 0],
1597
+ "8968": [1.25003, 1.75, 0, 0],
1598
+ "8969": [1.25003, 1.75, 0, 0],
1599
+ "8970": [1.25003, 1.75, 0, 0],
1600
+ "8971": [1.25003, 1.75, 0, 0],
1601
+ "9115": [0.64502, 1.155, 0, 0],
1602
+ "9116": [1e-05, 0.6, 0, 0],
1603
+ "9117": [0.64502, 1.155, 0, 0],
1604
+ "9118": [0.64502, 1.155, 0, 0],
1605
+ "9119": [1e-05, 0.6, 0, 0],
1606
+ "9120": [0.64502, 1.155, 0, 0],
1607
+ "9121": [0.64502, 1.155, 0, 0],
1608
+ "9122": [-0.00099, 0.601, 0, 0],
1609
+ "9123": [0.64502, 1.155, 0, 0],
1610
+ "9124": [0.64502, 1.155, 0, 0],
1611
+ "9125": [-0.00099, 0.601, 0, 0],
1612
+ "9126": [0.64502, 1.155, 0, 0],
1613
+ "9127": [1e-05, 0.9, 0, 0],
1614
+ "9128": [0.65002, 1.15, 0, 0],
1615
+ "9129": [0.90001, 0, 0, 0],
1616
+ "9130": [0, 0.3, 0, 0],
1617
+ "9131": [1e-05, 0.9, 0, 0],
1618
+ "9132": [0.65002, 1.15, 0, 0],
1619
+ "9133": [0.90001, 0, 0, 0],
1620
+ "9143": [0.88502, 0.915, 0, 0],
1621
+ "10216": [1.25003, 1.75, 0, 0],
1622
+ "10217": [1.25003, 1.75, 0, 0],
1623
+ "57344": [-0.00499, 0.605, 0, 0],
1624
+ "57345": [-0.00499, 0.605, 0, 0],
1625
+ "57680": [0, 0.12, 0, 0],
1626
+ "57681": [0, 0.12, 0, 0],
1627
+ "57682": [0, 0.12, 0, 0],
1628
+ "57683": [0, 0.12, 0, 0],
1629
+ },
1630
+ "Typewriter-Regular": {
1631
+ "33": [0, 0.61111, 0, 0],
1632
+ "34": [0, 0.61111, 0, 0],
1633
+ "35": [0, 0.61111, 0, 0],
1634
+ "36": [0.08333, 0.69444, 0, 0],
1635
+ "37": [0.08333, 0.69444, 0, 0],
1636
+ "38": [0, 0.61111, 0, 0],
1637
+ "39": [0, 0.61111, 0, 0],
1638
+ "40": [0.08333, 0.69444, 0, 0],
1639
+ "41": [0.08333, 0.69444, 0, 0],
1640
+ "42": [0, 0.52083, 0, 0],
1641
+ "43": [-0.08056, 0.53055, 0, 0],
1642
+ "44": [0.13889, 0.125, 0, 0],
1643
+ "45": [-0.08056, 0.53055, 0, 0],
1644
+ "46": [0, 0.125, 0, 0],
1645
+ "47": [0.08333, 0.69444, 0, 0],
1646
+ "48": [0, 0.61111, 0, 0],
1647
+ "49": [0, 0.61111, 0, 0],
1648
+ "50": [0, 0.61111, 0, 0],
1649
+ "51": [0, 0.61111, 0, 0],
1650
+ "52": [0, 0.61111, 0, 0],
1651
+ "53": [0, 0.61111, 0, 0],
1652
+ "54": [0, 0.61111, 0, 0],
1653
+ "55": [0, 0.61111, 0, 0],
1654
+ "56": [0, 0.61111, 0, 0],
1655
+ "57": [0, 0.61111, 0, 0],
1656
+ "58": [0, 0.43056, 0, 0],
1657
+ "59": [0.13889, 0.43056, 0, 0],
1658
+ "60": [-0.05556, 0.55556, 0, 0],
1659
+ "61": [-0.19549, 0.41562, 0, 0],
1660
+ "62": [-0.05556, 0.55556, 0, 0],
1661
+ "63": [0, 0.61111, 0, 0],
1662
+ "64": [0, 0.61111, 0, 0],
1663
+ "65": [0, 0.61111, 0, 0],
1664
+ "66": [0, 0.61111, 0, 0],
1665
+ "67": [0, 0.61111, 0, 0],
1666
+ "68": [0, 0.61111, 0, 0],
1667
+ "69": [0, 0.61111, 0, 0],
1668
+ "70": [0, 0.61111, 0, 0],
1669
+ "71": [0, 0.61111, 0, 0],
1670
+ "72": [0, 0.61111, 0, 0],
1671
+ "73": [0, 0.61111, 0, 0],
1672
+ "74": [0, 0.61111, 0, 0],
1673
+ "75": [0, 0.61111, 0, 0],
1674
+ "76": [0, 0.61111, 0, 0],
1675
+ "77": [0, 0.61111, 0, 0],
1676
+ "78": [0, 0.61111, 0, 0],
1677
+ "79": [0, 0.61111, 0, 0],
1678
+ "80": [0, 0.61111, 0, 0],
1679
+ "81": [0.13889, 0.61111, 0, 0],
1680
+ "82": [0, 0.61111, 0, 0],
1681
+ "83": [0, 0.61111, 0, 0],
1682
+ "84": [0, 0.61111, 0, 0],
1683
+ "85": [0, 0.61111, 0, 0],
1684
+ "86": [0, 0.61111, 0, 0],
1685
+ "87": [0, 0.61111, 0, 0],
1686
+ "88": [0, 0.61111, 0, 0],
1687
+ "89": [0, 0.61111, 0, 0],
1688
+ "90": [0, 0.61111, 0, 0],
1689
+ "91": [0.08333, 0.69444, 0, 0],
1690
+ "92": [0.08333, 0.69444, 0, 0],
1691
+ "93": [0.08333, 0.69444, 0, 0],
1692
+ "94": [0, 0.61111, 0, 0],
1693
+ "95": [0.09514, 0, 0, 0],
1694
+ "96": [0, 0.61111, 0, 0],
1695
+ "97": [0, 0.43056, 0, 0],
1696
+ "98": [0, 0.61111, 0, 0],
1697
+ "99": [0, 0.43056, 0, 0],
1698
+ "100": [0, 0.61111, 0, 0],
1699
+ "101": [0, 0.43056, 0, 0],
1700
+ "102": [0, 0.61111, 0, 0],
1701
+ "103": [0.22222, 0.43056, 0, 0],
1702
+ "104": [0, 0.61111, 0, 0],
1703
+ "105": [0, 0.61111, 0, 0],
1704
+ "106": [0.22222, 0.61111, 0, 0],
1705
+ "107": [0, 0.61111, 0, 0],
1706
+ "108": [0, 0.61111, 0, 0],
1707
+ "109": [0, 0.43056, 0, 0],
1708
+ "110": [0, 0.43056, 0, 0],
1709
+ "111": [0, 0.43056, 0, 0],
1710
+ "112": [0.22222, 0.43056, 0, 0],
1711
+ "113": [0.22222, 0.43056, 0, 0],
1712
+ "114": [0, 0.43056, 0, 0],
1713
+ "115": [0, 0.43056, 0, 0],
1714
+ "116": [0, 0.55358, 0, 0],
1715
+ "117": [0, 0.43056, 0, 0],
1716
+ "118": [0, 0.43056, 0, 0],
1717
+ "119": [0, 0.43056, 0, 0],
1718
+ "120": [0, 0.43056, 0, 0],
1719
+ "121": [0.22222, 0.43056, 0, 0],
1720
+ "122": [0, 0.43056, 0, 0],
1721
+ "123": [0.08333, 0.69444, 0, 0],
1722
+ "124": [0.08333, 0.69444, 0, 0],
1723
+ "125": [0.08333, 0.69444, 0, 0],
1724
+ "126": [0, 0.61111, 0, 0],
1725
+ "127": [0, 0.61111, 0, 0],
1726
+ "305": [0, 0.43056, 0, 0],
1727
+ "567": [0.22222, 0.43056, 0, 0],
1728
+ "768": [0, 0.61111, 0, 0],
1729
+ "769": [0, 0.61111, 0, 0],
1730
+ "770": [0, 0.61111, 0, 0],
1731
+ "771": [0, 0.61111, 0, 0],
1732
+ "772": [0, 0.56555, 0, 0],
1733
+ "774": [0, 0.61111, 0, 0],
1734
+ "776": [0, 0.61111, 0, 0],
1735
+ "778": [0, 0.61111, 0, 0],
1736
+ "780": [0, 0.56597, 0, 0],
1737
+ "915": [0, 0.61111, 0, 0],
1738
+ "916": [0, 0.61111, 0, 0],
1739
+ "920": [0, 0.61111, 0, 0],
1740
+ "923": [0, 0.61111, 0, 0],
1741
+ "926": [0, 0.61111, 0, 0],
1742
+ "928": [0, 0.61111, 0, 0],
1743
+ "931": [0, 0.61111, 0, 0],
1744
+ "933": [0, 0.61111, 0, 0],
1745
+ "934": [0, 0.61111, 0, 0],
1746
+ "936": [0, 0.61111, 0, 0],
1747
+ "937": [0, 0.61111, 0, 0],
1748
+ "2018": [0, 0.61111, 0, 0],
1749
+ "2019": [0, 0.61111, 0, 0],
1750
+ "8242": [0, 0.61111, 0, 0],
1751
+ },
1752
+ };
katex/src/functions.js ADDED
@@ -0,0 +1,585 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var utils = require("./utils");
2
+ var ParseError = require("./ParseError");
3
+
4
+ /* This file contains a list of functions that we parse, identified by
5
+ * the calls to defineFunction.
6
+ *
7
+ * The first argument to defineFunction is a single name or a list of names.
8
+ * All functions named in such a list will share a single implementation.
9
+ *
10
+ * Each declared function can have associated properties, which
11
+ * include the following:
12
+ *
13
+ * - numArgs: The number of arguments the function takes.
14
+ * If this is the only property, it can be passed as a number
15
+ * instead of an element of a properties object.
16
+ * - argTypes: (optional) An array corresponding to each argument of the
17
+ * function, giving the type of argument that should be parsed. Its
18
+ * length should be equal to `numArgs + numOptionalArgs`. Valid
19
+ * types:
20
+ * - "size": A size-like thing, such as "1em" or "5ex"
21
+ * - "color": An html color, like "#abc" or "blue"
22
+ * - "original": The same type as the environment that the
23
+ * function being parsed is in (e.g. used for the
24
+ * bodies of functions like \color where the first
25
+ * argument is special and the second argument is
26
+ * parsed normally)
27
+ * Other possible types (probably shouldn't be used)
28
+ * - "text": Text-like (e.g. \text)
29
+ * - "math": Normal math
30
+ * If undefined, this will be treated as an appropriate length
31
+ * array of "original" strings
32
+ * - greediness: (optional) The greediness of the function to use ungrouped
33
+ * arguments.
34
+ *
35
+ * E.g. if you have an expression
36
+ * \sqrt \frac 1 2
37
+ * since \frac has greediness=2 vs \sqrt's greediness=1, \frac
38
+ * will use the two arguments '1' and '2' as its two arguments,
39
+ * then that whole function will be used as the argument to
40
+ * \sqrt. On the other hand, the expressions
41
+ * \frac \frac 1 2 3
42
+ * and
43
+ * \frac \sqrt 1 2
44
+ * will fail because \frac and \frac have equal greediness
45
+ * and \sqrt has a lower greediness than \frac respectively. To
46
+ * make these parse, we would have to change them to:
47
+ * \frac {\frac 1 2} 3
48
+ * and
49
+ * \frac {\sqrt 1} 2
50
+ *
51
+ * The default value is `1`
52
+ * - allowedInText: (optional) Whether or not the function is allowed inside
53
+ * text mode (default false)
54
+ * - numOptionalArgs: (optional) The number of optional arguments the function
55
+ * should parse. If the optional arguments aren't found,
56
+ * `null` will be passed to the handler in their place.
57
+ * (default 0)
58
+ *
59
+ * The last argument is that implementation, the handler for the function(s).
60
+ * It is called to handle these functions and their arguments.
61
+ * It receives two arguments:
62
+ * - context contains information and references provided by the parser
63
+ * - args is an array of arguments obtained from TeX input
64
+ * The context contains the following properties:
65
+ * - funcName: the text (i.e. name) of the function, including \
66
+ * - parser: the parser object
67
+ * - lexer: the lexer object
68
+ * - positions: the positions in the overall string of the function
69
+ * and the arguments.
70
+ * The latter three should only be used to produce error messages.
71
+ *
72
+ * The function should return an object with the following keys:
73
+ * - type: The type of element that this is. This is then used in
74
+ * buildHTML/buildMathML to determine which function
75
+ * should be called to build this node into a DOM node
76
+ * Any other data can be added to the object, which will be passed
77
+ * in to the function in buildHTML/buildMathML as `group.value`.
78
+ */
79
+
80
+ function defineFunction(names, props, handler) {
81
+ if (typeof names === "string") {
82
+ names = [names];
83
+ }
84
+ if (typeof props === "number") {
85
+ props = { numArgs: props };
86
+ }
87
+ // Set default values of functions
88
+ var data = {
89
+ numArgs: props.numArgs,
90
+ argTypes: props.argTypes,
91
+ greediness: (props.greediness === undefined) ? 1 : props.greediness,
92
+ allowedInText: !!props.allowedInText,
93
+ numOptionalArgs: props.numOptionalArgs || 0,
94
+ handler: handler,
95
+ };
96
+ for (var i = 0; i < names.length; ++i) {
97
+ module.exports[names[i]] = data;
98
+ }
99
+ }
100
+
101
+ // A normal square root
102
+ defineFunction("\\sqrt", {
103
+ numArgs: 1,
104
+ numOptionalArgs: 1,
105
+ }, function(context, args) {
106
+ var index = args[0];
107
+ var body = args[1];
108
+ return {
109
+ type: "sqrt",
110
+ body: body,
111
+ index: index,
112
+ };
113
+ });
114
+
115
+ // Some non-mathy text
116
+ defineFunction(["\\text", "\\mbox", "\\hbox", "\\vbox"], {
117
+ numArgs: 1,
118
+ argTypes: ["text"],
119
+ greediness: 2,
120
+ }, function(context, args) {
121
+ var body = args[0];
122
+ // Since the corresponding buildHTML/buildMathML function expects a
123
+ // list of elements, we normalize for different kinds of arguments
124
+ // TODO(emily): maybe this should be done somewhere else
125
+ var inner;
126
+ if (body.type === "ordgroup") {
127
+ inner = body.value;
128
+ } else {
129
+ inner = [body];
130
+ }
131
+
132
+ return {
133
+ type: "text",
134
+ body: inner,
135
+ };
136
+ });
137
+
138
+ // A two-argument custom color
139
+ defineFunction("\\color", {
140
+ numArgs: 2,
141
+ allowedInText: true,
142
+ greediness: 3,
143
+ argTypes: ["color", "original"],
144
+ }, function(context, args) {
145
+ var color = args[0];
146
+ var body = args[1];
147
+ // Normalize the different kinds of bodies (see \text above)
148
+ var inner;
149
+ if (body.type === "ordgroup") {
150
+ inner = body.value;
151
+ } else {
152
+ inner = [body];
153
+ }
154
+
155
+ return {
156
+ type: "color",
157
+ color: color.value,
158
+ value: inner,
159
+ };
160
+ });
161
+
162
+ // An overline
163
+ defineFunction("\\overline", {
164
+ numArgs: 1,
165
+ }, function(context, args) {
166
+ var body = args[0];
167
+ return {
168
+ type: "overline",
169
+ body: body,
170
+ };
171
+ });
172
+
173
+ // An underline
174
+ defineFunction("\\underline", {
175
+ numArgs: 1,
176
+ }, function(context, args) {
177
+ var body = args[0];
178
+ return {
179
+ type: "underline",
180
+ body: body,
181
+ };
182
+ });
183
+
184
+ // A box of the width and height
185
+ defineFunction("\\rule", {
186
+ numArgs: 2,
187
+ numOptionalArgs: 1,
188
+ argTypes: ["size", "size", "size"],
189
+ }, function(context, args) {
190
+ var shift = args[0];
191
+ var width = args[1];
192
+ var height = args[2];
193
+ return {
194
+ type: "rule",
195
+ shift: shift && shift.value,
196
+ width: width.value,
197
+ height: height.value,
198
+ };
199
+ });
200
+
201
+ // A KaTeX logo
202
+ defineFunction("\\KaTeX", {
203
+ numArgs: 0,
204
+ }, function(context) {
205
+ return {
206
+ type: "katex",
207
+ };
208
+ });
209
+
210
+ defineFunction("\\phantom", {
211
+ numArgs: 1,
212
+ }, function(context, args) {
213
+ var body = args[0];
214
+ var inner;
215
+ if (body.type === "ordgroup") {
216
+ inner = body.value;
217
+ } else {
218
+ inner = [body];
219
+ }
220
+
221
+ return {
222
+ type: "phantom",
223
+ value: inner,
224
+ };
225
+ });
226
+
227
+ // Extra data needed for the delimiter handler down below
228
+ var delimiterSizes = {
229
+ "\\bigl" : {type: "open", size: 1},
230
+ "\\Bigl" : {type: "open", size: 2},
231
+ "\\biggl": {type: "open", size: 3},
232
+ "\\Biggl": {type: "open", size: 4},
233
+ "\\bigr" : {type: "close", size: 1},
234
+ "\\Bigr" : {type: "close", size: 2},
235
+ "\\biggr": {type: "close", size: 3},
236
+ "\\Biggr": {type: "close", size: 4},
237
+ "\\bigm" : {type: "rel", size: 1},
238
+ "\\Bigm" : {type: "rel", size: 2},
239
+ "\\biggm": {type: "rel", size: 3},
240
+ "\\Biggm": {type: "rel", size: 4},
241
+ "\\big" : {type: "textord", size: 1},
242
+ "\\Big" : {type: "textord", size: 2},
243
+ "\\bigg" : {type: "textord", size: 3},
244
+ "\\Bigg" : {type: "textord", size: 4},
245
+ };
246
+
247
+ var delimiters = [
248
+ "(", ")", "[", "\\lbrack", "]", "\\rbrack",
249
+ "\\{", "\\lbrace", "\\}", "\\rbrace",
250
+ "\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
251
+ "<", ">", "\\langle", "\\rangle", "\\lt", "\\gt",
252
+ "\\lvert", "\\rvert", "\\lVert", "\\rVert",
253
+ "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache",
254
+ "/", "\\backslash",
255
+ "|", "\\vert", "\\|", "\\Vert",
256
+ "\\uparrow", "\\Uparrow",
257
+ "\\downarrow", "\\Downarrow",
258
+ "\\updownarrow", "\\Updownarrow",
259
+ ".",
260
+ ];
261
+
262
+ var fontAliases = {
263
+ "\\Bbb": "\\mathbb",
264
+ "\\bold": "\\mathbf",
265
+ "\\frak": "\\mathfrak",
266
+ };
267
+
268
+ // Single-argument color functions
269
+ defineFunction([
270
+ "\\blue", "\\orange", "\\pink", "\\red",
271
+ "\\green", "\\gray", "\\purple",
272
+ "\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
273
+ "\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
274
+ "\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
275
+ "\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
276
+ "\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
277
+ "\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
278
+ "\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
279
+ "\\mintA", "\\mintB", "\\mintC",
280
+ "\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
281
+ "\\grayF", "\\grayG", "\\grayH", "\\grayI",
282
+ "\\kaBlue", "\\kaGreen",
283
+ ], {
284
+ numArgs: 1,
285
+ allowedInText: true,
286
+ greediness: 3,
287
+ }, function(context, args) {
288
+ var body = args[0];
289
+ var atoms;
290
+ if (body.type === "ordgroup") {
291
+ atoms = body.value;
292
+ } else {
293
+ atoms = [body];
294
+ }
295
+
296
+ return {
297
+ type: "color",
298
+ color: "katex-" + context.funcName.slice(1),
299
+ value: atoms,
300
+ };
301
+ });
302
+
303
+ // There are 2 flags for operators; whether they produce limits in
304
+ // displaystyle, and whether they are symbols and should grow in
305
+ // displaystyle. These four groups cover the four possible choices.
306
+
307
+ // No limits, not symbols
308
+ defineFunction([
309
+ "\\arcsin", "\\arccos", "\\arctan", "\\arg", "\\cos", "\\cosh",
310
+ "\\cot", "\\coth", "\\csc", "\\deg", "\\dim", "\\exp", "\\hom",
311
+ "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh",
312
+ "\\tan", "\\tanh",
313
+ ], {
314
+ numArgs: 0,
315
+ }, function(context) {
316
+ return {
317
+ type: "op",
318
+ limits: false,
319
+ symbol: false,
320
+ body: context.funcName,
321
+ };
322
+ });
323
+
324
+ // Limits, not symbols
325
+ defineFunction([
326
+ "\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max",
327
+ "\\min", "\\Pr", "\\sup",
328
+ ], {
329
+ numArgs: 0,
330
+ }, function(context) {
331
+ return {
332
+ type: "op",
333
+ limits: true,
334
+ symbol: false,
335
+ body: context.funcName,
336
+ };
337
+ });
338
+
339
+ // No limits, symbols
340
+ defineFunction([
341
+ "\\int", "\\iint", "\\iiint", "\\oint",
342
+ ], {
343
+ numArgs: 0,
344
+ }, function(context) {
345
+ return {
346
+ type: "op",
347
+ limits: false,
348
+ symbol: true,
349
+ body: context.funcName,
350
+ };
351
+ });
352
+
353
+ // Limits, symbols
354
+ defineFunction([
355
+ "\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap",
356
+ "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes",
357
+ "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint",
358
+ ], {
359
+ numArgs: 0,
360
+ }, function(context) {
361
+ return {
362
+ type: "op",
363
+ limits: true,
364
+ symbol: true,
365
+ body: context.funcName,
366
+ };
367
+ });
368
+
369
+ // Fractions
370
+ defineFunction([
371
+ "\\dfrac", "\\frac", "\\tfrac",
372
+ "\\dbinom", "\\binom", "\\tbinom",
373
+ ], {
374
+ numArgs: 2,
375
+ greediness: 2,
376
+ }, function(context, args) {
377
+ var numer = args[0];
378
+ var denom = args[1];
379
+ var hasBarLine;
380
+ var leftDelim = null;
381
+ var rightDelim = null;
382
+ var size = "auto";
383
+
384
+ switch (context.funcName) {
385
+ case "\\dfrac":
386
+ case "\\frac":
387
+ case "\\tfrac":
388
+ hasBarLine = true;
389
+ break;
390
+ case "\\dbinom":
391
+ case "\\binom":
392
+ case "\\tbinom":
393
+ hasBarLine = false;
394
+ leftDelim = "(";
395
+ rightDelim = ")";
396
+ break;
397
+ default:
398
+ throw new Error("Unrecognized genfrac command");
399
+ }
400
+
401
+ switch (context.funcName) {
402
+ case "\\dfrac":
403
+ case "\\dbinom":
404
+ size = "display";
405
+ break;
406
+ case "\\tfrac":
407
+ case "\\tbinom":
408
+ size = "text";
409
+ break;
410
+ }
411
+
412
+ return {
413
+ type: "genfrac",
414
+ numer: numer,
415
+ denom: denom,
416
+ hasBarLine: hasBarLine,
417
+ leftDelim: leftDelim,
418
+ rightDelim: rightDelim,
419
+ size: size,
420
+ };
421
+ });
422
+
423
+ // Left and right overlap functions
424
+ defineFunction(["\\llap", "\\rlap"], {
425
+ numArgs: 1,
426
+ allowedInText: true,
427
+ }, function(context, args) {
428
+ var body = args[0];
429
+ return {
430
+ type: context.funcName.slice(1),
431
+ body: body,
432
+ };
433
+ });
434
+
435
+ // Delimiter functions
436
+ defineFunction([
437
+ "\\bigl", "\\Bigl", "\\biggl", "\\Biggl",
438
+ "\\bigr", "\\Bigr", "\\biggr", "\\Biggr",
439
+ "\\bigm", "\\Bigm", "\\biggm", "\\Biggm",
440
+ "\\big", "\\Big", "\\bigg", "\\Bigg",
441
+ "\\left", "\\right"
442
+ ], {
443
+ numArgs: 1,
444
+ }, function(context, args) {
445
+ var delim = args[0];
446
+ if (!utils.contains(delimiters, delim.value)) {
447
+ throw new ParseError(
448
+ "Invalid delimiter: '" + delim.value + "' after '" +
449
+ context.funcName + "'",
450
+ context.lexer, context.positions[1]);
451
+ }
452
+
453
+ // \left and \right are caught somewhere in Parser.js, which is
454
+ // why this data doesn't match what is in buildHTML.
455
+ if (context.funcName === "\\left" || context.funcName === "\\right") {
456
+ return {
457
+ type: "leftright",
458
+ value: delim.value,
459
+ funcName: context.funcName
460
+ };
461
+ } else {
462
+ return {
463
+ type: "delimsizing",
464
+ size: delimiterSizes[context.funcName].size,
465
+ delimType: delimiterSizes[context.funcName].type,
466
+ value: delim.value,
467
+ funcName: context.funcName
468
+ };
469
+ }
470
+ });
471
+
472
+ // Sizing functions (handled in Parser.js explicitly, hence no handler)
473
+ defineFunction([
474
+ "\\tiny", "\\scriptsize", "\\footnotesize", "\\small",
475
+ "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge", "\\textrm", "\\rm", "\\cal", "\\bf", "\\siptstyle", "\\boldmath", "\\it"
476
+ ], 0, null);
477
+
478
+ // Style changing functions (handled in Parser.js explicitly, hence no
479
+ // handler)
480
+ defineFunction([
481
+ "\\displaystyle", "\\textstyle", "\\scriptstyle",
482
+ "\\scriptscriptstyle",
483
+ ], 0, null);
484
+
485
+ defineFunction([
486
+ // styles
487
+ "\\mathrm", "\\mathit", "\\mathbf","\\mathop","\\stackrel",
488
+
489
+ // families
490
+ "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
491
+ "\\mathtt",
492
+
493
+ "\\label", "\\comment", "\\hspace", "\\vspace", "\\atop", "\\fbox", "\\tag", "\\makebox",
494
+ "\\raisebox", "\\framebox", "\\circle", "\\line", "\\put", "\\vphantom", "\\textup", "\\noalign",
495
+
496
+ // aliases
497
+ "\\Bbb", "\\bold", "\\frak",
498
+ ], {
499
+ numArgs: 1,
500
+ greediness: 2,
501
+ }, function(context, args) {
502
+ var body = args[0];
503
+ var func = context.funcName;
504
+ if (func in fontAliases) {
505
+ func = fontAliases[func];
506
+ }
507
+ return {
508
+ type: "font",
509
+ font: func.slice(1),
510
+ body: body,
511
+ };
512
+ });
513
+
514
+ // Accents
515
+ defineFunction([
516
+ "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
517
+ "\\check", "\\hat", "\\vec", "\\dot",
518
+ // We don't support expanding accents yet
519
+ // "\\widetilde", "\\widehat"
520
+ ], {
521
+ numArgs: 1,
522
+ }, function(context, args) {
523
+ var base = args[0];
524
+ return {
525
+ type: "accent",
526
+ accent: context.funcName,
527
+ base: base,
528
+ };
529
+ });
530
+
531
+ // Infix generalized fractions
532
+ defineFunction(["\\over", "\\choose"], {
533
+ numArgs: 0,
534
+ }, function(context) {
535
+ var replaceWith;
536
+ switch (context.funcName) {
537
+ case "\\over":
538
+ replaceWith = "\\frac";
539
+ break;
540
+ case "\\choose":
541
+ replaceWith = "\\binom";
542
+ break;
543
+ default:
544
+ throw new Error("Unrecognized infix genfrac command");
545
+ }
546
+ return {
547
+ type: "infix",
548
+ replaceWith: replaceWith,
549
+ };
550
+ });
551
+
552
+ // Row breaks for aligned data
553
+ defineFunction(["\\\\", "\\cr"], {
554
+ numArgs: 0,
555
+ numOptionalArgs: 1,
556
+ argTypes: ["size"],
557
+ }, function(context, args) {
558
+ var size = args[0];
559
+ return {
560
+ type: "cr",
561
+ size: size,
562
+ };
563
+ });
564
+
565
+ // Environment delimiters
566
+ defineFunction(["\\begin", "\\end"], {
567
+ numArgs: 1,
568
+ argTypes: ["text"],
569
+ }, function(context, args) {
570
+ var nameGroup = args[0];
571
+ if (nameGroup.type !== "ordgroup") {
572
+ throw new ParseError(
573
+ "Invalid environment name",
574
+ context.lexer, context.positions[1]);
575
+ }
576
+ var name = "";
577
+ for (var i = 0; i < nameGroup.value.length; ++i) {
578
+ name += nameGroup.value[i].value;
579
+ }
580
+ return {
581
+ type: "environment",
582
+ name: name,
583
+ namepos: context.positions[1],
584
+ };
585
+ });
katex/src/mathMLTree.js ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * These objects store data about MathML nodes. This is the MathML equivalent
3
+ * of the types in domTree.js. Since MathML handles its own rendering, and
4
+ * since we're mainly using MathML to improve accessibility, we don't manage
5
+ * any of the styling state that the plain DOM nodes do.
6
+ *
7
+ * The `toNode` and `toMarkup` functions work simlarly to how they do in
8
+ * domTree.js, creating namespaced DOM nodes and HTML text markup respectively.
9
+ */
10
+
11
+ var utils = require("./utils");
12
+
13
+ /**
14
+ * This node represents a general purpose MathML node of any type. The
15
+ * constructor requires the type of node to create (for example, `"mo"` or
16
+ * `"mspace"`, corresponding to `<mo>` and `<mspace>` tags).
17
+ */
18
+ function MathNode(type, children) {
19
+ this.type = type;
20
+ this.attributes = {};
21
+ this.children = children || [];
22
+ }
23
+
24
+ /**
25
+ * Sets an attribute on a MathML node. MathML depends on attributes to convey a
26
+ * semantic content, so this is used heavily.
27
+ */
28
+ MathNode.prototype.setAttribute = function(name, value) {
29
+ this.attributes[name] = value;
30
+ };
31
+
32
+ /**
33
+ * Converts the math node into a MathML-namespaced DOM element.
34
+ */
35
+ MathNode.prototype.toNode = function() {
36
+ var node = document.createElementNS(
37
+ "http://www.w3.org/1998/Math/MathML", this.type);
38
+
39
+ for (var attr in this.attributes) {
40
+ if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
41
+ node.setAttribute(attr, this.attributes[attr]);
42
+ }
43
+ }
44
+
45
+ for (var i = 0; i < this.children.length; i++) {
46
+ node.appendChild(this.children[i].toNode());
47
+ }
48
+
49
+ return node;
50
+ };
51
+
52
+ /**
53
+ * Converts the math node into an HTML markup string.
54
+ */
55
+ MathNode.prototype.toMarkup = function() {
56
+ var markup = "<" + this.type;
57
+
58
+ // Add the attributes
59
+ for (var attr in this.attributes) {
60
+ if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
61
+ markup += " " + attr + "=\"";
62
+ markup += utils.escape(this.attributes[attr]);
63
+ markup += "\"";
64
+ }
65
+ }
66
+
67
+ markup += ">";
68
+
69
+ for (var i = 0; i < this.children.length; i++) {
70
+ markup += this.children[i].toMarkup();
71
+ }
72
+
73
+ markup += "</" + this.type + ">";
74
+
75
+ return markup;
76
+ };
77
+
78
+ /**
79
+ * This node represents a piece of text.
80
+ */
81
+ function TextNode(text) {
82
+ this.text = text;
83
+ }
84
+
85
+ /**
86
+ * Converts the text node into a DOM text node.
87
+ */
88
+ TextNode.prototype.toNode = function() {
89
+ return document.createTextNode(this.text);
90
+ };
91
+
92
+ /**
93
+ * Converts the text node into HTML markup (which is just the text itself).
94
+ */
95
+ TextNode.prototype.toMarkup = function() {
96
+ return utils.escape(this.text);
97
+ };
98
+
99
+ module.exports = {
100
+ MathNode: MathNode,
101
+ TextNode: TextNode,
102
+ };
katex/src/parseData.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * The resulting parse tree nodes of the parse tree.
3
+ */
4
+ function ParseNode(type, value, mode) {
5
+ this.type = type;
6
+ this.value = value;
7
+ this.mode = mode;
8
+ }
9
+
10
+ module.exports = {
11
+ ParseNode: ParseNode,
12
+ };
13
+
katex/src/parseTree.js ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Provides a single function for parsing an expression using a Parser
3
+ * TODO(emily): Remove this
4
+ */
5
+
6
+ var Parser = require("./Parser");
7
+
8
+ /**
9
+ * Parses an expression using a Parser, then returns the parsed result.
10
+ */
11
+ var parseTree = function(toParse, settings) {
12
+ var parser = new Parser(toParse, settings);
13
+
14
+ return parser.parse();
15
+ };
16
+
17
+ module.exports = parseTree;
katex/src/symbols.js ADDED
@@ -0,0 +1,687 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file holds a list of all no-argument functions and single-character
3
+ * symbols (like 'a' or ';').
4
+ *
5
+ * For each of the symbols, there are three properties they can have:
6
+ * - font (required): the font to be used for this symbol. Either "main" (the
7
+ normal font), or "ams" (the ams fonts).
8
+ * - group (required): the ParseNode group type the symbol should have (i.e.
9
+ "textord", "mathord", etc).
10
+ See https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types
11
+ * - replace: the character that this symbol or function should be
12
+ * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi
13
+ * character in the main font).
14
+ *
15
+ * The outermost map in the table indicates what mode the symbols should be
16
+ * accepted in (e.g. "math" or "text").
17
+ */
18
+
19
+ module.exports = {
20
+ math: {},
21
+ text: {},
22
+ };
23
+
24
+ function defineSymbol(mode, font, group, replace, name) {
25
+ module.exports[mode][name] = {
26
+ font: font,
27
+ group: group,
28
+ replace: replace,
29
+ };
30
+ }
31
+
32
+ // Some abbreviations for commonly used strings.
33
+ // This helps minify the code, and also spotting typos using jshint.
34
+
35
+ // modes:
36
+ var math = "math";
37
+ var text = "text";
38
+
39
+ // fonts:
40
+ var main = "main";
41
+ var ams = "ams";
42
+
43
+ // groups:
44
+ var accent = "accent";
45
+ var bin = "bin";
46
+ var close = "close";
47
+ var inner = "inner";
48
+ var mathord = "mathord";
49
+ var op = "op";
50
+ var open = "open";
51
+ var punct = "punct";
52
+ var rel = "rel";
53
+ var spacing = "spacing";
54
+ var textord = "textord";
55
+
56
+ // Now comes the symbol table
57
+
58
+ // Relation Symbols
59
+ defineSymbol(math, main, rel, "\u2261", "\\equiv");
60
+ defineSymbol(math, main, rel, "\u227a", "\\prec");
61
+ defineSymbol(math, main, rel, "\u227b", "\\succ");
62
+ defineSymbol(math, main, rel, "\u223c", "\\sim");
63
+ defineSymbol(math, main, rel, "\u22a5", "\\perp");
64
+ defineSymbol(math, main, rel, "\u2aaf", "\\preceq");
65
+ defineSymbol(math, main, rel, "\u2ab0", "\\succeq");
66
+ defineSymbol(math, main, rel, "\u2243", "\\simeq");
67
+ defineSymbol(math, main, rel, "\u2223", "\\mid");
68
+ defineSymbol(math, main, rel, "\u226a", "\\ll");
69
+ defineSymbol(math, main, rel, "\u226b", "\\gg");
70
+ defineSymbol(math, main, rel, "\u224d", "\\asymp");
71
+ defineSymbol(math, main, rel, "\u2225", "\\parallel");
72
+ defineSymbol(math, main, rel, "\u22c8", "\\bowtie");
73
+ defineSymbol(math, main, rel, "\u2323", "\\smile");
74
+ defineSymbol(math, main, rel, "\u2291", "\\sqsubseteq");
75
+ defineSymbol(math, main, rel, "\u2292", "\\sqsupseteq");
76
+ defineSymbol(math, main, rel, "\u2250", "\\doteq");
77
+ defineSymbol(math, main, rel, "\u2322", "\\frown");
78
+ defineSymbol(math, main, rel, "\u220b", "\\ni");
79
+ defineSymbol(math, main, rel, "\u221d", "\\propto");
80
+ defineSymbol(math, main, rel, "\u22a2", "\\vdash");
81
+ defineSymbol(math, main, rel, "\u22a3", "\\dashv");
82
+ defineSymbol(math, main, rel, "\u220b", "\\owns");
83
+
84
+ defineSymbol(math, main, rel, "\u220b", "\\widehat");
85
+ defineSymbol(math, main, rel, "\u220b", "\\widetilde");
86
+ defineSymbol(math, main, rel, "\u220b", "\\sp");
87
+ defineSymbol(math, main, rel, "\u220b", "\\quad");
88
+ // defineSymbol(math, main, rel, "\u220b", "\\cr");
89
+ defineSymbol(math, main, rel, "\u220b", "\\\\sim");
90
+ defineSymbol(math, main, rel, "\u220b", "\\nonumber");
91
+ defineSymbol(math, main, rel, "\u220b", "\\dots");
92
+ defineSymbol(math, main, rel, "\u220b", "\\cases");
93
+ defineSymbol(math, main, rel, "\u220b", "\\mit");
94
+ defineSymbol(math, main, rel, "\u220b", "\\smallskip");
95
+ defineSymbol(math, main, rel, "\u220b", "\\slash");
96
+ defineSymbol(math, main, rel, "\u220b", "\\d");
97
+ defineSymbol(math, main, rel, "\u220b", "\\c");
98
+ defineSymbol(math, main, rel, "\u220b", "\\b");
99
+ defineSymbol(math, main, rel, "\u220b", "\\M");
100
+ defineSymbol(math, main, rel, "\u220b", "\\S");
101
+ defineSymbol(math, main, rel, "\u220b", "\\(");
102
+ defineSymbol(math, main, rel, "\u220b", "\\)");
103
+ // defineSymbol(math, main, rel, "\u220b", "\\Comp");
104
+ defineSymbol(math, main, rel, "\u220b", "\\thinspace");
105
+ defineSymbol(math, main, rel, "\u220b", "\\hskip");
106
+ defineSymbol(math, main, rel, "\u220b", "\\tt");
107
+ defineSymbol(math, main, rel, "\u220b", "\\not");
108
+ defineSymbol(math, main, rel, "\u220b", "\\boldmathr");
109
+ defineSymbol(math, main, rel, "\u220b", "\\overleftarrow");
110
+ defineSymbol(math, main, rel, "\u220b", "\\overrightarrow");
111
+ defineSymbol(math, main, rel, "\u220b", "\\intf");
112
+ defineSymbol(math, main, rel, "\u220b", "\\sf");
113
+ defineSymbol(math, main, rel, "\u220b", "\\textbf");
114
+ defineSymbol(math, main, rel, "\u220b", "\\L");
115
+ defineSymbol(math, main, rel, "\u220b", "\\pii");
116
+ defineSymbol(math, main, rel, "\u220b", "\\unitlength");
117
+ defineSymbol(math, main, rel, "\u220b", "\\arowtor5linv");
118
+ defineSymbol(math, main, rel, "\u220b", "\\hline");
119
+ defineSymbol(math, main, rel, "\u220b", "\\mathbin");
120
+ defineSymbol(math, main, rel, "\u220b", "\\nc");
121
+ defineSymbol(math, main, rel, "\u220b", "\\underbrace");
122
+ defineSymbol(math, main, rel, "\u220b", "\\o");
123
+ defineSymbol(math, main, rel, "\u220b", "\\a");
124
+ defineSymbol(math, main, rel, "\u220b", "\\b");
125
+ defineSymbol(math, main, rel, "\u220b", "\\c");
126
+ defineSymbol(math, main, rel, "\u220b", "\\d");
127
+ defineSymbol(math, main, rel, "\u220b", "\\e");
128
+ defineSymbol(math, main, rel, "\u220b", "\\f");
129
+ defineSymbol(math, main, rel, "\u220b", "\\g");
130
+ defineSymbol(math, main, rel, "\u220b", "\\h");
131
+ defineSymbol(math, main, rel, "\u220b", "\\i");
132
+ defineSymbol(math, main, rel, "\u220b", "\\j");
133
+ defineSymbol(math, main, rel, "\u220b", "\\k");
134
+ defineSymbol(math, main, rel, "\u220b", "\\l");
135
+ defineSymbol(math, main, rel, "\u220b", "\\m");
136
+ defineSymbol(math, main, rel, "\u220b", "\\n");
137
+ defineSymbol(math, main, rel, "\u220b", "\\o");
138
+ // defineSymbol(math, main, rel, "\u220b", "\\wedgee");
139
+ defineSymbol(math, main, rel, "\u220b", "\\sb");
140
+ defineSymbol(math, main, rel, "\u220b", "\\do");
141
+ defineSymbol(math, main, rel, "\u220b", "\\em");
142
+ // defineSymbol(math, main, rel, "\u220b", "\\diamonda");
143
+
144
+
145
+ defineSymbol(math, main, rel, "\u220b", "\\dint");
146
+ defineSymbol(math, main, rel, "\u220b", "\\intd");
147
+
148
+
149
+ // Punctuation
150
+ defineSymbol(math, main, punct, "\u002e", "\\ldotp");
151
+ defineSymbol(math, main, punct, "\u22c5", "\\cdotp");
152
+
153
+ // Misc Symbols
154
+ defineSymbol(math, main, textord, "\u0023", "\\#");
155
+ defineSymbol(math, main, textord, "\u0026", "\\&");
156
+ defineSymbol(math, main, textord, "\u2135", "\\aleph");
157
+ defineSymbol(math, main, textord, "\u2200", "\\forall");
158
+ defineSymbol(math, main, textord, "\u210f", "\\hbar");
159
+ defineSymbol(math, main, textord, "\u2203", "\\eixsts");
160
+ defineSymbol(math, main, textord, "\u2207", "\\nabla");
161
+ defineSymbol(math, main, textord, "\u266d", "\\flat");
162
+ defineSymbol(math, main, textord, "\u2113", "\\ell");
163
+ defineSymbol(math, main, textord, "\u266e", "\\natural");
164
+ defineSymbol(math, main, textord, "\u2663", "\\clubsuit");
165
+ defineSymbol(math, main, textord, "\u2118", "\\wp");
166
+ defineSymbol(math, main, textord, "\u266f", "\\sharp");
167
+ defineSymbol(math, main, textord, "\u2662", "\\diamondsuit");
168
+ defineSymbol(math, main, textord, "\u211c", "\\Re");
169
+ defineSymbol(math, main, textord, "\u2661", "\\heartsuit");
170
+ defineSymbol(math, main, textord, "\u2111", "\\Im");
171
+ defineSymbol(math, main, textord, "\u2660", "\\spadesuit");
172
+
173
+ // Math and Text
174
+ defineSymbol(math, main, textord, "\u2020", "\\dag");
175
+ defineSymbol(math, main, textord, "\u2021", "\\ddag");
176
+
177
+ // Large Delimiters
178
+ defineSymbol(math, main, close, "\u23b1", "\\rmoustache");
179
+ defineSymbol(math, main, open, "\u23b0", "\\lmoustache");
180
+ defineSymbol(math, main, close, "\u27ef", "\\rgroup");
181
+ defineSymbol(math, main, open, "\u27ee", "\\lgroup");
182
+
183
+ // Binary Operators
184
+ defineSymbol(math, main, bin, "\u2213", "\\mp");
185
+ defineSymbol(math, main, bin, "\u2296", "\\ominus");
186
+ defineSymbol(math, main, bin, "\u228e", "\\uplus");
187
+ defineSymbol(math, main, bin, "\u2293", "\\sqcap");
188
+ defineSymbol(math, main, bin, "\u2217", "\\ast");
189
+ defineSymbol(math, main, bin, "\u2294", "\\sqcup");
190
+ defineSymbol(math, main, bin, "\u25ef", "\\bigcirc");
191
+ defineSymbol(math, main, bin, "\u2219", "\\bullet");
192
+ defineSymbol(math, main, bin, "\u2021", "\\ddagger");
193
+ defineSymbol(math, main, bin, "\u2240", "\\wr");
194
+ defineSymbol(math, main, bin, "\u2a3f", "\\amalg");
195
+
196
+ // Arrow Symbols
197
+ defineSymbol(math, main, rel, "\u27f5", "\\longleftarrow");
198
+ defineSymbol(math, main, rel, "\u21d0", "\\Leftarrow");
199
+ defineSymbol(math, main, rel, "\u27f8", "\\Longleftarrow");
200
+ defineSymbol(math, main, rel, "\u27f6", "\\longrightarrow");
201
+ defineSymbol(math, main, rel, "\u21d2", "\\Rightarrow");
202
+ defineSymbol(math, main, rel, "\u27f9", "\\Longrightarrow");
203
+ defineSymbol(math, main, rel, "\u2194", "\\leftrightarrow");
204
+ defineSymbol(math, main, rel, "\u27f7", "\\longleftrightarrow");
205
+ defineSymbol(math, main, rel, "\u21d4", "\\Leftrightarrow");
206
+ defineSymbol(math, main, rel, "\u27fa", "\\Longleftrightarrow");
207
+ defineSymbol(math, main, rel, "\u21a6", "\\mapsto");
208
+ defineSymbol(math, main, rel, "\u27fc", "\\longmapsto");
209
+ defineSymbol(math, main, rel, "\u2197", "\\nearrow");
210
+ defineSymbol(math, main, rel, "\u21a9", "\\hookleftarrow");
211
+ defineSymbol(math, main, rel, "\u21aa", "\\hookrightarrow");
212
+ defineSymbol(math, main, rel, "\u2198", "\\searrow");
213
+ defineSymbol(math, main, rel, "\u21bc", "\\leftharpoonup");
214
+ defineSymbol(math, main, rel, "\u21c0", "\\rightharpoonup");
215
+ defineSymbol(math, main, rel, "\u2199", "\\swarrow");
216
+ defineSymbol(math, main, rel, "\u21bd", "\\leftharpoondown");
217
+ defineSymbol(math, main, rel, "\u21c1", "\\rightharpoondown");
218
+ defineSymbol(math, main, rel, "\u2196", "\\nwarrow");
219
+ defineSymbol(math, main, rel, "\u21cc", "\\rightleftharpoons");
220
+
221
+ // AMS Negated Binary Relations
222
+ defineSymbol(math, ams, rel, "\u226e", "\\nless");
223
+ defineSymbol(math, ams, rel, "\ue010", "\\nleqslant");
224
+ defineSymbol(math, ams, rel, "\ue011", "\\nleqq");
225
+ defineSymbol(math, ams, rel, "\u2a87", "\\lneq");
226
+ defineSymbol(math, ams, rel, "\u2268", "\\lneqq");
227
+ defineSymbol(math, ams, rel, "\ue00c", "\\lvertneqq");
228
+ defineSymbol(math, ams, rel, "\u22e6", "\\lnsim");
229
+ defineSymbol(math, ams, rel, "\u2a89", "\\lnapprox");
230
+ defineSymbol(math, ams, rel, "\u2280", "\\nprec");
231
+ defineSymbol(math, ams, rel, "\u22e0", "\\npreceq");
232
+ defineSymbol(math, ams, rel, "\u22e8", "\\precnsim");
233
+ defineSymbol(math, ams, rel, "\u2ab9", "\\precnapprox");
234
+ defineSymbol(math, ams, rel, "\u2241", "\\nsim");
235
+ defineSymbol(math, ams, rel, "\ue006", "\\nshortmid");
236
+ defineSymbol(math, ams, rel, "\u2224", "\\nmid");
237
+ defineSymbol(math, ams, rel, "\u22ac", "\\nvdash");
238
+ defineSymbol(math, ams, rel, "\u22ad", "\\nvDash");
239
+ defineSymbol(math, ams, rel, "\u22ea", "\\ntriangleleft");
240
+ defineSymbol(math, ams, rel, "\u22ec", "\\ntrianglelefteq");
241
+ defineSymbol(math, ams, rel, "\u228a", "\\subsetneq");
242
+ defineSymbol(math, ams, rel, "\ue01a", "\\varsubsetneq");
243
+ defineSymbol(math, ams, rel, "\u2acb", "\\subsetneqq");
244
+ defineSymbol(math, ams, rel, "\ue017", "\\varsubsetneqq");
245
+ defineSymbol(math, ams, rel, "\u226f", "\\ngtr");
246
+ defineSymbol(math, ams, rel, "\ue00f", "\\ngeqslant");
247
+ defineSymbol(math, ams, rel, "\ue00e", "\\ngeqq");
248
+ defineSymbol(math, ams, rel, "\u2a88", "\\gneq");
249
+ defineSymbol(math, ams, rel, "\u2269", "\\gneqq");
250
+ defineSymbol(math, ams, rel, "\ue00d", "\\gvertneqq");
251
+ defineSymbol(math, ams, rel, "\u22e7", "\\gnsim");
252
+ defineSymbol(math, ams, rel, "\u2a8a", "\\gnapprox");
253
+ defineSymbol(math, ams, rel, "\u2281", "\\nsucc");
254
+ defineSymbol(math, ams, rel, "\u22e1", "\\nsucceq");
255
+ defineSymbol(math, ams, rel, "\u22e9", "\\succnsim");
256
+ defineSymbol(math, ams, rel, "\u2aba", "\\succnapprox");
257
+ defineSymbol(math, ams, rel, "\u2246", "\\ncong");
258
+ defineSymbol(math, ams, rel, "\ue007", "\\nshortparallel");
259
+ defineSymbol(math, ams, rel, "\u2226", "\\nparallel");
260
+ defineSymbol(math, ams, rel, "\u22af", "\\nVDash");
261
+ defineSymbol(math, ams, rel, "\u22eb", "\\ntriangleright");
262
+ defineSymbol(math, ams, rel, "\u22ed", "\\ntrianglerighteq");
263
+ defineSymbol(math, ams, rel, "\ue018", "\\nsupseteqq");
264
+ defineSymbol(math, ams, rel, "\u228b", "\\supsetneq");
265
+ defineSymbol(math, ams, rel, "\ue01b", "\\varsupsetneq");
266
+ defineSymbol(math, ams, rel, "\u2acc", "\\supsetneqq");
267
+ defineSymbol(math, ams, rel, "\ue019", "\\varsupsetneqq");
268
+ defineSymbol(math, ams, rel, "\u22ae", "\\nVdash");
269
+ defineSymbol(math, ams, rel, "\u2ab5", "\\precneqq");
270
+ defineSymbol(math, ams, rel, "\u2ab6", "\\succneqq");
271
+ defineSymbol(math, ams, rel, "\ue016", "\\nsubseteqq");
272
+ defineSymbol(math, ams, bin, "\u22b4", "\\unlhd");
273
+ defineSymbol(math, ams, bin, "\u22b5", "\\unrhd");
274
+
275
+ // AMS Negated Arrows
276
+ defineSymbol(math, ams, rel, "\u219a", "\\nleftarrow");
277
+ defineSymbol(math, ams, rel, "\u219b", "\\nrightarrow");
278
+ defineSymbol(math, ams, rel, "\u21cd", "\\nLeftarrow");
279
+ defineSymbol(math, ams, rel, "\u21cf", "\\nRightarrow");
280
+ defineSymbol(math, ams, rel, "\u21ae", "\\nleftrightarrow");
281
+ defineSymbol(math, ams, rel, "\u21ce", "\\nLeftrightarrow");
282
+
283
+ // AMS Misc
284
+ defineSymbol(math, ams, rel, "\u25b3", "\\vartriangle");
285
+ defineSymbol(math, ams, textord, "\u210f", "\\hslash");
286
+ defineSymbol(math, ams, textord, "\u25bd", "\\triangledown");
287
+ defineSymbol(math, ams, textord, "\u25ca", "\\lozenge");
288
+ defineSymbol(math, ams, textord, "\u24c8", "\\circledS");
289
+ defineSymbol(math, ams, textord, "\u00ae", "\\circledR");
290
+ defineSymbol(math, ams, textord, "\u2221", "\\measuredangle");
291
+ defineSymbol(math, ams, textord, "\u2204", "\\nexists");
292
+ defineSymbol(math, ams, textord, "\u2127", "\\mho");
293
+ defineSymbol(math, ams, textord, "\u2132", "\\Finv");
294
+ defineSymbol(math, ams, textord, "\u2141", "\\Game");
295
+ defineSymbol(math, ams, textord, "\u006b", "\\Bbbk");
296
+ defineSymbol(math, ams, textord, "\u2035", "\\backprime");
297
+ defineSymbol(math, ams, textord, "\u25b2", "\\blacktriangle");
298
+ defineSymbol(math, ams, textord, "\u25bc", "\\blacktriangledown");
299
+ defineSymbol(math, ams, textord, "\u25a0", "\\blacksquare");
300
+ defineSymbol(math, ams, textord, "\u29eb", "\\blacklozenge");
301
+ defineSymbol(math, ams, textord, "\u2605", "\\bigstar");
302
+ defineSymbol(math, ams, textord, "\u2222", "\\sphericalangle");
303
+ defineSymbol(math, ams, textord, "\u2201", "\\complement");
304
+ defineSymbol(math, ams, textord, "\u00f0", "\\eth");
305
+ defineSymbol(math, ams, textord, "\u2571", "\\diagup");
306
+ defineSymbol(math, ams, textord, "\u2572", "\\diagdown");
307
+ defineSymbol(math, ams, textord, "\u25a1", "\\square");
308
+ defineSymbol(math, ams, textord, "\u25a1", "\\Box");
309
+ defineSymbol(math, ams, textord, "\u25ca", "\\Diamond");
310
+ defineSymbol(math, ams, textord, "\u00a5", "\\yen");
311
+ defineSymbol(math, ams, textord, "\u2713", "\\checkmark");
312
+
313
+ // AMS Hebrew
314
+ defineSymbol(math, ams, textord, "\u2136", "\\beth");
315
+ defineSymbol(math, ams, textord, "\u2138", "\\daleth");
316
+ defineSymbol(math, ams, textord, "\u2137", "\\gimel");
317
+
318
+ // AMS Greek
319
+ defineSymbol(math, ams, textord, "\u03dd", "\\digamma");
320
+ defineSymbol(math, ams, textord, "\u03f0", "\\varkappa");
321
+
322
+ // AMS Delimiters
323
+ defineSymbol(math, ams, open, "\u250c", "\\ulcorner");
324
+ defineSymbol(math, ams, close, "\u2510", "\\urcorner");
325
+ defineSymbol(math, ams, open, "\u2514", "\\llcorner");
326
+ defineSymbol(math, ams, close, "\u2518", "\\lrcorner");
327
+
328
+ // AMS Binary Relations
329
+ defineSymbol(math, ams, rel, "\u2266", "\\leqq");
330
+ defineSymbol(math, ams, rel, "\u2a7d", "\\leqslant");
331
+ defineSymbol(math, ams, rel, "\u2a95", "\\eqslantless");
332
+ defineSymbol(math, ams, rel, "\u2272", "\\lesssim");
333
+ defineSymbol(math, ams, rel, "\u2a85", "\\lessapprox");
334
+ defineSymbol(math, ams, rel, "\u224a", "\\approxeq");
335
+ defineSymbol(math, ams, bin, "\u22d6", "\\lessdot");
336
+ defineSymbol(math, ams, rel, "\u22d8", "\\lll");
337
+ defineSymbol(math, ams, rel, "\u2276", "\\lessgtr");
338
+ defineSymbol(math, ams, rel, "\u22da", "\\lesseqgtr");
339
+ defineSymbol(math, ams, rel, "\u2a8b", "\\lesseqqgtr");
340
+ defineSymbol(math, ams, rel, "\u2251", "\\doteqdot");
341
+ defineSymbol(math, ams, rel, "\u2253", "\\risingdotseq");
342
+ defineSymbol(math, ams, rel, "\u2252", "\\fallingdotseq");
343
+ defineSymbol(math, ams, rel, "\u223d", "\\backsim");
344
+ defineSymbol(math, ams, rel, "\u22cd", "\\backsimeq");
345
+ defineSymbol(math, ams, rel, "\u2ac5", "\\subseteqq");
346
+ defineSymbol(math, ams, rel, "\u22d0", "\\Subset");
347
+ defineSymbol(math, ams, rel, "\u228f", "\\sqsubset");
348
+ defineSymbol(math, ams, rel, "\u227c", "\\preccurlyeq");
349
+ defineSymbol(math, ams, rel, "\u22de", "\\curlyeqprec");
350
+ defineSymbol(math, ams, rel, "\u227e", "\\precsim");
351
+ defineSymbol(math, ams, rel, "\u2ab7", "\\precapprox");
352
+ defineSymbol(math, ams, rel, "\u22b2", "\\vartriangleleft");
353
+ defineSymbol(math, ams, rel, "\u22b4", "\\trianglelefteq");
354
+ defineSymbol(math, ams, rel, "\u22a8", "\\vDash");
355
+ defineSymbol(math, ams, rel, "\u22aa", "\\Vvdash");
356
+ defineSymbol(math, ams, rel, "\u2323", "\\smallsmile");
357
+ defineSymbol(math, ams, rel, "\u2322", "\\smallfrown");
358
+ defineSymbol(math, ams, rel, "\u224f", "\\bumpeq");
359
+ defineSymbol(math, ams, rel, "\u224e", "\\Bumpeq");
360
+ defineSymbol(math, ams, rel, "\u2267", "\\geqq");
361
+ defineSymbol(math, ams, rel, "\u2a7e", "\\geqslant");
362
+ defineSymbol(math, ams, rel, "\u2a96", "\\eqslantgtr");
363
+ defineSymbol(math, ams, rel, "\u2273", "\\gtrsim");
364
+ defineSymbol(math, ams, rel, "\u2a86", "\\gtrapprox");
365
+ defineSymbol(math, ams, bin, "\u22d7", "\\gtrdot");
366
+ defineSymbol(math, ams, rel, "\u22d9", "\\ggg");
367
+ defineSymbol(math, ams, rel, "\u2277", "\\gtrless");
368
+ defineSymbol(math, ams, rel, "\u22db", "\\gtreqless");
369
+ defineSymbol(math, ams, rel, "\u2a8c", "\\gtreqqless");
370
+ defineSymbol(math, ams, rel, "\u2256", "\\eqcirc");
371
+ defineSymbol(math, ams, rel, "\u2257", "\\circeq");
372
+ defineSymbol(math, ams, rel, "\u225c", "\\triangleq");
373
+ defineSymbol(math, ams, rel, "\u223c", "\\thicksim");
374
+ defineSymbol(math, ams, rel, "\u2248", "\\thickapprox");
375
+ defineSymbol(math, ams, rel, "\u2ac6", "\\supseteqq");
376
+ defineSymbol(math, ams, rel, "\u22d1", "\\Supset");
377
+ defineSymbol(math, ams, rel, "\u2290", "\\sqsupset");
378
+ defineSymbol(math, ams, rel, "\u227d", "\\succcurlyeq");
379
+ defineSymbol(math, ams, rel, "\u22df", "\\curlyeqsucc");
380
+ defineSymbol(math, ams, rel, "\u227f", "\\succsim");
381
+ defineSymbol(math, ams, rel, "\u2ab8", "\\succapprox");
382
+ defineSymbol(math, ams, rel, "\u22b3", "\\vartriangleright");
383
+ defineSymbol(math, ams, rel, "\u22b5", "\\trianglerighteq");
384
+ defineSymbol(math, ams, rel, "\u22a9", "\\Vdash");
385
+ defineSymbol(math, ams, rel, "\u2223", "\\shortmid");
386
+ defineSymbol(math, ams, rel, "\u2225", "\\shortparallel");
387
+ defineSymbol(math, ams, rel, "\u226c", "\\between");
388
+ defineSymbol(math, ams, rel, "\u22d4", "\\pitchfork");
389
+ defineSymbol(math, ams, rel, "\u221d", "\\varpropto");
390
+ defineSymbol(math, ams, rel, "\u25c0", "\\blacktriangleleft");
391
+ defineSymbol(math, ams, rel, "\u2234", "\\therefore");
392
+ defineSymbol(math, ams, rel, "\u220d", "\\backepsilon");
393
+ defineSymbol(math, ams, rel, "\u25b6", "\\blacktriangleright");
394
+ defineSymbol(math, ams, rel, "\u2235", "\\because");
395
+ defineSymbol(math, ams, rel, "\u22d8", "\\llless");
396
+ defineSymbol(math, ams, rel, "\u22d9", "\\gggtr");
397
+ defineSymbol(math, ams, bin, "\u22b2", "\\lhd");
398
+ defineSymbol(math, ams, bin, "\u22b3", "\\rhd");
399
+ defineSymbol(math, ams, rel, "\u2242", "\\eqsim");
400
+ defineSymbol(math, main, rel, "\u22c8", "\\Join");
401
+ defineSymbol(math, ams, rel, "\u2251", "\\Doteq");
402
+
403
+ // AMS Binary Operators
404
+ defineSymbol(math, ams, bin, "\u2214", "\\dotplus");
405
+ defineSymbol(math, ams, bin, "\u2216", "\\smallsetminus");
406
+ defineSymbol(math, ams, bin, "\u22d2", "\\Cap");
407
+ defineSymbol(math, ams, bin, "\u22d3", "\\Cup");
408
+ defineSymbol(math, ams, bin, "\u2a5e", "\\doublebarwedge");
409
+ defineSymbol(math, ams, bin, "\u229f", "\\boxminus");
410
+ defineSymbol(math, ams, bin, "\u229e", "\\boxplus");
411
+ defineSymbol(math, ams, bin, "\u22c7", "\\divideontimes");
412
+ defineSymbol(math, ams, bin, "\u22c9", "\\ltimes");
413
+ defineSymbol(math, ams, bin, "\u22ca", "\\rtimes");
414
+ defineSymbol(math, ams, bin, "\u22cb", "\\leftthreetimes");
415
+ defineSymbol(math, ams, bin, "\u22cc", "\\rightthreetimes");
416
+ defineSymbol(math, ams, bin, "\u22cf", "\\curlywedge");
417
+ defineSymbol(math, ams, bin, "\u22ce", "\\curlyvee");
418
+ defineSymbol(math, ams, bin, "\u229d", "\\circleddash");
419
+ defineSymbol(math, ams, bin, "\u229b", "\\circledast");
420
+ defineSymbol(math, ams, bin, "\u22c5", "\\centerdot");
421
+ defineSymbol(math, ams, bin, "\u22ba", "\\intercal");
422
+ defineSymbol(math, ams, bin, "\u22d2", "\\doublecap");
423
+ defineSymbol(math, ams, bin, "\u22d3", "\\doublecup");
424
+ defineSymbol(math, ams, bin, "\u22a0", "\\boxtimes");
425
+
426
+ // AMS Arrows
427
+ defineSymbol(math, ams, rel, "\u21e2", "\\dashrightarrow");
428
+ defineSymbol(math, ams, rel, "\u21e0", "\\dashleftarrow");
429
+ defineSymbol(math, ams, rel, "\u21c7", "\\leftleftarrows");
430
+ defineSymbol(math, ams, rel, "\u21c6", "\\leftrightarrows");
431
+ defineSymbol(math, ams, rel, "\u21da", "\\Lleftarrow");
432
+ defineSymbol(math, ams, rel, "\u219e", "\\twoheadleftarrow");
433
+ defineSymbol(math, ams, rel, "\u21a2", "\\leftarrowtail");
434
+ defineSymbol(math, ams, rel, "\u21ab", "\\looparrowleft");
435
+ defineSymbol(math, ams, rel, "\u21cb", "\\leftrightharpoons");
436
+ defineSymbol(math, ams, rel, "\u21b6", "\\curvearrowleft");
437
+ defineSymbol(math, ams, rel, "\u21ba", "\\circlearrowleft");
438
+ defineSymbol(math, ams, rel, "\u21b0", "\\Lsh");
439
+ defineSymbol(math, ams, rel, "\u21c8", "\\upuparrows");
440
+ defineSymbol(math, ams, rel, "\u21bf", "\\upharpoonleft");
441
+ defineSymbol(math, ams, rel, "\u21c3", "\\downharpoonleft");
442
+ defineSymbol(math, ams, rel, "\u22b8", "\\multimap");
443
+ defineSymbol(math, ams, rel, "\u21ad", "\\leftrightsquigarrow");
444
+ defineSymbol(math, ams, rel, "\u21c9", "\\rightrightarrows");
445
+ defineSymbol(math, ams, rel, "\u21c4", "\\rightleftarrows");
446
+ defineSymbol(math, ams, rel, "\u21a0", "\\twoheadrightarrow");
447
+ defineSymbol(math, ams, rel, "\u21a3", "\\rightarrowtail");
448
+ defineSymbol(math, ams, rel, "\u21ac", "\\looparrowright");
449
+ defineSymbol(math, ams, rel, "\u21b7", "\\curvearrowright");
450
+ defineSymbol(math, ams, rel, "\u21bb", "\\circlearrowright");
451
+ defineSymbol(math, ams, rel, "\u21b1", "\\Rsh");
452
+ defineSymbol(math, ams, rel, "\u21ca", "\\downdownarrows");
453
+ defineSymbol(math, ams, rel, "\u21be", "\\upharpoonright");
454
+ defineSymbol(math, ams, rel, "\u21c2", "\\downharpoonright");
455
+ defineSymbol(math, ams, rel, "\u21dd", "\\rightsquigarrow");
456
+ defineSymbol(math, ams, rel, "\u21dd", "\\leadsto");
457
+ defineSymbol(math, ams, rel, "\u21db", "\\Rrightarrow");
458
+ defineSymbol(math, ams, rel, "\u21be", "\\restriction");
459
+
460
+ defineSymbol(math, main, textord, "\u2018", "`");
461
+ defineSymbol(math, main, textord, "$", "\\$");
462
+ defineSymbol(math, main, textord, "%", "\\%");
463
+ defineSymbol(math, main, textord, "_", "\\_");
464
+ defineSymbol(math, main, textord, "\u2220", "\\angle");
465
+ defineSymbol(math, main, textord, "\u221e", "\\infty");
466
+ defineSymbol(math, main, textord, "\u2032", "\\prime");
467
+ defineSymbol(math, main, textord, "\u25b3", "\\triangle");
468
+ defineSymbol(math, main, textord, "\u0393", "\\Gamma");
469
+ defineSymbol(math, main, textord, "\u0394", "\\Delta");
470
+ defineSymbol(math, main, textord, "\u0398", "\\Theta");
471
+ defineSymbol(math, main, textord, "\u039b", "\\Lambda");
472
+ defineSymbol(math, main, textord, "\u039e", "\\Xi");
473
+ defineSymbol(math, main, textord, "\u03a0", "\\Pi");
474
+ defineSymbol(math, main, textord, "\u03a3", "\\Sigma");
475
+ defineSymbol(math, main, textord, "\u03a5", "\\Upsilon");
476
+ defineSymbol(math, main, textord, "\u03a6", "\\Phi");
477
+ defineSymbol(math, main, textord, "\u03a8", "\\Psi");
478
+ defineSymbol(math, main, textord, "\u03a9", "\\Omega");
479
+ defineSymbol(math, main, textord, "\u00ac", "\\neg");
480
+ defineSymbol(math, main, textord, "\u00ac", "\\lnot");
481
+ defineSymbol(math, main, textord, "\u22a4", "\\top");
482
+ defineSymbol(math, main, textord, "\u22a5", "\\bot");
483
+ defineSymbol(math, main, textord, "\u2205", "\\emptyset");
484
+ defineSymbol(math, ams, textord, "\u2205", "\\varnothing");
485
+ defineSymbol(math, main, mathord, "\u03b1", "\\alpha");
486
+ defineSymbol(math, main, mathord, "\u03b2", "\\beta");
487
+ defineSymbol(math, main, mathord, "\u03b3", "\\gamma");
488
+ defineSymbol(math, main, mathord, "\u03b4", "\\delta");
489
+ defineSymbol(math, main, mathord, "\u03f5", "\\epsilon");
490
+ defineSymbol(math, main, mathord, "\u03b6", "\\zeta");
491
+ defineSymbol(math, main, mathord, "\u03b7", "\\eta");
492
+ defineSymbol(math, main, mathord, "\u03b8", "\\theta");
493
+ defineSymbol(math, main, mathord, "\u03b9", "\\iota");
494
+ defineSymbol(math, main, mathord, "\u03ba", "\\kappa");
495
+ defineSymbol(math, main, mathord, "\u03bb", "\\lambda");
496
+ defineSymbol(math, main, mathord, "\u03bc", "\\mu");
497
+ defineSymbol(math, main, mathord, "\u03bd", "\\nu");
498
+ defineSymbol(math, main, mathord, "\u03be", "\\xi");
499
+ defineSymbol(math, main, mathord, "o", "\\omicron");
500
+ defineSymbol(math, main, mathord, "\u03c0", "\\pi");
501
+ defineSymbol(math, main, mathord, "\u03c1", "\\rho");
502
+ defineSymbol(math, main, mathord, "\u03c3", "\\sigma");
503
+ defineSymbol(math, main, mathord, "\u03c4", "\\tau");
504
+ defineSymbol(math, main, mathord, "\u03c5", "\\upsilon");
505
+ defineSymbol(math, main, mathord, "\u03d5", "\\phi");
506
+ defineSymbol(math, main, mathord, "\u03c7", "\\chi");
507
+ defineSymbol(math, main, mathord, "\u03c8", "\\psi");
508
+ defineSymbol(math, main, mathord, "\u03c9", "\\omega");
509
+ defineSymbol(math, main, mathord, "\u03b5", "\\varepsilon");
510
+ defineSymbol(math, main, mathord, "\u03d1", "\\vartheta");
511
+ defineSymbol(math, main, mathord, "\u03d6", "\\varpi");
512
+ defineSymbol(math, main, mathord, "\u03f1", "\\varrho");
513
+ defineSymbol(math, main, mathord, "\u03c2", "\\varsigma");
514
+ defineSymbol(math, main, mathord, "\u03c6", "\\varphi");
515
+ defineSymbol(math, main, bin, "\u2217", "*");
516
+ defineSymbol(math, main, bin, "+", "+");
517
+ defineSymbol(math, main, bin, "\u2212", "-");
518
+ defineSymbol(math, main, bin, "\u22c5", "\\cdot");
519
+ defineSymbol(math, main, bin, "\u2218", "\\circ");
520
+ defineSymbol(math, main, bin, "\u00f7", "\\div");
521
+ defineSymbol(math, main, bin, "\u00b1", "\\pm");
522
+ defineSymbol(math, main, bin, "\u00d7", "\\times");
523
+ defineSymbol(math, main, bin, "\u2229", "\\cap");
524
+ defineSymbol(math, main, bin, "\u222a", "\\cup");
525
+ defineSymbol(math, main, bin, "\u2216", "\\setminus");
526
+ defineSymbol(math, main, bin, "\u2227", "\\land");
527
+ defineSymbol(math, main, bin, "\u2228", "\\lor");
528
+ defineSymbol(math, main, bin, "\u2227", "\\wedge");
529
+ defineSymbol(math, main, bin, "\u2228", "\\vee");
530
+ defineSymbol(math, main, textord, "\u221a", "\\surd");
531
+ defineSymbol(math, main, open, "(", "(");
532
+ defineSymbol(math, main, open, "[", "[");
533
+ defineSymbol(math, main, open, "\u27e8", "\\langle");
534
+ defineSymbol(math, main, open, "\u2223", "\\lvert");
535
+ defineSymbol(math, main, open, "\u2225", "\\lVert");
536
+ defineSymbol(math, main, close, ")", ")");
537
+ defineSymbol(math, main, close, "]", "]");
538
+ defineSymbol(math, main, close, "?", "?");
539
+ defineSymbol(math, main, close, "!", "!");
540
+ defineSymbol(math, main, close, "\u27e9", "\\rangle");
541
+ defineSymbol(math, main, close, "\u2223", "\\rvert");
542
+ defineSymbol(math, main, close, "\u2225", "\\rVert");
543
+ defineSymbol(math, main, rel, "=", "=");
544
+ defineSymbol(math, main, rel, "<", "<");
545
+ defineSymbol(math, main, rel, ">", ">");
546
+ defineSymbol(math, main, rel, ":", ":");
547
+ defineSymbol(math, main, rel, "\u2248", "\\approx");
548
+ defineSymbol(math, main, rel, "\u2245", "\\cong");
549
+ defineSymbol(math, main, rel, "\u2265", "\\ge");
550
+ defineSymbol(math, main, rel, "\u2265", "\\geq");
551
+ defineSymbol(math, main, rel, "\u2190", "\\gets");
552
+ defineSymbol(math, main, rel, ">", "\\gt");
553
+ defineSymbol(math, main, rel, "\u2208", "\\in");
554
+ defineSymbol(math, main, rel, "\u2209", "\\notin");
555
+ defineSymbol(math, main, rel, "\u2282", "\\subset");
556
+ defineSymbol(math, main, rel, "\u2283", "\\supset");
557
+ defineSymbol(math, main, rel, "\u2286", "\\subseteq");
558
+ defineSymbol(math, main, rel, "\u2287", "\\supseteq");
559
+ defineSymbol(math, ams, rel, "\u2288", "\\nsubseteq");
560
+ defineSymbol(math, ams, rel, "\u2289", "\\nsupseteq");
561
+ defineSymbol(math, main, rel, "\u22a8", "\\models");
562
+ defineSymbol(math, main, rel, "\u2190", "\\leftarrow");
563
+ defineSymbol(math, main, rel, "\u2264", "\\le");
564
+ defineSymbol(math, main, rel, "\u2264", "\\leq");
565
+ defineSymbol(math, main, rel, "<", "\\lt");
566
+ defineSymbol(math, main, rel, "\u2260", "\\ne");
567
+ defineSymbol(math, main, rel, "\u2260", "\\neq");
568
+ defineSymbol(math, main, rel, "\u2192", "\\rightarrow");
569
+ defineSymbol(math, main, rel, "\u2192", "\\to");
570
+ defineSymbol(math, ams, rel, "\u2271", "\\ngeq");
571
+ defineSymbol(math, ams, rel, "\u2270", "\\nleq");
572
+ defineSymbol(math, main, spacing, null, "\\!");
573
+ defineSymbol(math, main, spacing, "\u00a0", "\\ ");
574
+ defineSymbol(math, main, spacing, "\u00a0", "~");
575
+ defineSymbol(math, main, spacing, null, "\\,");
576
+ defineSymbol(math, main, spacing, null, "\\:");
577
+ defineSymbol(math, main, spacing, null, "\\;");
578
+ defineSymbol(math, main, spacing, null, "\\enspace");
579
+ defineSymbol(math, main, spacing, null, "\\qquad");
580
+ defineSymbol(math, main, spacing, null, "\\quad");
581
+ defineSymbol(math, main, spacing, "\u00a0", "\\space");
582
+ defineSymbol(math, main, punct, ",", ",");
583
+ defineSymbol(math, main, punct, ";", ";");
584
+ defineSymbol(math, main, punct, ":", "\\colon");
585
+ defineSymbol(math, ams, bin, "\u22bc", "\\barwedge");
586
+ defineSymbol(math, ams, bin, "\u22bb", "\\veebar");
587
+ defineSymbol(math, main, bin, "\u2299", "\\odot");
588
+ defineSymbol(math, main, bin, "\u2295", "\\oplus");
589
+ defineSymbol(math, main, bin, "\u2297", "\\otimes");
590
+ defineSymbol(math, main, textord, "\u2202", "\\partial");
591
+ defineSymbol(math, main, bin, "\u2298", "\\oslash");
592
+ defineSymbol(math, ams, bin, "\u229a", "\\circledcirc");
593
+ defineSymbol(math, ams, bin, "\u22a1", "\\boxdot");
594
+ defineSymbol(math, main, bin, "\u25b3", "\\bigtriangleup");
595
+ defineSymbol(math, main, bin, "\u25bd", "\\bigtriangledown");
596
+ defineSymbol(math, main, bin, "\u2020", "\\dagger");
597
+ defineSymbol(math, main, bin, "\u22c4", "\\diamond");
598
+ defineSymbol(math, main, bin, "\u22c6", "\\star");
599
+ defineSymbol(math, main, bin, "\u25c3", "\\triangleleft");
600
+ defineSymbol(math, main, bin, "\u25b9", "\\triangleright");
601
+ defineSymbol(math, main, open, "{", "\\{");
602
+ defineSymbol(math, main, close, "}", "\\}");
603
+ defineSymbol(math, main, open, "{", "\\lbrace");
604
+ defineSymbol(math, main, close, "}", "\\rbrace");
605
+ defineSymbol(math, main, open, "[", "\\lbrack");
606
+ defineSymbol(math, main, close, "]", "\\rbrack");
607
+ defineSymbol(math, main, open, "\u230a", "\\lfloor");
608
+ defineSymbol(math, main, close, "\u230b", "\\rfloor");
609
+ defineSymbol(math, main, open, "\u2308", "\\lceil");
610
+ defineSymbol(math, main, close, "\u2309", "\\rceil");
611
+ defineSymbol(math, main, textord, "\\", "\\backslash");
612
+ defineSymbol(math, main, textord, "\u2223", "|");
613
+ defineSymbol(math, main, textord, "\u2223", "\\vert");
614
+ defineSymbol(math, main, textord, "\u2225", "\\|");
615
+ defineSymbol(math, main, textord, "\u2225", "\\Vert");
616
+ defineSymbol(math, main, rel, "\u2191", "\\uparrow");
617
+ defineSymbol(math, main, rel, "\u21d1", "\\Uparrow");
618
+ defineSymbol(math, main, rel, "\u2193", "\\downarrow");
619
+ defineSymbol(math, main, rel, "\u21d3", "\\Downarrow");
620
+ defineSymbol(math, main, rel, "\u2195", "\\updownarrow");
621
+ defineSymbol(math, main, rel, "\u21d5", "\\Updownarrow");
622
+ defineSymbol(math, math, op, "\u2210", "\\coprod");
623
+ defineSymbol(math, math, op, "\u22c1", "\\bigvee");
624
+ defineSymbol(math, math, op, "\u22c0", "\\bigwedge");
625
+ defineSymbol(math, math, op, "\u2a04", "\\biguplus");
626
+ defineSymbol(math, math, op, "\u22c2", "\\bigcap");
627
+ defineSymbol(math, math, op, "\u22c3", "\\bigcup");
628
+ defineSymbol(math, math, op, "\u222b", "\\int");
629
+ defineSymbol(math, math, op, "\u222b", "\\intop");
630
+ defineSymbol(math, math, op, "\u222c", "\\iint");
631
+ defineSymbol(math, math, op, "\u222d", "\\iiint");
632
+ defineSymbol(math, math, op, "\u220f", "\\prod");
633
+ defineSymbol(math, math, op, "\u2211", "\\sum");
634
+
635
+ defineSymbol(math, math, op, "\u2a02", "\\bigotimes");
636
+ defineSymbol(math, math, op, "\u2a01", "\\bigoplus");
637
+ defineSymbol(math, math, op, "\u2a00", "\\bigodot");
638
+ defineSymbol(math, math, op, "\u222e", "\\oint");
639
+ defineSymbol(math, math, op, "\u2a06", "\\bigsqcup");
640
+ defineSymbol(math, math, op, "\u222b", "\\smallint");
641
+ defineSymbol(math, main, inner, "\u2026", "\\ldots");
642
+ defineSymbol(math, main, inner, "\u22ef", "\\cdots");
643
+ defineSymbol(math, main, inner, "\u22f1", "\\ddots");
644
+ defineSymbol(math, main, textord, "\u22ee", "\\vdots");
645
+ defineSymbol(math, main, accent, "\u00b4", "\\acute");
646
+ defineSymbol(math, main, accent, "\u0060", "\\grave");
647
+ defineSymbol(math, main, accent, "\u00a8", "\\ddot");
648
+ defineSymbol(math, main, accent, "\u007e", "\\tilde");
649
+ defineSymbol(math, main, accent, "\u00af", "\\bar");
650
+ defineSymbol(math, main, accent, "\u02d8", "\\breve");
651
+ defineSymbol(math, main, accent, "\u02c7", "\\check");
652
+ defineSymbol(math, main, accent, "\u005e", "\\hat");
653
+ defineSymbol(math, main, accent, "\u20d7", "\\vec");
654
+ defineSymbol(math, main, accent, "\u02d9", "\\dot");
655
+ defineSymbol(math, main, mathord, "\u0131", "\\imath");
656
+ defineSymbol(math, main, mathord, "\u0237", "\\jmath");
657
+
658
+
659
+ defineSymbol(text, main, spacing, "\u00a0", "\\ ");
660
+ defineSymbol(text, main, spacing, "\u00a0", " ");
661
+ defineSymbol(text, main, spacing, "\u00a0", "~");
662
+
663
+ // There are lots of symbols which are the same, so we add them in afterwards.
664
+ var i;
665
+ var ch;
666
+
667
+ // All of these are textords in math mode
668
+ var mathTextSymbols = "0123456789/@.\"";
669
+ for (i = 0; i < mathTextSymbols.length; i++) {
670
+ ch = mathTextSymbols.charAt(i);
671
+ defineSymbol(math, main, textord, ch, ch);
672
+ }
673
+
674
+ // All of these are textords in text mode
675
+ var textSymbols = "0123456789`!@*()-=+[]'\";:?/.,";
676
+ for (i = 0; i < textSymbols.length; i++) {
677
+ ch = textSymbols.charAt(i);
678
+ defineSymbol(text, main, textord, ch, ch);
679
+ }
680
+
681
+ // All of these are textords in text mode, and mathords in math mode
682
+ var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
683
+ for (i = 0; i < letters.length; i++) {
684
+ ch = letters.charAt(i);
685
+ defineSymbol(math, main, mathord, ch, ch);
686
+ defineSymbol(text, main, textord, ch, ch);
687
+ }
katex/src/utils.js ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This file contains a list of utility functions which are useful in other
3
+ * files.
4
+ */
5
+
6
+ /**
7
+ * Provide an `indexOf` function which works in IE8, but defers to native if
8
+ * possible.
9
+ */
10
+ var nativeIndexOf = Array.prototype.indexOf;
11
+ var indexOf = function(list, elem) {
12
+ if (list == null) {
13
+ return -1;
14
+ }
15
+ if (nativeIndexOf && list.indexOf === nativeIndexOf) {
16
+ return list.indexOf(elem);
17
+ }
18
+ var i = 0;
19
+ var l = list.length;
20
+ for (; i < l; i++) {
21
+ if (list[i] === elem) {
22
+ return i;
23
+ }
24
+ }
25
+ return -1;
26
+ };
27
+
28
+ /**
29
+ * Return whether an element is contained in a list
30
+ */
31
+ var contains = function(list, elem) {
32
+ return indexOf(list, elem) !== -1;
33
+ };
34
+
35
+ /**
36
+ * Provide a default value if a setting is undefined
37
+ */
38
+ var deflt = function(setting, defaultIfUndefined) {
39
+ return setting === undefined ? defaultIfUndefined : setting;
40
+ };
41
+
42
+ // hyphenate and escape adapted from Facebook's React under Apache 2 license
43
+
44
+ var uppercase = /([A-Z])/g;
45
+ var hyphenate = function(str) {
46
+ return str.replace(uppercase, "-$1").toLowerCase();
47
+ };
48
+
49
+ var ESCAPE_LOOKUP = {
50
+ "&": "&amp;",
51
+ ">": "&gt;",
52
+ "<": "&lt;",
53
+ "\"": "&quot;",
54
+ "'": "&#x27;",
55
+ };
56
+
57
+ var ESCAPE_REGEX = /[&><"']/g;
58
+
59
+ function escaper(match) {
60
+ return ESCAPE_LOOKUP[match];
61
+ }
62
+
63
+ /**
64
+ * Escapes text to prevent scripting attacks.
65
+ *
66
+ * @param {*} text Text value to escape.
67
+ * @return {string} An escaped string.
68
+ */
69
+ function escape(text) {
70
+ return ("" + text).replace(ESCAPE_REGEX, escaper);
71
+ }
72
+
73
+ /**
74
+ * A function to set the text content of a DOM element in all supported
75
+ * browsers. Note that we don't define this if there is no document.
76
+ */
77
+ var setTextContent;
78
+ if (typeof document !== "undefined") {
79
+ var testNode = document.createElement("span");
80
+ if ("textContent" in testNode) {
81
+ setTextContent = function(node, text) {
82
+ node.textContent = text;
83
+ };
84
+ } else {
85
+ setTextContent = function(node, text) {
86
+ node.innerText = text;
87
+ };
88
+ }
89
+ }
90
+
91
+ /**
92
+ * A function to clear a node.
93
+ */
94
+ function clearNode(node) {
95
+ setTextContent(node, "");
96
+ }
97
+
98
+ module.exports = {
99
+ contains: contains,
100
+ deflt: deflt,
101
+ escape: escape,
102
+ hyphenate: hyphenate,
103
+ indexOf: indexOf,
104
+ setTextContent: setTextContent,
105
+ clearNode: clearNode,
106
+ };
match-at/README.md ADDED
@@ -0,0 +1 @@
 
 
1
+ # match-at [![Build Status](https://travis-ci.org/spicyj/match-at.svg?branch=master)](https://travis-ci.org/spicyj/match-at)
match-at/lib/__tests__/matchAt-test.js ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+
3
+ describe("matchAt", function () {
4
+
5
+ var matchAt;
6
+
7
+ beforeEach(function () {
8
+ matchAt = require("../matchAt.js");
9
+ });
10
+
11
+ it("matches a simple regex", function () {
12
+ expect(matchAt(/l/, "hello", 0)).toBe(null);
13
+ expect(matchAt(/l/, "hello", 1)).toBe(null);
14
+ expect(matchAt(/l/, "hello", 4)).toBe(null);
15
+ expect(matchAt(/l/, "hello", 5)).toBe(null);
16
+
17
+ var match = matchAt(/l/, "hello", 2);
18
+ expect(Array.isArray(match)).toBe(true);
19
+ expect(match.index).toBe(2);
20
+ expect(match.input).toBe("hello");
21
+ expect(match[0]).toBe("l");
22
+ expect(match[1]).toBe(undefined);
23
+ expect(match.length).toBe(1);
24
+
25
+ var match = matchAt(/l/, "hello", 3);
26
+ expect(Array.isArray(match)).toBe(true);
27
+ expect(match.index).toBe(3);
28
+ expect(match.input).toBe("hello");
29
+ expect(match[0]).toBe("l");
30
+ expect(match[1]).toBe(undefined);
31
+ expect(match.length).toBe(1);
32
+ });
33
+
34
+ it("matches a zero-length regex", function () {
35
+ expect(matchAt(/(?=l)/, "hello", 0)).toBe(null);
36
+ expect(matchAt(/(?=l)/, "hello", 1)).toBe(null);
37
+ expect(matchAt(/(?=l)/, "hello", 4)).toBe(null);
38
+ expect(matchAt(/(?=l)/, "hello", 5)).toBe(null);
39
+
40
+ var match = matchAt(/(?=l)/, "hello", 2);
41
+ expect(Array.isArray(match)).toBe(true);
42
+ expect(match.index).toBe(2);
43
+ expect(match.input).toBe("hello");
44
+ expect(match[0]).toBe("");
45
+ expect(match[1]).toBe(undefined);
46
+ expect(match.length).toBe(1);
47
+
48
+ var match = matchAt(/(?=l)/, "hello", 3);
49
+ expect(Array.isArray(match)).toBe(true);
50
+ expect(match.index).toBe(3);
51
+ expect(match.input).toBe("hello");
52
+ expect(match[0]).toBe("");
53
+ expect(match[1]).toBe(undefined);
54
+ expect(match.length).toBe(1);
55
+ });
56
+
57
+ it("matches a regex with capturing groups", function () {
58
+ expect(matchAt(/(l)(l)?/, "hello", 0)).toBe(null);
59
+ expect(matchAt(/(l)(l)?/, "hello", 1)).toBe(null);
60
+ expect(matchAt(/(l)(l)?/, "hello", 4)).toBe(null);
61
+ expect(matchAt(/(l)(l)?/, "hello", 5)).toBe(null);
62
+
63
+ var match = matchAt(/(l)(l)?/, "hello", 2);
64
+ expect(Array.isArray(match)).toBe(true);
65
+ expect(match.index).toBe(2);
66
+ expect(match.input).toBe("hello");
67
+ expect(match[0]).toBe("ll");
68
+ expect(match[1]).toBe("l");
69
+ expect(match[2]).toBe("l");
70
+ expect(match.length).toBe(3);
71
+
72
+ var match = matchAt(/(l)(l)?/, "hello", 3);
73
+ expect(Array.isArray(match)).toBe(true);
74
+ expect(match.index).toBe(3);
75
+ expect(match.input).toBe("hello");
76
+ expect(match[0]).toBe("l");
77
+ expect(match[1]).toBe("l");
78
+ expect(match[2]).toBe(undefined);
79
+ expect(match.length).toBe(3);
80
+ });
81
+
82
+ it("copies flags over", function () {
83
+ expect(matchAt(/L/i, "hello", 0)).toBe(null);
84
+ expect(matchAt(/L/i, "hello", 1)).toBe(null);
85
+ expect(matchAt(/L/i, "hello", 2)).not.toBe(null);
86
+ expect(matchAt(/L/i, "hello", 3)).not.toBe(null);
87
+ expect(matchAt(/L/i, "hello", 4)).toBe(null);
88
+ expect(matchAt(/L/i, "hello", 5)).toBe(null);
89
+ });
90
+ });
match-at/lib/matchAt.js ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @flow */
2
+
3
+ "use strict";
4
+
5
+ function getRelocatable(re) {
6
+ // In the future, this could use a WeakMap instead of an expando.
7
+ if (!re.__matchAtRelocatable) {
8
+ // Disjunctions are the lowest-precedence operator, so we can make any
9
+ // pattern match the empty string by appending `|()` to it:
10
+ // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-patterns
11
+ var source = re.source + "|()";
12
+
13
+ // We always make the new regex global.
14
+ var flags = "g" + (re.ignoreCase ? "i" : "") + (re.multiline ? "m" : "") + (re.unicode ? "u" : "")
15
+ // sticky (/.../y) doesn't make sense in conjunction with our relocation
16
+ // logic, so we ignore it here.
17
+ ;
18
+
19
+ re.__matchAtRelocatable = new RegExp(source, flags);
20
+ }
21
+ return re.__matchAtRelocatable;
22
+ }
23
+
24
+ function matchAt(re, str, pos) {
25
+ if (re.global || re.sticky) {
26
+ throw new Error("matchAt(...): Only non-global regexes are supported");
27
+ }
28
+ var reloc = getRelocatable(re);
29
+ reloc.lastIndex = pos;
30
+ var match = reloc.exec(str);
31
+ // Last capturing group is our sentinel that indicates whether the regex
32
+ // matched at the given location.
33
+ if (match[match.length - 1] == null) {
34
+ // Original regex matched.
35
+ match.length = match.length - 1;
36
+ return match;
37
+ } else {
38
+ return null;
39
+ }
40
+ }
41
+
42
+ module.exports = matchAt;
match-at/package.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "match-at",
3
+ "version": "0.1.0",
4
+ "description": "Relocatable regular expressions.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/spicyj/match-at"
8
+ },
9
+ "main": "lib/matchAt.js",
10
+ "files": [
11
+ "lib/"
12
+ ],
13
+ "devDependencies": {
14
+ "babel": "^4.7.16",
15
+ "jest-cli": "^0.4.0",
16
+ "react-tools": "^0.13.1"
17
+ },
18
+ "jest": {
19
+ "scriptPreprocessor": "<rootDir>/jestSupport/preprocessor.js",
20
+ "unmockedModulePathPatterns": [
21
+ ""
22
+ ]
23
+ },
24
+ "scripts": {
25
+ "prepublish": "babel -d lib/ src/",
26
+ "test": "jest"
27
+ },
28
+ "gitHead": "4197daff69720734c72ba3321ed68a41c0527fb2",
29
+ "bugs": {
30
+ "url": "https://github.com/spicyj/match-at/issues"
31
+ },
32
+ "homepage": "https://github.com/spicyj/match-at",
33
+ "_id": "match-at@0.1.0",
34
+ "_shasum": "f561e7709ff9a105b85cc62c6b8ee7c15bf24f31",
35
+ "_from": "match-at@",
36
+ "_npmVersion": "2.2.0",
37
+ "_nodeVersion": "0.10.35",
38
+ "_npmUser": {
39
+ "name": "spicyj",
40
+ "email": "ben@benalpert.com"
41
+ },
42
+ "maintainers": [
43
+ {
44
+ "name": "spicyj",
45
+ "email": "ben@benalpert.com"
46
+ }
47
+ ],
48
+ "dist": {
49
+ "shasum": "f561e7709ff9a105b85cc62c6b8ee7c15bf24f31",
50
+ "tarball": "https://registry.npmjs.org/match-at/-/match-at-0.1.0.tgz"
51
+ },
52
+ "directories": {},
53
+ "_resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.0.tgz"
54
+ }
preprocess_latex.js ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var katex = require("./katex/katex.js")
2
+ options = require("./katex/src/Options.js")
3
+ var readline = require('readline');
4
+ var rl = readline.createInterface({
5
+ input: process.stdin,
6
+ output: process.stdout,
7
+ terminal: false
8
+ });
9
+
10
+
11
+ rl.on('line', function(line){
12
+ a = line
13
+ if (line[0] == "%") {
14
+ line = line.substr(1, line.length - 1);
15
+ }
16
+ line = line.split('%')[0];
17
+
18
+ line = line.split('\\~').join(' ');
19
+
20
+ for (var i = 0; i < 300; i++) {
21
+ line = line.replace(/\\>/, " ");
22
+ line = line.replace('$', ' ');
23
+ line = line.replace(/\\label{.*?}/, "");
24
+ }
25
+
26
+ if (line.indexOf("matrix") == -1 && line.indexOf("cases")==-1 &&
27
+ line.indexOf("array")==-1 && line.indexOf("begin")==-1) {
28
+ for (var i = 0; i < 300; i++) {
29
+ line = line.replace(/\\\\/, "\\,");
30
+ }
31
+ }
32
+
33
+
34
+ line = line + " "
35
+ // global_str is tokenized version (build in parser.js)
36
+ // norm_str is normalized version build by renderer below.
37
+ //Yuntiantry {
38
+
39
+
40
+ if (process.argv[2] == "tokenize") {
41
+ var tree = katex.__parse(line, {});
42
+ console.log(global_str.replace(/\\label { .*? }/, ""));
43
+ } else {
44
+ for (var i = 0; i < 300; ++i) {
45
+ line = line.replace(/{\\rm/, "\\mathrm{");
46
+ line = line.replace(/{ \\rm/, "\\mathrm{");
47
+ line = line.replace(/\\rm{/, "\\mathrm{");
48
+ }
49
+
50
+ var tree = katex.__parse(line, {});
51
+ buildExpression(tree, new options({}));
52
+ for (var i = 0; i < 300; ++i) {
53
+ norm_str = norm_str.replace('SSSSSS', '$');
54
+ norm_str = norm_str.replace(' S S S S S S', '$');
55
+ }
56
+ console.log(norm_str.replace(/\\label { .*? }/, ""));
57
+ }
58
+ //} catch (e) {
59
+ // console.error(line);
60
+ // console.error(norm_str);
61
+ // console.error(e);
62
+ // console.log("");
63
+ //}
64
+ global_str = ""
65
+ norm_str = ""
66
+ })
67
+
68
+
69
+
70
+ // This is a LaTeX AST to LaTeX Renderer (modified version of KaTeX AST-> MathML).
71
+ norm_str = ""
72
+
73
+ var groupTypes = {};
74
+
75
+ groupTypes.mathord = function(group, options) {
76
+ if (options.font == "mathrm"){
77
+ for (i = 0; i < group.value.length; ++i ) {
78
+ if (group.value[i] == " ") {
79
+ norm_str = norm_str + group.value[i] + "\; ";
80
+ } else {
81
+ norm_str = norm_str + group.value[i] + " ";
82
+ }
83
+ }
84
+ } else {
85
+ norm_str = norm_str + group.value + " ";
86
+ }
87
+ };
88
+
89
+ groupTypes.textord = function(group, options) {
90
+ norm_str = norm_str + group.value + " ";
91
+ };
92
+
93
+ groupTypes.bin = function(group) {
94
+ norm_str = norm_str + group.value + " ";
95
+ };
96
+
97
+ groupTypes.rel = function(group) {
98
+ norm_str = norm_str + group.value + " ";
99
+ };
100
+
101
+ groupTypes.open = function(group) {
102
+ norm_str = norm_str + group.value + " ";
103
+ };
104
+
105
+ groupTypes.close = function(group) {
106
+ norm_str = norm_str + group.value + " ";
107
+ };
108
+
109
+ groupTypes.inner = function(group) {
110
+ norm_str = norm_str + group.value + " ";
111
+ };
112
+
113
+ groupTypes.punct = function(group) {
114
+ norm_str = norm_str + group.value + " ";
115
+ };
116
+
117
+ groupTypes.ordgroup = function(group, options) {
118
+ norm_str = norm_str + "{ ";
119
+
120
+ buildExpression(group.value, options);
121
+
122
+ norm_str = norm_str + "} ";
123
+ };
124
+
125
+ groupTypes.text = function(group, options) {
126
+
127
+ norm_str = norm_str + "\\mathrm { ";
128
+
129
+ buildExpression(group.value.body, options);
130
+ norm_str = norm_str + "} ";
131
+ };
132
+
133
+ groupTypes.color = function(group, options) {
134
+ var inner = buildExpression(group.value.value, options);
135
+
136
+ var node = new mathMLTree.MathNode("mstyle", inner);
137
+
138
+ node.setAttribute("mathcolor", group.value.color);
139
+
140
+ return node;
141
+ };
142
+
143
+ groupTypes.supsub = function(group, options) {
144
+ buildGroup(group.value.base, options);
145
+
146
+ if (group.value.sub) {
147
+ norm_str = norm_str + "_ ";
148
+ if (group.value.sub.type != 'ordgroup') {
149
+ norm_str = norm_str + " { ";
150
+ buildGroup(group.value.sub, options);
151
+ norm_str = norm_str + "} ";
152
+ } else {
153
+ buildGroup(group.value.sub, options);
154
+ }
155
+
156
+ }
157
+
158
+ if (group.value.sup) {
159
+ norm_str = norm_str + "^ ";
160
+ if (group.value.sup.type != 'ordgroup') {
161
+ norm_str = norm_str + " { ";
162
+ buildGroup(group.value.sup, options);
163
+ norm_str = norm_str + "} ";
164
+ } else {
165
+ buildGroup(group.value.sup, options);
166
+ }
167
+ }
168
+
169
+ };
170
+
171
+ groupTypes.genfrac = function(group, options) {
172
+ if (!group.value.hasBarLine) {
173
+ norm_str = norm_str + "\\binom ";
174
+ } else {
175
+ norm_str = norm_str + "\\frac ";
176
+ }
177
+ buildGroup(group.value.numer, options);
178
+ buildGroup(group.value.denom, options);
179
+
180
+ };
181
+
182
+ groupTypes.array = function(group, options) {
183
+ norm_str = norm_str + "\\begin{" + group.value.style + "} ";
184
+
185
+ if (group.value.style == "array" || group.value.style == "tabular") {
186
+ norm_str = norm_str + "{ ";
187
+ if (group.value.cols) {
188
+ group.value.cols.map(function(start) {
189
+ if (start) {
190
+ if (start.type == "align") {
191
+ norm_str = norm_str + start.align + " ";
192
+ } else if (start.type == "separator") {
193
+ norm_str = norm_str + start.separator + " ";
194
+ }
195
+ }
196
+ });
197
+ } else {
198
+ group.value.body[0].map(function(start) {
199
+ norm_str = norm_str + "c ";
200
+ } );
201
+ }
202
+ norm_str = norm_str + "} ";
203
+ }
204
+ group.value.body.map(function(row) {
205
+ if (row.length > 1 || row[0].value.length > 0) {
206
+ if (row[0].value[0] && row[0].value[0].value == "\\hline") {
207
+ norm_str = norm_str + "\\hline ";
208
+ row[0].value = row[0].value.slice(1);
209
+ }
210
+ out = row.map(function(cell) {
211
+ buildGroup(cell, options);
212
+ norm_str = norm_str + "& ";
213
+ });
214
+ norm_str = norm_str.substring(0, norm_str.length-2) + "\\\\ ";
215
+ }
216
+ });
217
+ norm_str = norm_str + "\\end{" + group.value.style + "} ";
218
+ };
219
+
220
+ groupTypes.sqrt = function(group, options) {
221
+ var node;
222
+ if (group.value.index) {
223
+ norm_str = norm_str + "\\sqrt [ " + group.value.index + " ] ";
224
+ buildGroup(group.value.body, options);
225
+ } else {
226
+ norm_str = norm_str + "\\sqrt ";
227
+ buildGroup(group.value.body, options);
228
+ }
229
+ };
230
+
231
+ groupTypes.leftright = function(group, options) {
232
+
233
+
234
+
235
+ norm_str = norm_str + "\\left" + group.value.left + " ";
236
+ buildExpression(group.value.body, options);
237
+ norm_str = norm_str + "\\right" + group.value.right + " ";
238
+ };
239
+
240
+ groupTypes.accent = function(group, options) {
241
+ if (group.value.base.type != 'ordgroup') {
242
+ norm_str = norm_str + group.value.accent + " { ";
243
+ buildGroup(group.value.base, options);
244
+ norm_str = norm_str + "} ";
245
+ } else {
246
+ norm_str = norm_str + group.value.accent + " ";
247
+ buildGroup(group.value.base, options);
248
+ }
249
+ };
250
+
251
+ groupTypes.spacing = function(group) {
252
+ var node;
253
+ if (group.value == " ") {
254
+ norm_str = norm_str + "~ ";
255
+ } else {
256
+ norm_str = norm_str + group.value + " ";
257
+ }
258
+ return node;
259
+ };
260
+
261
+ groupTypes.op = function(group) {
262
+ var node;
263
+
264
+ // TODO(emily): handle big operators using the `largeop` attribute
265
+
266
+
267
+ if (group.value.symbol) {
268
+ // This is a symbol. Just add the symbol.
269
+ norm_str = norm_str + group.value.body + " ";
270
+
271
+ } else {
272
+ if (group.value.limits == false) {
273
+ norm_str = norm_str + "\\\operatorname { ";
274
+ } else {
275
+ norm_str = norm_str + "\\\operatorname* { ";
276
+ }
277
+ for (i = 1; i < group.value.body.length; ++i ) {
278
+ norm_str = norm_str + group.value.body[i] + " ";
279
+ }
280
+ norm_str = norm_str + "} ";
281
+ }
282
+ };
283
+
284
+ groupTypes.katex = function(group) {
285
+ var node = new mathMLTree.MathNode(
286
+ "mtext", [new mathMLTree.TextNode("KaTeX")]);
287
+
288
+ return node;
289
+ };
290
+
291
+
292
+
293
+ groupTypes.font = function(group, options) {
294
+ var font = group.value.font;
295
+ if (font == "mbox" || font == "hbox") {
296
+ font = "mathrm";
297
+ }
298
+ norm_str = norm_str + "\\" + font + " ";
299
+ buildGroup(group.value.body, options.withFont(font));
300
+ };
301
+
302
+ groupTypes.delimsizing = function(group) {
303
+ var children = [];
304
+ norm_str = norm_str + group.value.funcName + " " + group.value.value + " ";
305
+ };
306
+
307
+ groupTypes.styling = function(group, options) {
308
+ norm_str = norm_str + " " + group.value.original + " ";
309
+ buildExpression(group.value.value, options);
310
+
311
+ };
312
+
313
+ groupTypes.sizing = function(group, options) {
314
+
315
+ if (group.value.original == "\\rm") {
316
+ norm_str = norm_str + "\\mathrm { ";
317
+ buildExpression(group.value.value, options.withFont("mathrm"));
318
+ norm_str = norm_str + "} ";
319
+ } else {
320
+ norm_str = norm_str + " " + group.value.original + " ";
321
+ buildExpression(group.value.value, options);
322
+ }
323
+ };
324
+
325
+ groupTypes.overline = function(group, options) {
326
+ norm_str = norm_str + "\\overline { ";
327
+
328
+ buildGroup(group.value.body, options);
329
+ norm_str = norm_str + "} ";
330
+ norm_str = norm_str;
331
+
332
+ };
333
+
334
+ groupTypes.underline = function(group, options) {
335
+ norm_str = norm_str + "\\underline { ";
336
+ buildGroup(group.value.body, options);
337
+ norm_str = norm_str + "} ";
338
+
339
+ norm_str = norm_str;
340
+
341
+ };
342
+
343
+ groupTypes.rule = function(group) {
344
+ norm_str = norm_str + "\\rule { "+group.value.width.number+" "+group.value.width.unit+" } { "+group.value.height.number+" "+group.value.height.unit+ " } ";
345
+
346
+ };
347
+
348
+ groupTypes.llap = function(group, options) {
349
+ norm_str = norm_str + "\\llap ";
350
+ buildGroup(group.value.body, options);
351
+ };
352
+
353
+ groupTypes.rlap = function(group, options) {
354
+ norm_str = norm_str + "\\rlap ";
355
+ buildGroup(group.value.body, options);
356
+
357
+ };
358
+
359
+ groupTypes.phantom = function(group, options, prev) {
360
+ norm_str = norm_str + "\\phantom { ";
361
+ buildExpression(group.value.value, options);
362
+ norm_str = norm_str + "} ";
363
+
364
+ };
365
+
366
+ /**
367
+ * Takes a list of nodes, builds them, and returns a list of the generated
368
+ * MathML nodes. A little simpler than the HTML version because we don't do any
369
+ * previous-node handling.
370
+ */
371
+ var buildExpression = function(expression, options) {
372
+ var groups = [];
373
+ for (var i = 0; i < expression.length; i++) {
374
+ var group = expression[i];
375
+ buildGroup(group, options);
376
+ }
377
+ // console.log(norm_str);
378
+ // return groups;
379
+ };
380
+
381
+ /**
382
+ * Takes a group from the parser and calls the appropriate groupTypes function
383
+ * on it to produce a MathML node.
384
+ */
385
+ var buildGroup = function(group, options) {
386
+ if (groupTypes[group.type]) {
387
+ groupTypes[group.type](group, options);
388
+ } else {
389
+ throw new ParseError(
390
+ "Got group of unknown type: '" + group.type + "'");
391
+ }
392
+ };
393
+
394
+
395
+