diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index a0a65c66..00000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -contrib/auto-render/test/*.js -src/autocorrect.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 0511c021..00000000 --- a/.eslintrc +++ /dev/null @@ -1,73 +0,0 @@ -{ - "extends": [ - "eslint:recommended" - ], - "globals":{ - "BigInt":true - }, - "rules": { - "arrow-spacing": 2, - "brace-style": [2, "1tbs", { "allowSingleLine": true }], - "camelcase": [2, { "properties": "never" }], - "comma-dangle": [2, "never"], - "comma-spacing": [2, { "before": false, "after": true }], - "constructor-super": 2, - "curly": 2, - "eol-last": 2, - "eqeqeq": [2, "allow-null"], - "guard-for-in": 2, - "indent": "off", - "indent-legacy": [2, 2, {"SwitchCase": 1}], - "keyword-spacing": 2, - "linebreak-style": [2, "unix"], - "max-len": [2, 100, 4, { "ignoreUrls": true, "ignoreRegExpLiterals": true }], - "new-cap": 2, - "no-alert": 2, - "no-array-constructor": 2, - "no-console": 2, - "no-const-assign": 2, - "no-debugger": 2, - "no-dupe-class-members": 2, - "no-dupe-keys": 2, - "no-extra-bind": 2, - "no-misleading-character-class": 0, - "no-new": 2, - "no-new-func": 2, - "no-new-object": 2, - "no-spaced-func": 2, - "no-this-before-super": 2, - "no-throw-literal": 2, - "no-trailing-spaces": 2, - "no-undef": 2, - "no-unexpected-multiline": 2, - "no-unreachable": 2, - "no-unused-vars": [2, {"args": "none", "varsIgnorePattern": "^_*$"}], - "no-useless-call": 2, - "no-var": 2, - "no-with": 2, - "object-curly-spacing": [2, "always"], - "one-var": [2, "never"], - "prefer-const": 2, - "prefer-spread": 0, - "semi": 0, - "space-before-blocks": 2, - "space-before-function-paren": [2, "never"], - "space-infix-ops": 2, - "space-unary-ops": 2, - "prefer-template": 0, - "arrow-parens": 0, - "prefer-arrow-callback": 0, - "valid-jsdoc": 0, - "require-jsdoc": 0 - }, - "env": { - "node": true, - "browser": true, - "es6": true - }, - "parserOptions": { - "ecmaVersion": 8, - "sourceType": "module" - }, - "root": true -} diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 5dc46e6b..00000000 --- a/.gitattributes +++ /dev/null @@ -1,3 +0,0 @@ -* text=auto eol=lf -*.{cmd,[cC][mM][dD]} text eol=crlf -*.{bat,[bB][aA][tT]} text eol=crlf \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 30a6a350..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,366 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. This CHANGELOG roughly follows the guidelines from [keepachangelog.com](https://keepachangelog.com/en/1.0.0/). - -## [0.6.9] = 2022-06-11 - -### Fixed - -- Colors of lower-case color names -- `\surd` vertical alignment when rendered in Latin Modern - -## [0.6.8] = 2022-05-20 - -### Fixed - -- Avoid crash when mhchem \ce{} is empty -- Numerals in text mode - -### Added - -- Support Unicode (sub|superscript) characters - -## [0.6.7] = 2022-03-27 - -### Fixed - -- Added operator spacing to Unicode characters ∖∘∙ -- Avoid error when a spacing function is the base of a subscript. -- Fix nested font size changes -- Replace string.substr() with string.slice() -- Use Unicode U+203E, Overline, for \bar{} - -### Added - -- Support \strictif and \strictfi - -### Docs - -- Explain how to work around a Cambria Math radical size problem -- Edit README for brevity - -## [0.6.6] = 2022-01-28 - -### Fixed - -- Workaround a Firefox bug. Prevent space around a \mathrm{} function with a one-character argument. - -## [0.6.5] = 2022-01-20 - -### Added - -- 15 functions from the `cmll` package - -### Fixed - -- Omit color attribute and wrapper from \rule when unecessary - -## [0.6.4] = 2022-01-15 - -### Fixed - -- More improvement of recognition of delimiters after functions like \sin - -## [0.6.3] = 2022-01-14 - -### Fixed - -- Improve recognition of delimiters after functions like \sin - -## [0.6.2] = 2022-01-13 - -### Fixed - -- \bm{\sin} -- Remove spurious space between \sin (x) - -## [0.6.1] = 2022-01-12 - -### Fixed - -- \mathinner when part of a denominator - -## [0.6.0] = 2022-01-11 - -### Changed - -- In default Temml, Numbers are now consolidated into one element if they begin and end with a number and contain numerals, commas, or dots -- Some error messages are revised - -### Added - -- Documentation section regarding numbers - -## [0.5.3] = 2022-01-08 - -### Fixed - -- Suppress operator spacing between adjacent relations - -## [0.5.2] = 2022-01-07 - -### Fixed - -- \tag now stays in display mode - -### Changed - -- Parse error message now is displayed on screen, not in a hover hint. -- Added locations to some error messages. - -## [0.5.1] = 2022-01-05 - -### Fixed - -- \vcentcolon, \ratio - -## [0.5.0] = 2022-01-04 - -### Changed - -- Rendering option `maxSize` now takes an array of two numbers. - -### Added - -- \centerdot - -### Fixed - -- text-mode colon -- All unit tests now pass. -- All SVG images have been removed from Temml - -## [0.4.2] = 2021-12-24 - -### Fixed - -- \mathcal{ego} -- \not\operatorname -- \big\backslash and \right\backslash -- displaystyle \sideset -- := -- {cases} environment row spacing -- \varnothing -- math-mode \O and \o -- Greek edge cases of bold, italic, and sans-serif -- \shortmid, \nshortmid, \shortparallel, \nshortparallel, \smallsetminus -- non-stretchy accents (so they do not stretch) -- Make best effort to support Greek sans-serif - -### Added - -- \sgn - -## [0.4.1] = 2021-12-20 - -### Fixed - -- \bmod -- \colon spacing -- \right . -- \includegraphics -- \angle padding -- \subarray row spacing -- "/" spacing -- width of stacked harpoons -- operator spacing when adjacent to \color -- Improve laps -- Use character U+2044 for inline fractions -- Work around Firefox bug affecting \mathrlap -- \boldsymbol when it wraps an operator -- array environment enclosing lines -- \mathbf{\Omega} -- \mathop - -### Added - -- Copy button to home page. -- Images from LaTeX in KaTeX screenshotter tests -- Mozilla test suite -- mhchem test suite - -## [0.4.0] = 2021-12-06 - -### Changed - -- Remove \centerdot -- Remove \vcenter -- Remove \newextarrow -- Edit mhchem to sync w/extensible arrow fix. - -### Fixed - -- Prevent arrowhead distortion on extensible arrows -- Fix scriptstyle errors. -- Adjust RGB values of base colors. - -## [0.3.3] - 2021-11-24 - -### Added - -- Support \odv and \pdv from derivative package -- Rendering option `elementIsMath` - -### Changed - -- Make color names case-sensitive -- Use Unicode character U+212B for \AA - -### Fixed - -- Explicitly set stretchy="true" on delimiters to evade a Firefox bug -- Soft line breaks inside \color -- \mathbin that contains a - -## [0.3.2] - 2021-11-21 - -### Added - -- \definecolor -- Optional argument that sets the color model in color functions -- Predefined colors per Tables 4.1 and 4.2 in xcolor package -- \nsubset and \nsupset - -### Changed - -- Use character U+005F for \overline and \underline. Regain stretchiness. - -### Fixed - -- Spacing for \mid -- Workaround a Fireox bug for spacing of - -## [0.3.1] - 2021-11-15 - -### Added - -- Rendering option preventTagLap - -## [0.3.0] - 2021-11-12 - -### Removed - -- Support for \global, \gdef, and \xdef - -### Added - -- Preamble definition -- Support \nonumber -- STIX2 is now available on the home page - -### Fixed - -- Text mode accents in strict mode get only a console message, not an error. - -### Changed - -- Revert to macron character for \bar -- Change a font name from Temml-Script.woff2 to Temml.woff2. -- Change a folder name from /temml/ to /assets/. -- Documentation clarifies the current chancery/roundhand situation. - -## [0.2.3] - 2021-11-06 - -### Added - -- Support \ballotx -- Support \permil - -## [0.2.2] - 2021-11-04 - -### Added - -- Support \c -- Support \female and \male -- Support \relax -- Soft line breaks in Firefox, if no - -### Changed - -- element namespace is now optional -- elemennt w/TeX string is now optional -- Removed "temml" class from element -- Reduced number of visible DOM elements -- Support AMS environment w/one empty row -- \bar{} accent now uses character U+2015, horizontal bar - -### Fixed - -- Spaces inside \text{} -- \char now supports >16-bit Unicode characters -- \mathbb operating on numbers -- Circular dependency -- Stretchy arrow bug -- Validation errors in \mathop, \mathrel, and \operatorname - -## [0.2.1] - 2021-08-10 - -### Changed - -- Change CSS files. Each CSS file now is synchronized with a single math font. - -### Added - -- Support Asana and XITS fonts. -- Support \Braket, \Set, and \set. - -## [0.2.0] - 2021-08-02 - -### Removed - -- Soft line breaks, since they will not work in Chromium. - -### Fixed - -- Improve handling of \limits -- Improve handling of newline. -- Respect catcode in macro expansion and set ~ correctly. -- Improve \operatorname*. -- Fix non-stretchy accents in Firefox. -- Use correct Unicode for uppercase Greek. - -### Changed - -- Support font functions via substitution of Unicode characters instead of `mathvariant`. Font functions will now work in Chromium. -- Change \pmb to use CSS text-shadow instead of `mathvariant = bold`. - -### Added - -- Support \backcong. - -## [0.1.3] - 2021-05-21 - -### Fixed - -- Treat `\` followed by whitespace including up to one newline as equivalent to `\ `. -- Isolate `border-color` from page CSS. - -### Added - -- `\P` and `\S` in math mode. - -## [0.1.2] - 2021-02-18 - -### Fixed - -- Workaround for Firefox arrow minlength bug. - -### Removed - -- \overlinesegment & \underlinesegment - -## [0.1.1] - 2021-02-17 - -### Fixed - -- \overlinesegment & \underlinesegment SVGs - -### Changed - -- Removed Firefox browser sniff from CSS - -## [0.1.0] - 2021-02-01 - -### Added - -- Initial Release diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 676c8a47..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2020 Ron Kok - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 021b08a1..00000000 --- a/README.md +++ /dev/null @@ -1,44 +0,0 @@ -*Temml* is a LaTeX-to-MathML JavaScript conversion utility. It is built to be lightweight. - -| Library | Minified JavaScript + CSS | -|:--------------|:-------------------------:| -| Temml | 142 KB | -| MathJax 2.7.5 | 338 KB | -| KaTeX | 280 KB | -| TeXZilla | 168 KB | - -As a futher advantage, Temml can use local system fonts. The minimum Temml installation serves a font file that is only 12kb. - -When the [MathML-in-Chromium](https://mathml.igalia.com/news/) project is complete, all the major browsers will support MathML and Temml will become the most lightweight way to render math in a browser. - -Temml’s coverage of LaTeX functions is as good as MathJax, slightly better than KaTeX 0.13.0 and substantially better than TeXZilla. See a [detailed coverage comparison](https://temml.org/docs/en/comparison.html). - -Temml's [test](https://temml.org/docs/en/supported.html) suite [includes](https://temml.org/tests/mozilla-tests.html) many [rendered](https://temml.org/tests/wiki-tests.html) examples [that](https://temml.org/tests/mhchem-tests.html) are [available](https://temml.org/tests/LaTeXML-tests.html) for viewing. - -Temml's demonstration page is at https://temml.org/ - -Documentation can be found at: - -* [Installation](https://temml.org/docs/en/administration.html) - -* LaTeX function support, [sorted into logical groups](https://temml.org/docs/en/supported.html). - -* LaTeX function support, [sorted alphabetically](https://temml.org/docs/en/support_table.html). - -### Acknowledgements - -I built Temml by: - -1. Forking [KaTeX](https://katex.org/). - -2. Deleting half the code, removing the HTML parts and keeping the parser, the macro expander, and the MathML parts. - -3. Doing some code refactoring and many MathML bug fixes. - -4. Adding new functionality: upright lower-case Greek letters, `\euro`, `\label{…}`, `\ref{…}`, `\longdiv{…}`, `\prescript`, `\definecolor`, `xcolor` color names, etc. - -I wish to thank Khan Academy and the many volunteer KaTeX contributors. This library would not exist if KaTeX had not existed first. - ---- - -Temml is released under terms of the [MIT license](https://mit-license.org/) diff --git a/contrib/auto-render/README.md b/contrib/auto-render/README.md deleted file mode 100644 index db7a1276..00000000 --- a/contrib/auto-render/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# Auto-render extension - -This is a client-side extension to automatically render all of the math inside of the -text of a running HTML document. It searches all of the text nodes in a given element -for the given delimiters, and renders the math in place. - - -This extension isn't part of Temml proper, so the script needs to be included -(via a ` - ... - - - - ... - - - ... - - -``` - -The auto-render extension exposes a single function, `window.renderMathInElement`, with -the following API: - -```js -function renderMathInElement(elem, options) -``` - -`elem` is an HTML DOM element, typically `document.main`. The function will -recursively search for text nodes inside this element and render the math in them. - -`options` is an optional object argument that can have the same keys as [the -options](https://temml.org/docs/en/administration.html#options) passed to -`temml.render`. In addition, there are five auto-render-specific keys: - -- `delimiters`: This is a list of delimiters to look for math, processed in - the same order as the list. Each delimiter has three properties: - - - `left`: A string which starts the math expression (i.e. the left delimiter). - - `right`: A string which ends the math expression (i.e. the right delimiter). - - `display`: A boolean of whether the math in the expression should be - rendered in display mode or not. - - The default `delimiters` value is: - - ```js - [ - { left: "$$", right: "$$", display: true }, - { left: "\\(", right: "\\)", display: false }, - { left: "\\begin{equation}", right: "\\end{equation}", display: true }, - { left: "\\begin{align}", right: "\\end{align}", display: true }, - { left: "\\begin{alignat}", right: "\\end{alignat}", display: true }, - { left: "\\begin{gather}", right: "\\end{gather}", display: true }, - { left: "\\begin{CD}", right: "\\end{CD}", display: true }, - { left: "\\begin{multline}", right: "\\end{multline}", display: true }, - { left: "\\[", right: "\\]", display: true } - ] - ``` - - If you want to add support for inline math via `$…$`, be sure to list it - **after** `$$…$$`. Because rules are processed in order, putting a `$` rule first would - match `$$` and treat as an empty math expression. Here is an example that includes `$…$`: - - ```js - [ - {left: "$$", right: "$$", display: true}, - // Put $ after $$. - {left: "$", right: "$", display: false}, - {left: "\\(", right: "\\)", display: false}, - // Put \[ last to avoid conflict with possible future \\[1em] row separator. - {left: "\\[", right: "\\]", display: true} - ] - ``` - -- `ignoredTags`: This is a list of DOM node types to ignore when recursing - through. The default value is - `["script", "noscript", "style", "textarea", "pre", "code", "option"]`. - -- `ignoredClasses`: This is a list of DOM node class names to ignore when - recursing through. By default, this value is not set. - -- `errorCallback`: A callback method returning a message and an error stack - in case of an critical error during rendering. The default uses `console.error`. - -- `preProcess`: A callback function, `(math: string) => string`, used to process - math expressions before rendering. diff --git a/contrib/auto-render/auto-render.js b/contrib/auto-render/auto-render.js deleted file mode 100644 index e0de5cad..00000000 --- a/contrib/auto-render/auto-render.js +++ /dev/null @@ -1,128 +0,0 @@ -/* eslint no-console:0 */ - -import temml from "temml"; -import splitAtDelimiters from "./splitAtDelimiters"; - -/* Note: optionsCopy is mutated by this method. If it is ever exposed in the - * API, we should copy it before mutating. - */ -const renderMathInText = function(text, optionsCopy) { - const data = splitAtDelimiters(text, optionsCopy.delimiters); - if (data.length === 1 && data[0].type === "text") { - // There is no formula in the text. - // Let's return null which means there is no need to replace - // the current text node with a new one. - return null; - } - - const fragment = document.createDocumentFragment(); - - for (let i = 0; i < data.length; i++) { - if (data[i].type === "text") { - fragment.appendChild(document.createTextNode(data[i].data)); - } else { - const span = document.createElement("span"); - let math = data[i].data; - // Override any display mode defined in the settings with that - // defined by the text itself - optionsCopy.displayMode = data[i].display; - try { - if (optionsCopy.preProcess) { - math = optionsCopy.preProcess(math); - } - temml.render(math, span, optionsCopy); - } catch (e) { - if (!(e instanceof temml.ParseError)) { - throw e; - } - optionsCopy.errorCallback( - "Temml auto-render: Failed to parse `" + data[i].data + "` with ", - e - ); - fragment.appendChild(document.createTextNode(data[i].rawData)); - continue; - } - fragment.appendChild(span); - } - } - - return fragment; -}; - -const renderElem = function(elem, optionsCopy) { - for (let i = 0; i < elem.childNodes.length; i++) { - const childNode = elem.childNodes[i]; - if (childNode.nodeType === 3) { - // Text node - const frag = renderMathInText(childNode.textContent, optionsCopy); - if (frag) { - i += frag.childNodes.length - 1; - elem.replaceChild(frag, childNode); - } - } else if (childNode.nodeType === 1) { - // Element node - const className = " " + childNode.className + " "; - const shouldRender = - optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 && - optionsCopy.ignoredClasses.every((x) => className.indexOf(" " + x + " ") === -1); - - if (shouldRender) { - renderElem(childNode, optionsCopy); - } - } - // Otherwise, it's something else, and ignore it. - } -}; - -const renderMathInElement = function(elem, options) { - if (!elem) { - throw new Error("No element provided to render"); - } - - const optionsCopy = {}; - - // Object.assign(optionsCopy, option) - for (const option in options) { - if (Object.prototype.hasOwnProperty.call(options, option)) { - optionsCopy[option] = options[option]; - } - } - - // default options - optionsCopy.delimiters = optionsCopy.delimiters || [ - { left: "$$", right: "$$", display: true }, - { left: "\\(", right: "\\)", display: false }, - // LaTeX uses $…$, but it ruins the display of normal `$` in text: - // {left: "$", right: "$", display: false}, - // $ must come after $$ - - // Render AMS environments even if outside $$…$$ delimiters. - { left: "\\begin{equation}", right: "\\end{equation}", display: true }, - { left: "\\begin{align}", right: "\\end{align}", display: true }, - { left: "\\begin{alignat}", right: "\\end{alignat}", display: true }, - { left: "\\begin{gather}", right: "\\end{gather}", display: true }, - { left: "\\begin{CD}", right: "\\end{CD}", display: true }, - - { left: "\\[", right: "\\]", display: true } - ]; - optionsCopy.ignoredTags = optionsCopy.ignoredTags || [ - "script", - "noscript", - "style", - "textarea", - "pre", - "code", - "option" - ]; - optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; - optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; - - // Enable sharing of global macros defined via `\gdef` between different - // math elements within a single call to `renderMathInElement`. - optionsCopy.macros = optionsCopy.macros || {}; - - renderElem(elem, optionsCopy); - temml.postProcess(elem); -}; - -export default renderMathInElement; diff --git a/contrib/auto-render/dist/auto-render.js b/contrib/auto-render/dist/auto-render.js deleted file mode 100644 index 3848e38f..00000000 --- a/contrib/auto-render/dist/auto-render.js +++ /dev/null @@ -1,217 +0,0 @@ -var renderMathInElement = (function (temml) { - 'use strict'; - - function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } - - var temml__default = /*#__PURE__*/_interopDefaultLegacy(temml); - - /* eslint no-constant-condition:0 */ - const findEndOfMath = function(delimiter, text, startIndex) { - // Adapted from - // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx - let index = startIndex; - let braceLevel = 0; - - const delimLength = delimiter.length; - - while (index < text.length) { - const character = text[index]; - - if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { - return index; - } else if (character === "\\") { - index++; - } else if (character === "{") { - braceLevel++; - } else if (character === "}") { - braceLevel--; - } - - index++; - } - - return -1; - }; - - const escapeRegex = function(string) { - return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); - }; - - const amsRegex = /^\\begin{/; - - const splitAtDelimiters = function(text, delimiters) { - let index; - const data = []; - - const regexLeft = new RegExp( - "(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")" - ); - - while (true) { - index = text.search(regexLeft); - if (index === -1) { - break; - } - if (index > 0) { - data.push({ - type: "text", - data: text.slice(0, index) - }); - text = text.slice(index); // now text starts with delimiter - } - // ... so this always succeeds: - const i = delimiters.findIndex((delim) => text.startsWith(delim.left)); - index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length); - if (index === -1) { - break; - } - const rawData = text.slice(0, index + delimiters[i].right.length); - const math = amsRegex.test(rawData) - ? rawData - : text.slice(delimiters[i].left.length, index); - data.push({ - type: "math", - data: math, - rawData, - display: delimiters[i].display - }); - text = text.slice(index + delimiters[i].right.length); - } - - if (text !== "") { - data.push({ - type: "text", - data: text - }); - } - - return data; - }; - - /* eslint no-console:0 */ - - /* Note: optionsCopy is mutated by this method. If it is ever exposed in the - * API, we should copy it before mutating. - */ - const renderMathInText = function(text, optionsCopy) { - const data = splitAtDelimiters(text, optionsCopy.delimiters); - if (data.length === 1 && data[0].type === "text") { - // There is no formula in the text. - // Let's return null which means there is no need to replace - // the current text node with a new one. - return null; - } - - const fragment = document.createDocumentFragment(); - - for (let i = 0; i < data.length; i++) { - if (data[i].type === "text") { - fragment.appendChild(document.createTextNode(data[i].data)); - } else { - const span = document.createElement("span"); - let math = data[i].data; - // Override any display mode defined in the settings with that - // defined by the text itself - optionsCopy.displayMode = data[i].display; - try { - if (optionsCopy.preProcess) { - math = optionsCopy.preProcess(math); - } - temml__default["default"].render(math, span, optionsCopy); - } catch (e) { - if (!(e instanceof temml__default["default"].ParseError)) { - throw e; - } - optionsCopy.errorCallback( - "Temml auto-render: Failed to parse `" + data[i].data + "` with ", - e - ); - fragment.appendChild(document.createTextNode(data[i].rawData)); - continue; - } - fragment.appendChild(span); - } - } - - return fragment; - }; - - const renderElem = function(elem, optionsCopy) { - for (let i = 0; i < elem.childNodes.length; i++) { - const childNode = elem.childNodes[i]; - if (childNode.nodeType === 3) { - // Text node - const frag = renderMathInText(childNode.textContent, optionsCopy); - if (frag) { - i += frag.childNodes.length - 1; - elem.replaceChild(frag, childNode); - } - } else if (childNode.nodeType === 1) { - // Element node - const className = " " + childNode.className + " "; - const shouldRender = - optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 && - optionsCopy.ignoredClasses.every((x) => className.indexOf(" " + x + " ") === -1); - - if (shouldRender) { - renderElem(childNode, optionsCopy); - } - } - // Otherwise, it's something else, and ignore it. - } - }; - - const renderMathInElement = function(elem, options) { - if (!elem) { - throw new Error("No element provided to render"); - } - - const optionsCopy = {}; - - // Object.assign(optionsCopy, option) - for (const option in options) { - if (Object.prototype.hasOwnProperty.call(options, option)) { - optionsCopy[option] = options[option]; - } - } - - // default options - optionsCopy.delimiters = optionsCopy.delimiters || [ - { left: "$$", right: "$$", display: true }, - { left: "\\(", right: "\\)", display: false }, - // LaTeX uses $…$, but it ruins the display of normal `$` in text: - // {left: "$", right: "$", display: false}, - // $ must come after $$ - - // Render AMS environments even if outside $$…$$ delimiters. - { left: "\\begin{equation}", right: "\\end{equation}", display: true }, - { left: "\\begin{align}", right: "\\end{align}", display: true }, - { left: "\\begin{alignat}", right: "\\end{alignat}", display: true }, - { left: "\\begin{gather}", right: "\\end{gather}", display: true }, - { left: "\\begin{CD}", right: "\\end{CD}", display: true }, - - { left: "\\[", right: "\\]", display: true } - ]; - optionsCopy.ignoredTags = optionsCopy.ignoredTags || [ - "script", - "noscript", - "style", - "textarea", - "pre", - "code", - "option" - ]; - optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; - optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; - - // Enable sharing of global macros defined via `\gdef` between different - // math elements within a single call to `renderMathInElement`. - optionsCopy.macros = optionsCopy.macros || {}; - - renderElem(elem, optionsCopy); - temml__default["default"].postProcess(elem); - }; - - return renderMathInElement; - -})(temml); diff --git a/contrib/auto-render/dist/auto-render.min.js b/contrib/auto-render/dist/auto-render.min.js deleted file mode 100644 index 55bcd20c..00000000 --- a/contrib/auto-render/dist/auto-render.min.js +++ /dev/null @@ -1 +0,0 @@ -var renderMathInElement=function(e){"use strict";function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n=t(e);const r=function(e,t,n){let r=n,a=0;const i=e.length;for(;re.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"))).join("|")+")");for(;n=e.search(l),-1!==n;){n>0&&(i.push({type:"text",data:e.slice(0,n)}),e=e.slice(n));const l=t.findIndex((t=>e.startsWith(t.left)));if(n=r(t[l].right,e,t[l].left.length),-1===n)break;const o=e.slice(0,n+t[l].right.length),s=a.test(o)?o:e.slice(t[l].left.length,n);i.push({type:"math",data:s,rawData:o,display:t[l].display}),e=e.slice(n+t[l].right.length)}return""!==e&&i.push({type:"text",data:e}),i}(e,t.delimiters);if(1===i.length&&"text"===i[0].type)return null;const l=document.createDocumentFragment();for(let e=0;e-1===e.indexOf(" "+t+" ")))&&l(r,t)}}};return function(e,t){if(!e)throw new Error("No element provided to render");const r={};for(const e in t)Object.prototype.hasOwnProperty.call(t,e)&&(r[e]=t[e]);r.delimiters=r.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],r.ignoredTags=r.ignoredTags||["script","noscript","style","textarea","pre","code","option"],r.ignoredClasses=r.ignoredClasses||[],r.errorCallback=r.errorCallback||console.error,r.macros=r.macros||{},l(e,r),n.default.postProcess(e)}}(temml); \ No newline at end of file diff --git a/contrib/auto-render/splitAtDelimiters.js b/contrib/auto-render/splitAtDelimiters.js deleted file mode 100644 index 0c93c13a..00000000 --- a/contrib/auto-render/splitAtDelimiters.js +++ /dev/null @@ -1,84 +0,0 @@ -/* eslint no-constant-condition:0 */ -const findEndOfMath = function(delimiter, text, startIndex) { - // Adapted from - // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx - let index = startIndex; - let braceLevel = 0; - - const delimLength = delimiter.length; - - while (index < text.length) { - const character = text[index]; - - if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { - return index; - } else if (character === "\\") { - index++; - } else if (character === "{") { - braceLevel++; - } else if (character === "}") { - braceLevel--; - } - - index++; - } - - return -1; -}; - -const escapeRegex = function(string) { - return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); -}; - -const amsRegex = /^\\begin{/; - -const splitAtDelimiters = function(text, delimiters) { - let index; - const data = []; - - const regexLeft = new RegExp( - "(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")" - ) - - while (true) { - index = text.search(regexLeft); - if (index === -1) { - break; - } - if (index > 0) { - data.push({ - type: "text", - data: text.slice(0, index) - }); - text = text.slice(index); // now text starts with delimiter - } - // ... so this always succeeds: - const i = delimiters.findIndex((delim) => text.startsWith(delim.left)); - index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length); - if (index === -1) { - break; - } - const rawData = text.slice(0, index + delimiters[i].right.length); - const math = amsRegex.test(rawData) - ? rawData - : text.slice(delimiters[i].left.length, index); - data.push({ - type: "math", - data: math, - rawData, - display: delimiters[i].display - }); - text = text.slice(index + delimiters[i].right.length); - } - - if (text !== "") { - data.push({ - type: "text", - data: text - }); - } - - return data; -}; - -export default splitAtDelimiters; diff --git a/contrib/auto-render/test/auto-render-spec.js b/contrib/auto-render/test/auto-render-spec.js deleted file mode 100644 index 3875bfb1..00000000 --- a/contrib/auto-render/test/auto-render-spec.js +++ /dev/null @@ -1,234 +0,0 @@ -/* global beforeEach: false */ -/* global expect: false */ -/* global it: false */ -/* global describe: false */ - -import splitAtDelimiters from "../splitAtDelimiters"; -import renderMathInElement from "../auto-render"; - -beforeEach(function() { - expect.extend({ - toSplitInto: function(actual, left, right, result) { - const message = { - pass: true, - message: "'" + actual + "' split correctly" - }; - - const startData = [{ type: "text", data: actual }]; - - const split = splitAtDelimiters(startData, left, right, false); - - if (split.length !== result.length) { - message.pass = false; - message.message = - "Different number of splits: " + - split.length + - " vs. " + - result.length + - " (" + - JSON.stringify(split) + - " vs. " + - JSON.stringify(result) + - ")"; - return message; - } - - for (let i = 0; i < split.length; i++) { - const real = split[i]; - const correct = result[i]; - - let good = true; - let diff; - - if (real.type !== correct.type) { - good = false; - diff = "type"; - } else if (real.data !== correct.data) { - good = false; - diff = "data"; - } else if (real.display !== correct.display) { - good = false; - diff = "display"; - } - - if (!good) { - message.pass = false; - message.message = - "Difference at split " + - (i + 1) + - ": " + - JSON.stringify(real) + - " vs. " + - JSON.stringify(correct) + - " (" + - diff + - " differs)"; - break; - } - } - - return message; - } - }); -}); - -describe("A delimiter splitter", function() { - it("doesn't split when there are no delimiters", function() { - expect("hello").toSplitInto("(", ")", [{ type: "text", data: "hello" }]); - }); - - it("doesn't create a math node with only one left delimiter", function() { - expect("hello ( world").toSplitInto("(", ")", [ - { type: "text", data: "hello " }, - { type: "text", data: "( world" } - ]); - }); - - it("doesn't split when there's only a right delimiter", function() { - expect("hello ) world").toSplitInto("(", ")", [{ type: "text", data: "hello ) world" }]); - }); - - it("splits when there are both delimiters", function() { - expect("hello ( world ) boo").toSplitInto("(", ")", [ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "( world )", display: false }, - { type: "text", data: " boo" } - ]); - }); - - it("splits on multi-character delimiters", function() { - expect("hello [[ world ]] boo").toSplitInto("[[", "]]", [ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "[[ world ]]", display: false }, - { type: "text", data: " boo" } - ]); - }); - - it("splits mutliple times", function() { - expect("hello ( world ) boo ( more ) stuff").toSplitInto("(", ")", [ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "( world )", display: false }, - { type: "text", data: " boo " }, - { type: "math", data: " more ", rawData: "( more )", display: false }, - { type: "text", data: " stuff" } - ]); - }); - - it("leaves the ending when there's only a left delimiter", function() { - expect("hello ( world ) boo ( left").toSplitInto("(", ")", [ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "( world )", display: false }, - { type: "text", data: " boo " }, - { type: "text", data: "( left" } - ]); - }); - - it("doesn't split when close delimiters are in {}s", function() { - expect("hello ( world { ) } ) boo").toSplitInto("(", ")", [ - { type: "text", data: "hello " }, - { type: "math", data: " world { ) } ", rawData: "( world { ) } )", display: false }, - { type: "text", data: " boo" } - ]); - - expect("hello ( world { { } ) } ) boo").toSplitInto("(", ")", [ - { type: "text", data: "hello " }, - { type: "math", data: " world { { } ) } ", rawData: "( world { { } ) } )", display: false }, - { type: "text", data: " boo" } - ]); - }); - - it("doesn't split at escaped delimiters", function() { - expect("hello ( world \\) ) boo").toSplitInto("(", ")", [ - { type: "text", data: "hello " }, - { type: "math", data: " world \\) ", rawData: "( world \\) )", display: false }, - { type: "text", data: " boo" } - ]); - - /* TODO(emily): make this work maybe? - expect("hello \\( ( world ) boo").toSplitInto( - "(", ")", - [ - {type: "text", data: "hello \\( "}, - {type: "math", data: " world ", - rawData: "( world )", display: false}, - {type: "text", data: " boo"}, - ]); - */ - }); - - it("splits when the right and left delimiters are the same", function() { - expect("hello $ world $ boo").toSplitInto("$", "$", [ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "$ world $", display: false }, - { type: "text", data: " boo" } - ]); - }); - - it("remembers which delimiters are display-mode", function() { - const startData = [{ type: "text", data: "hello ( world ) boo" }]; - - expect(splitAtDelimiters(startData, "(", ")", true)).toEqual([ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "( world )", display: true }, - { type: "text", data: " boo" } - ]); - }); - - it("works with more than one start datum", function() { - const startData = [ - { type: "text", data: "hello ( world ) boo" }, - { type: "math", data: "math", rawData: "(math)", display: true }, - { type: "text", data: "hello ( world ) boo" } - ]; - - expect(splitAtDelimiters(startData, "(", ")", false)).toEqual([ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "( world )", display: false }, - { type: "text", data: " boo" }, - { type: "math", data: "math", rawData: "(math)", display: true }, - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "( world )", display: false }, - { type: "text", data: " boo" } - ]); - }); - - it("doesn't do splitting inside of math nodes", function() { - const startData = [ - { type: "text", data: "hello ( world ) boo" }, - { - type: "math", - data: "hello ( world ) boo", - rawData: "(hello ( world ) boo)", - display: true - } - ]; - - expect(splitAtDelimiters(startData, "(", ")", false)).toEqual([ - { type: "text", data: "hello " }, - { type: "math", data: " world ", rawData: "( world )", display: false }, - { type: "text", data: " boo" }, - { - type: "math", - data: "hello ( world ) boo", - rawData: "(hello ( world ) boo)", - display: true - } - ]); - }); -}); - -describe("Pre-process callback", function() { - it("replace `-squared` with `^2 `", function() { - const el1 = document.createElement("div"); - el1.textContent = "Circle equation: $x-squared + y-squared = r-squared$."; - const el2 = document.createElement("div"); - el2.textContent = "Circle equation: $x^2 + y^2 = r^2$."; - const delimiters = [{ left: "$", right: "$", display: false }]; - renderMathInElement(el1, { - delimiters, - preProcess: (math) => math.replace(/-squared/g, "^2") - }); - renderMathInElement(el2, { delimiters }); - expect(el1.innerHTML).toEqual(el2.innerHTML); - }); -}); diff --git a/contrib/auto-render/test/auto-render.js b/contrib/auto-render/test/auto-render.js deleted file mode 100644 index 3848e38f..00000000 --- a/contrib/auto-render/test/auto-render.js +++ /dev/null @@ -1,217 +0,0 @@ -var renderMathInElement = (function (temml) { - 'use strict'; - - function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } - - var temml__default = /*#__PURE__*/_interopDefaultLegacy(temml); - - /* eslint no-constant-condition:0 */ - const findEndOfMath = function(delimiter, text, startIndex) { - // Adapted from - // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx - let index = startIndex; - let braceLevel = 0; - - const delimLength = delimiter.length; - - while (index < text.length) { - const character = text[index]; - - if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { - return index; - } else if (character === "\\") { - index++; - } else if (character === "{") { - braceLevel++; - } else if (character === "}") { - braceLevel--; - } - - index++; - } - - return -1; - }; - - const escapeRegex = function(string) { - return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); - }; - - const amsRegex = /^\\begin{/; - - const splitAtDelimiters = function(text, delimiters) { - let index; - const data = []; - - const regexLeft = new RegExp( - "(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")" - ); - - while (true) { - index = text.search(regexLeft); - if (index === -1) { - break; - } - if (index > 0) { - data.push({ - type: "text", - data: text.slice(0, index) - }); - text = text.slice(index); // now text starts with delimiter - } - // ... so this always succeeds: - const i = delimiters.findIndex((delim) => text.startsWith(delim.left)); - index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length); - if (index === -1) { - break; - } - const rawData = text.slice(0, index + delimiters[i].right.length); - const math = amsRegex.test(rawData) - ? rawData - : text.slice(delimiters[i].left.length, index); - data.push({ - type: "math", - data: math, - rawData, - display: delimiters[i].display - }); - text = text.slice(index + delimiters[i].right.length); - } - - if (text !== "") { - data.push({ - type: "text", - data: text - }); - } - - return data; - }; - - /* eslint no-console:0 */ - - /* Note: optionsCopy is mutated by this method. If it is ever exposed in the - * API, we should copy it before mutating. - */ - const renderMathInText = function(text, optionsCopy) { - const data = splitAtDelimiters(text, optionsCopy.delimiters); - if (data.length === 1 && data[0].type === "text") { - // There is no formula in the text. - // Let's return null which means there is no need to replace - // the current text node with a new one. - return null; - } - - const fragment = document.createDocumentFragment(); - - for (let i = 0; i < data.length; i++) { - if (data[i].type === "text") { - fragment.appendChild(document.createTextNode(data[i].data)); - } else { - const span = document.createElement("span"); - let math = data[i].data; - // Override any display mode defined in the settings with that - // defined by the text itself - optionsCopy.displayMode = data[i].display; - try { - if (optionsCopy.preProcess) { - math = optionsCopy.preProcess(math); - } - temml__default["default"].render(math, span, optionsCopy); - } catch (e) { - if (!(e instanceof temml__default["default"].ParseError)) { - throw e; - } - optionsCopy.errorCallback( - "Temml auto-render: Failed to parse `" + data[i].data + "` with ", - e - ); - fragment.appendChild(document.createTextNode(data[i].rawData)); - continue; - } - fragment.appendChild(span); - } - } - - return fragment; - }; - - const renderElem = function(elem, optionsCopy) { - for (let i = 0; i < elem.childNodes.length; i++) { - const childNode = elem.childNodes[i]; - if (childNode.nodeType === 3) { - // Text node - const frag = renderMathInText(childNode.textContent, optionsCopy); - if (frag) { - i += frag.childNodes.length - 1; - elem.replaceChild(frag, childNode); - } - } else if (childNode.nodeType === 1) { - // Element node - const className = " " + childNode.className + " "; - const shouldRender = - optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 && - optionsCopy.ignoredClasses.every((x) => className.indexOf(" " + x + " ") === -1); - - if (shouldRender) { - renderElem(childNode, optionsCopy); - } - } - // Otherwise, it's something else, and ignore it. - } - }; - - const renderMathInElement = function(elem, options) { - if (!elem) { - throw new Error("No element provided to render"); - } - - const optionsCopy = {}; - - // Object.assign(optionsCopy, option) - for (const option in options) { - if (Object.prototype.hasOwnProperty.call(options, option)) { - optionsCopy[option] = options[option]; - } - } - - // default options - optionsCopy.delimiters = optionsCopy.delimiters || [ - { left: "$$", right: "$$", display: true }, - { left: "\\(", right: "\\)", display: false }, - // LaTeX uses $…$, but it ruins the display of normal `$` in text: - // {left: "$", right: "$", display: false}, - // $ must come after $$ - - // Render AMS environments even if outside $$…$$ delimiters. - { left: "\\begin{equation}", right: "\\end{equation}", display: true }, - { left: "\\begin{align}", right: "\\end{align}", display: true }, - { left: "\\begin{alignat}", right: "\\end{alignat}", display: true }, - { left: "\\begin{gather}", right: "\\end{gather}", display: true }, - { left: "\\begin{CD}", right: "\\end{CD}", display: true }, - - { left: "\\[", right: "\\]", display: true } - ]; - optionsCopy.ignoredTags = optionsCopy.ignoredTags || [ - "script", - "noscript", - "style", - "textarea", - "pre", - "code", - "option" - ]; - optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; - optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; - - // Enable sharing of global macros defined via `\gdef` between different - // math elements within a single call to `renderMathInElement`. - optionsCopy.macros = optionsCopy.macros || {}; - - renderElem(elem, optionsCopy); - temml__default["default"].postProcess(elem); - }; - - return renderMathInElement; - -})(temml); diff --git a/contrib/auto-render/test/test_page.html b/contrib/auto-render/test/test_page.html deleted file mode 100644 index 04172f26..00000000 --- a/contrib/auto-render/test/test_page.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - Auto-render test - - - - - - -
- This is some text $math \frac12$ other text - - Other node \[ displaymath \frac{1}{2} \] blah $$ \int_2^3 $$ - - and some more text \(and math\) blah. And $math with a - \$ sign$. -
-        Stuff in a $pre tag$
-      
-

An AMS environment without $$…$$ delimiters.

-

\begin{equation}\begin{split} a &=b+c\\ &=e+f \end{split} \end{equation}

-

$\unsupported$

-
- - - diff --git a/contrib/mhchem/README.md b/contrib/mhchem/README.md deleted file mode 100644 index b81ffcfa..00000000 --- a/contrib/mhchem/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# mhchem extension - -This extension adds to Temml the `\ce` and `\pu` functions from the [mhchem](https://mhchem.github.io/MathJax-mhchem/) package. - -You can download the `mhchem.min.js` file from this repository. - -### Usage - -This extension isn't part of core Temml, so the script should be separately included. Write the following line into the HTML page's ``. Place it _after_ the line that calls `temml.js`. - -```html - - -``` - -If you are working sever-side, just use `temml.cjs`. It already includes all the functions in `mhchem.js`. - -### Syntax - -See the [mhchem Manual](https://mhchem.github.io/MathJax-mhchem/) for a full explanation of the input syntax, with working examples. The manual also includes a demonstration box. - -Note that old versions of `mhchem.sty` used `\cf` for chemical formula and `\ce` for chemical equations, but `\cf` has been deprecated in place of `\ce`. This extension supports only `\ce`. You can define a macro mapping `\cf` to `\ce` if needed. - -### Browser Support - -This extension has been tested on Chrome, Firefox, Opera, and Edge. diff --git a/contrib/mhchem/mhchem.js b/contrib/mhchem/mhchem.js deleted file mode 100644 index 6e507ce7..00000000 --- a/contrib/mhchem/mhchem.js +++ /dev/null @@ -1,1705 +0,0 @@ -/* eslint-disable */ -/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ - -/************************************************************* - * - * Temml mhchem.js - * - * This file implements a Temml version of mhchem version 3.3.0. - * It is adapted from MathJax/extensions/TeX/mhchem.js - * It differs from the MathJax version as follows: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. - * 3. The reaction arrow code is simplified. All reaction arrows are rendered - * using Temml extensible arrows instead of building non-extensible arrows. - * 4. The ~bond forms are composed entirely of \rule elements. - * 5. Two dashes in _getBond are wrapped in braces to suppress spacing. i.e., {-} - * 6. The electron dot uses \textbullet instead of \bullet. - * - * This code, as other Temml code, is released under the MIT license. - * - * /************************************************************* - * - * MathJax/extensions/TeX/mhchem.js - * - * Implements the \ce command for handling chemical formulas - * from the mhchem LaTeX package. - * - * --------------------------------------------------------------------- - * - * Copyright (c) 2011-2015 The MathJax Consortium - * Copyright (c) 2015-2018 Martin Hensel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Coding Style -// - use '' for identifiers that can by minified/uglified -// - use "" for strings that need to stay untouched - -// version: "3.3.0" for MathJax and Temml - - -// Add \ce, \pu, and \tripleDash to the Temml macros. - -temml.__defineMacro("\\ce", function(context) { - return chemParse(context.consumeArgs(1)[0], "ce") -}); - -temml.__defineMacro("\\pu", function(context) { - return chemParse(context.consumeArgs(1)[0], "pu"); -}); - -// Math fonts do not include glyphs for the ~ form of bonds. So we'll send path geometry -// So we'll compose characters built from \rule elements. -temml.__defineMacro("\\uniDash", `{\\rule{0.672em}{0.06em}}`) -temml.__defineMacro("\\triDash", `{\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}}`) -temml.__defineMacro("\\tripleDash", `\\kern0.075em\\raise0.25em{\\triDash}\\kern0.075em`) -temml.__defineMacro("\\tripleDashOverLine", `\\kern0.075em\\mathrlap{\\raise0.125em{\\uniDash}}\\raise0.34em{\\triDash}\\kern0.075em`) -temml.__defineMacro("\\tripleDashOverDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\triDash}}\\raise0.27em{\\uniDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`) -temml.__defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\uniDash}}\\raise0.27em{\\triDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`) - - // - // This is the main function for handing the \ce and \pu commands. - // It takes the argument to \ce or \pu and returns the corresponding TeX string. - // - - var chemParse = function (tokens, stateMachine) { - // Recreate the argument string from Temml's array of tokens. - var str = ""; - var expectedLoc = tokens.length && tokens[tokens.length - 1].loc.start - for (var i = tokens.length - 1; i >= 0; i--) { - if(tokens[i].loc.start > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = tokens[i].loc.start; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - // Call the mhchem core parser. - var tex = texify.go(mhchemParser.go(str, stateMachine)); - return tex; - }; - - // - // Core parser for mhchem syntax (recursive) - // - /** @type {MhchemParser} */ - var mhchemParser = { - // - // Parses mchem \ce syntax - // - // Call like - // go("H2O"); - // - go: function (input, stateMachine) { - if (!input) { return []; } - if (stateMachine === undefined) { stateMachine = 'ce'; } - var state = '0'; - - // - // String buffers for parsing: - // - // buffer.a == amount - // buffer.o == element - // buffer.b == left-side superscript - // buffer.p == left-side subscript - // buffer.q == right-side subscript - // buffer.d == right-side superscript - // - // buffer.r == arrow - // buffer.rdt == arrow, script above, type - // buffer.rd == arrow, script above, content - // buffer.rqt == arrow, script below, type - // buffer.rq == arrow, script below, content - // - // buffer.text_ - // buffer.rm - // etc. - // - // buffer.parenthesisLevel == int, starting at 0 - // buffer.sb == bool, space before - // buffer.beginsWithBond == bool - // - // These letters are also used as state names. - // - // Other states: - // 0 == begin of main part (arrow/operator unlikely) - // 1 == next entity - // 2 == next entity (arrow/operator unlikely) - // 3 == next atom - // c == macro - // - /** @type {Buffer} */ - var buffer = {}; - buffer['parenthesisLevel'] = 0; - - input = input.replace(/\n/g, " "); - input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); - input = input.replace(/[\u2026]/g, "..."); - - // - // Looks through mhchemParser.transitions, to execute a matching action - // (recursive) - // - var lastInput; - var watchdog = 10; - /** @type {ParserOutput[]} */ - var output = []; - while (true) { - if (lastInput !== input) { - watchdog = 10; - lastInput = input; - } else { - watchdog--; - } - // - // Find actions in transition table - // - var machine = mhchemParser.stateMachines[stateMachine]; - var t = machine.transitions[state] || machine.transitions['*']; - iterateTransitions: - for (var i=0; i 0) { - if (!task.revisit) { - input = matches.remainder; - } - if (!task.toContinue) { - break iterateTransitions; - } - } else { - return output; - } - } - } - // - // Prevent infinite loop - // - if (watchdog <= 0) { - throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character - } - } - }, - concatArray: function (a, b) { - if (b) { - if (Array.isArray(b)) { - for (var iB=0; iB': /^[=<>]/, - '#': /^[#\u2261]/, - '+': /^\+/, - '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation - '-9': /^-(?=[0-9])/, - '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, - '-': /^-/, - 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, - 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, - 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, - '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, - '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, - 'CMT': /^[CMT](?=\[)/, - '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, - '1st-level escape': /^(&|\\\\|\\hline)\s*/, - '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before - '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, - '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, - '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, - '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, - 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway - 'others': /^[\/~|]/, - '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, - '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, - '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, - '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, - '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, - '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); }, - '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, - '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, - 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, - 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge - 'roman numeral': /^[IVX]+/, - '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, - 'amount': function (input) { - var match; - // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing - match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); - if (a) { // e.g. $2n-1$, $-$ - match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - } - return null; - }, - 'amount2': function (input) { return this['amount'](input); }, - '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, - 'formula$': function (input) { - if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula - var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - return null; - }, - 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, - '/': /^\s*(\/)\s*/, - '//': /^\s*(\/\/)\s*/, - '*': /^\s*[*.]\s*/ - }, - findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { - /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ - var _match = function (input, pattern) { - if (typeof pattern === "string") { - if (input.indexOf(pattern) !== 0) { return null; } - return pattern; - } else { - var match = input.match(pattern); - if (!match) { return null; } - return match[0]; - } - }; - /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ - var _findObserveGroups = function (input, i, endChars) { - var braces = 0; - while (i < input.length) { - var a = input.charAt(i); - var match = _match(input.substr(i), endChars); - if (match !== null && braces === 0) { - return { endMatchBegin: i, endMatchEnd: i + match.length }; - } else if (a === "{") { - braces++; - } else if (a === "}") { - if (braces === 0) { - throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; - } else { - braces--; - } - } - i++; - } - if (braces > 0) { - return null; - } - return null; - }; - var match = _match(input, begExcl); - if (match === null) { return null; } - input = input.substr(match.length); - match = _match(input, begIncl); - if (match === null) { return null; } - var e = _findObserveGroups(input, match.length, endIncl || endExcl); - if (e === null) { return null; } - var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); - if (!(beg2Excl || beg2Incl)) { - return { - match_: match1, - remainder: input.substr(e.endMatchEnd) - }; - } else { - var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); - if (group2 === null) { return null; } - /** @type {string[]} */ - var matchRet = [match1, group2.match_]; - return { - match_: (combine ? matchRet.join("") : matchRet), - remainder: group2.remainder - }; - } - }, - - // - // Matching function - // e.g. match("a", input) will look for the regexp called "a" and see if it matches - // returns null or {match_:"a", remainder:"bc"} - // - match_: function (m, input) { - var pattern = mhchemParser.patterns.patterns[m]; - if (pattern === undefined) { - throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern - } else if (typeof pattern === "function") { - return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser - } else { // RegExp - var match = input.match(pattern); - if (match) { - var mm; - if (match[2]) { - mm = [ match[1], match[2] ]; - } else if (match[1]) { - mm = match[1]; - } else { - mm = match[0]; - } - return { match_: mm, remainder: input.substr(match[0].length) }; - } - return null; - } - } - }, - - // - // Generic state machine actions - // - actions: { - 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; }, - 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; }, - 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; }, - 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; }, - 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; }, - 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; }, - 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; }, - 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; }, - 'insert': function (buffer, m, a) { return { type_: a }; }, - 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; }, - 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, - 'copy': function (buffer, m) { return m; }, - 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; }, - 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); }, - '{text}': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); - ret.push("}"); - return ret; - }, - 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); }, - 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); }, - 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, - 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; }, - 'ce': function (buffer, m) { return mhchemParser.go(m); }, - '1/2': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m.match(/^[+\-]/)) { - ret.push(m.substr(0, 1)); - m = m.substr(1); - } - var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); - n[1] = n[1].replace(/\$/g, ""); - ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); - if (n[3]) { - n[3] = n[3].replace(/\$/g, ""); - ret.push({ type_: 'tex-math', p1: n[3] }); - } - return ret; - }, - '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); } - }, - // - // createTransitions - // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } - // with expansion of 'a|b' to 'a' and 'b' (at 2 places) - // - createTransitions: function (o) { - var pattern, state; - /** @type {string[]} */ - var stateArray; - var i; - // - // 1. Collect all states - // - /** @type {Transitions} */ - var transitions = {}; - for (pattern in o) { - for (state in o[pattern]) { - stateArray = state.split("|"); - o[pattern][state].stateArray = stateArray; - for (i=0; i': { - '0|1|2|3': { action_: 'r=', nextState: 'r' }, - 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' }, - '*': { action_: [ 'output', 'r=' ], nextState: 'r' } }, - '+': { - 'o': { action_: 'd= kv', nextState: 'd' }, - 'd|D': { action_: 'd=', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd|qD': { action_: 'd=', nextState: 'qd' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' }, - '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - 'amount': { - '0|2': { action_: 'a=', nextState: 'a' } }, - 'pm-operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } }, - 'operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - '-$': { - 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' }, - 'd': { action_: 'd=', nextState: 'd' }, - 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd': { action_: 'd=', nextState: 'qd' }, - 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - '-9': { - '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } }, - '- orbital overlap': { - 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } }, - '-': { - '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' }, - '3': { action_: { type_: 'bond', option: "-" } }, - 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' }, - 'b': { action_: 'b=' }, - 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, - 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - 'amount2': { - '1|3': { action_: 'a=', nextState: 'a' } }, - 'letters': { - '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, - 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, - 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, - 'digits': { - 'o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q': { action_: [ 'output', 'o=' ], nextState: 'o' }, - 'a': { action_: 'o=', nextState: 'o' } }, - 'space A': { - 'b|p|bp': {} }, - 'space': { - 'a': { nextState: 'as' }, - '0': { action_: 'sb=false' }, - '1|2': { action_: 'sb=true' }, - 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, - '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} }, - '1st-level escape': { - '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] }, - '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } }, - '[(...)]': { - 'r|rt': { action_: 'rd=', nextState: 'rd' }, - 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, - '...': { - 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' }, - '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } }, - '. |* ': { - '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } }, - 'state of aggregation $': { - '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } }, - '{[(': { - 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } }, - ')]}': { - '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' }, - 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } }, - ', ': { - '*': { action_: [ 'output', 'comma' ], nextState: '0' } }, - '^_': { // ^ and _ without a sensible argument - '*': { } }, - '^{(...)}|^($...$)': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'D' }, - 'q': { action_: 'd=', nextState: 'qD' }, - 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } }, - '^a|^\\x{}{}|^\\x{}|^\\x|\'': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'd|qd|D|qD': { action_: 'd=' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } }, - '_{(state of aggregation)}$': { - 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { - '0|1|2|as': { action_: 'p=', nextState: 'p' }, - 'b': { action_: 'p=', nextState: 'bp' }, - '3|o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '=<>': { - '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } }, - '#': { - '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } }, - '{}': { - '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, - '{...}': { - '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, - 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '$...$': { - 'a': { action_: 'a=' }, // 2$n$ - '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount' - 'as|o': { action_: 'o=' }, - 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '\\bond{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } }, - '\\frac{(...)}': { - '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } }, - '\\overset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } }, - '\\underset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } }, - '\\underbrace{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } }, - '\\color{(...)}0': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } }, - '\\ce{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } }, - '\\,': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } }, - '\\x{}{}|\\x{}|\\x': { - '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' }, - '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } }, - 'others': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } }, - 'else2': { - 'a': { action_: 'a to o', nextState: 'o', revisit: true }, - 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true }, - 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true }, - '*': { action_: [ 'output', 'copy' ], nextState: '3' } } - }), - actions: { - 'o after d': function (buffer, m) { - var ret; - if ((buffer.d || "").match(/^[0-9]+$/)) { - var tmp = buffer.d; - buffer.d = undefined; - ret = this['output'](buffer); - buffer.b = tmp; - } else { - ret = this['output'](buffer); - } - mhchemParser.actions['o='](buffer, m); - return ret; - }, - 'd= kv': function (buffer, m) { - buffer.d = m; - buffer.dType = 'kv'; - }, - 'charge or bond': function (buffer, m) { - if (buffer['beginsWithBond']) { - /** @type {ParserOutput[]} */ - var ret = []; - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - return ret; - } else { - buffer.d = m; - } - }, - '- after o/d': function (buffer, m, isAfterD) { - var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); - var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); - var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); - var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); - var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 ); - if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { - buffer.o = '$' + buffer.o + '$'; - } - /** @type {ParserOutput[]} */ - var ret = []; - if (hyphenFollows) { - mhchemParser.concatArray(ret, this['output'](buffer)); - ret.push({ type_: 'hyphen' }); - } else { - c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); - if (isAfterD && c1 && c1.remainder==='') { - mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); - mhchemParser.concatArray(ret, this['output'](buffer)); - } else { - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - } - } - return ret; - }, - 'a to o': function (buffer) { - buffer.o = buffer.a; - buffer.a = undefined; - }, - 'sb=true': function (buffer) { buffer.sb = true; }, - 'sb=false': function (buffer) { buffer.sb = false; }, - 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; }, - 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; }, - 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; }, - 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; }, - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') }; - }, - 'comma': function (buffer, m) { - var a = m.replace(/\s*$/, ''); - var withSpace = (a !== m); - if (withSpace && buffer['parenthesisLevel'] === 0) { - return { type_: 'comma enumeration L', p1: a }; - } else { - return { type_: 'comma enumeration M', p1: a }; - } - }, - 'output': function (buffer, m, entityFollows) { - // entityFollows: - // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) - // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) - // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - if (!buffer.r) { - ret = []; - if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { - //ret = []; - } else { - if (buffer.sb) { - ret.push({ type_: 'entitySkip' }); - } - if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) { - buffer.o = buffer.a; - buffer.a = undefined; - } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { - buffer.o = buffer.a; - buffer.d = buffer.b; - buffer.q = buffer.p; - buffer.a = buffer.b = buffer.p = undefined; - } else { - if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { - buffer.dType = 'oxidation'; - } else if (buffer.o && buffer.dType==='kv' && !buffer.q) { - buffer.dType = undefined; - } - } - ret.push({ - type_: 'chemfive', - a: mhchemParser.go(buffer.a, 'a'), - b: mhchemParser.go(buffer.b, 'bd'), - p: mhchemParser.go(buffer.p, 'pq'), - o: mhchemParser.go(buffer.o, 'o'), - q: mhchemParser.go(buffer.q, 'pq'), - d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), - dType: buffer.dType - }); - } - } else { // r - /** @type {ParserOutput[]} */ - var rd; - if (buffer.rdt === 'M') { - rd = mhchemParser.go(buffer.rd, 'tex-math'); - } else if (buffer.rdt === 'T') { - rd = [ { type_: 'text', p1: buffer.rd || "" } ]; - } else { - rd = mhchemParser.go(buffer.rd); - } - /** @type {ParserOutput[]} */ - var rq; - if (buffer.rqt === 'M') { - rq = mhchemParser.go(buffer.rq, 'tex-math'); - } else if (buffer.rqt === 'T') { - rq = [ { type_: 'text', p1: buffer.rq || ""} ]; - } else { - rq = mhchemParser.go(buffer.rq); - } - ret = { - type_: 'arrow', - r: buffer.r, - rd: rd, - rq: rq - }; - } - for (var p in buffer) { - if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { - delete buffer[p]; - } - } - return ret; - }, - 'oxidation-output': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); - ret.push("}"); - return ret; - }, - 'frac-output': function (buffer, m) { - return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'overset-output': function (buffer, m) { - return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underset-output': function (buffer, m) { - return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underbrace-output': function (buffer, m) { - return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) }; - }, - 'r=': function (buffer, m) { buffer.r = m; }, - 'rdt=': function (buffer, m) { buffer.rdt = m; }, - 'rd=': function (buffer, m) { buffer.rd = m; }, - 'rqt=': function (buffer, m) { buffer.rqt = m; }, - 'rq=': function (buffer, m) { buffer.rq = m; }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } - } - }, - 'a': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - '$(...)$': { - '*': { action_: 'tex-math tight', nextState: '1' } }, - ',': { - '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'o': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - 'letters': { - '*': { action_: 'rm' } }, - '\\ca': { - '*': { action_: { type_: 'insert', option: 'circa' } } }, - '\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: '{text}' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'text': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '{...}': { - '*': { action_: 'text=' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '\\greek': { - '*': { action_: [ 'output', 'rm' ] } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: [ 'output', 'copy' ] } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.text_) { - /** @type {ParserOutput} */ - var ret = { type_: 'text', p1: buffer.text_ }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'pq': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'state of aggregation $': { - '*': { action_: 'state of aggregation' } }, - 'i$': { - '0': { nextState: '!f', revisit: true } }, - '(KV letters),': { - '0': { action_: 'rm', nextState: '0' } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'letters': { - '*': { action_: 'rm' } }, - '-9.,9': { - '*': { action_: '9,9' } }, - ',': { - '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') }; - } - } - }, - 'bd': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'x$': { - '0': { nextState: '!f', revisit: true } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '-9.,9 no missing 0': { - '*': { action_: '9,9' } }, - '.': { - '*': { action_: { type_: 'insert', option: 'electron dot' } } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'x': { - '*': { action_: { type_: 'insert', option: 'KV x' } } }, - 'letters': { - '*': { action_: 'rm' } }, - '\'': { - '*': { action_: { type_: 'insert', option: 'prime' } } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') }; - } - } - }, - 'oxidation': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'roman numeral': { - '*': { action_: 'roman-numeral' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; } - } - }, - 'tex-math': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'tex-math tight': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - '-|+': { - '*': { action_: 'tight operator' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; }, - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - '9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - ',': { - '*': { action_: 'comma' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; } - } - }, - //#endregion - // - // \pu state machines - // - //#region pu - 'pu': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - 'space$': { - '*': { action_: [ 'output', 'space' ] } }, - '{[(|)]}': { - '0|a': { action_: 'copy' } }, - '(-)(9)^(-9)': { - '0': { action_: 'number^', nextState: 'a' } }, - '(-)(9.,9)(e)(99)': { - '0': { action_: 'enumber', nextState: 'a' } }, - 'space': { - '0|a': {} }, - 'pm-operator': { - '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } }, - 'operator': { - '0|a': { action_: 'copy', nextState: '0' } }, - '//': { - 'd': { action_: 'o=', nextState: '/' } }, - '/': { - 'd': { action_: 'o=', nextState: '/' } }, - '{...}|else': { - '0|d': { action_: 'd=', nextState: 'd' }, - 'a': { action_: [ 'space', 'd=' ], nextState: 'd' }, - '/|q': { action_: 'q=', nextState: 'q' } } - }), - actions: { - 'enumber': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - if (m[1]) { - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - if (m[2]) { - if (m[2].match(/[,.]/)) { - mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); - } else { - ret.push(m[2]); - } - } - m[3] = m[4] || m[3]; - if (m[3]) { - m[3] = m[3].trim(); - if (m[3] === "e" || m[3].substr(0, 1) === "*") { - ret.push({ type_: 'cdot' }); - } else { - ret.push({ type_: 'times' }); - } - } - } - if (m[3]) { - ret.push("10^{"+m[5]+"}"); - } - return ret; - }, - 'number^': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - ret.push("^{"+m[2]+"}"); - return ret; - }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }, - 'space': function () { return { type_: 'pu-space-1' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); - if (md && md.remainder === '') { buffer.d = md.match_; } - var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); - if (mq && mq.remainder === '') { buffer.q = mq.match_; } - if (buffer.d) { - buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - } - if (buffer.q) { // fraction - buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - var b5 = { - d: mhchemParser.go(buffer.d, 'pu'), - q: mhchemParser.go(buffer.q, 'pu') - }; - if (buffer.o === '//') { - ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q }; - } else { - ret = b5.d; - if (b5.d.length > 1 || b5.q.length > 1) { - ret.push({ type_: ' / ' }); - } else { - ret.push({ type_: '/' }); - } - mhchemParser.concatArray(ret, b5.q); - } - } else { // no fraction - ret = mhchemParser.go(buffer.d, 'pu-2'); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-2': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '*': { - '*': { action_: [ 'output', 'cdot' ], nextState: '0' } }, - '\\x': { - '*': { action_: 'rm=' } }, - 'space': { - '*': { action_: [ 'output', 'space' ], nextState: '0' } }, - '^{(...)}|^(-1)': { - '1': { action_: '^(-1)' } }, - '-9.,9': { - '0': { action_: 'rm=', nextState: '0' }, - '1': { action_: '^(-1)', nextState: '0' } }, - '{...}|else': { - '*': { action_: 'rm=', nextState: '1' } } - }), - actions: { - 'cdot': function () { return { type_: 'tight cdot' }; }, - '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; }, - 'space': function () { return { type_: 'pu-space-2' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret = []; - if (buffer.rm) { - var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); - if (mrm && mrm.remainder === '') { - ret = mhchemParser.go(mrm.match_, 'pu'); - } else { - ret = { type_: 'rm', p1: buffer.rm }; - } - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '0': { action_: 'output-0' }, - 'o': { action_: 'output-o' } }, - ',': { - '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } }, - '.': { - '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; }, - 'output-0': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length % 3; - if (a === 0) { a = 3; } - for (var i=buffer.text_.length-3; i>0; i-=3) { - ret.push(buffer.text_.substr(i, 3)); - ret.push({ type_: '1000 separator' }); - } - ret.push(buffer.text_.substr(0, a)); - ret.reverse(); - } else { - ret.push(buffer.text_); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - }, - 'output-o': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length - 3; - for (var i=0; i, so we change \vphantom{X} to {} - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - } else { - if (b5.q) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - if (b5.d) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "^{"+b5.d+"}"; - } - } - break; - case 'rm': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'text': - if (buf.p1.match(/[\^_]/)) { - buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}"); - res = "\\mathrm{"+buf.p1+"}"; - } else { - res = "\\text{"+buf.p1+"}"; - } - break; - case 'roman numeral': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'state of aggregation': - res = "\\mskip2mu "+texify._goInner(buf.p1); - break; - case 'state of aggregation subscript': - res = "\\mskip1mu "+texify._goInner(buf.p1); - break; - case 'bond': - res = texify._getBond(buf.kind_); - if (!res) { - throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"]; - } - break; - case 'frac': - var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}"; - res = "\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}"; - break; - case 'pu-frac': - var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - res = "\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}"; - break; - case 'tex-math': - res = buf.p1 + " "; - break; - case 'frac-ce': - res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'overset': - res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underset': - res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underbrace': - res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}"; - break; - case 'color': - res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}"; - break; - case 'color0': - res = "\\color{" + buf.color + "}"; - break; - case 'arrow': - var b6 = { - rd: texify._goInner(buf.rd), - rq: texify._goInner(buf.rq) - }; - var arrow = texify._getArrow(buf.r); - if (b6.rq) { arrow += "[{\\rm " + b6.rq + "}]"; } - if (b6.rd) { - arrow += "{\\rm " + b6.rd + "}"; - } else { - arrow += "{}"; - } - res = arrow; - break; - case 'operator': - res = texify._getOperator(buf.kind_); - break; - case '1st-level escape': - res = buf.p1+" "; // &, \\\\, \\hlin - break; - case 'space': - res = " "; - break; - case 'entitySkip': - res = "~"; - break; - case 'pu-space-1': - res = "~"; - break; - case 'pu-space-2': - res = "\\mkern3mu "; - break; - case '1000 separator': - res = "\\mkern2mu "; - break; - case 'commaDecimal': - res = "{,}"; - break; - case 'comma enumeration L': - res = "{"+buf.p1+"}\\mkern6mu "; - break; - case 'comma enumeration M': - res = "{"+buf.p1+"}\\mkern3mu "; - break; - case 'comma enumeration S': - res = "{"+buf.p1+"}\\mkern1mu "; - break; - case 'hyphen': - res = "\\text{-}"; - break; - case 'addition compound': - res = "\\,{\\cdot}\\,"; - break; - case 'electron dot': - res = "\\mkern1mu \\text{\\textbullet}\\mkern1mu "; - break; - case 'KV x': - res = "{\\times}"; - break; - case 'prime': - res = "\\prime "; - break; - case 'cdot': - res = "\\cdot "; - break; - case 'tight cdot': - res = "\\mkern1mu{\\cdot}\\mkern1mu "; - break; - case 'times': - res = "\\times "; - break; - case 'circa': - res = "{\\sim}"; - break; - case '^': - res = "uparrow"; - break; - case 'v': - res = "downarrow"; - break; - case 'ellipsis': - res = "\\ldots "; - break; - case '/': - res = "/"; - break; - case ' / ': - res = "\\,/\\,"; - break; - default: - assertNever(buf); - throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output - } - assertString(res); - return res; - }, - _getArrow: function (a) { - switch (a) { - case "->": return "\\yields"; - case "\u2192": return "\\yields"; - case "\u27F6": return "\\yields"; - case "<-": return "\\yieldsLeft"; - case "<->": return "\\mesomerism"; - case "<-->": return "\\yieldsLeftRight"; - case "<=>": return "\\equilibrium"; - case "\u21CC": return "\\equilibrium"; - case "<=>>": return "\\equilibriumRight"; - case "<<=>": return "\\equilibriumLeft"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getBond: function (a) { - switch (a) { - case "-": return "{-}"; - case "1": return "{-}"; - case "=": return "{=}"; - case "2": return "{=}"; - case "#": return "{\\equiv}"; - case "3": return "{\\equiv}"; - case "~": return "{\\tripleDash}"; - case "~-": return "{\\tripleDashOverLine}"; - case "~=": return "{\\tripleDashOverDoubleLine}"; - case "~--": return "{\\tripleDashOverDoubleLine}"; - case "-~-": return "{\\tripleDashBetweenDoubleLine}"; - case "...": return "{{\\cdot}{\\cdot}{\\cdot}}"; - case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; - case "->": return "{\\rightarrow}"; - case "<-": return "{\\leftarrow}"; - case "<": return "{<}"; - case ">": return "{>}"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getOperator: function (a) { - switch (a) { - case "+": return " {}+{} "; - case "-": return " {}-{} "; - case "=": return " {}={} "; - case "<": return " {}<{} "; - case ">": return " {}>{} "; - case "<<": return " {}\\ll{} "; - case ">>": return " {}\\gg{} "; - case "\\pm": return " {}\\pm{} "; - case "\\approx": return " {}\\approx{} "; - case "$\\approx$": return " {}\\approx{} "; - case "v": return " \\downarrow{} "; - case "(v)": return " \\downarrow{} "; - case "^": return " \\uparrow{} "; - case "(^)": return " \\uparrow{} "; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - - // - // Helpers for code anaylsis - // Will show type error at calling position - // - /** @param {number} a */ - function assertNever(a) {} - /** @param {string} a */ - function assertString(a) {} diff --git a/contrib/mhchem/mhchem.min.js b/contrib/mhchem/mhchem.min.js deleted file mode 100644 index 2eafa389..00000000 --- a/contrib/mhchem/mhchem.min.js +++ /dev/null @@ -1 +0,0 @@ -temml.__defineMacro("\\ce",(function(t){return chemParse(t.consumeArgs(1)[0],"ce")})),temml.__defineMacro("\\pu",(function(t){return chemParse(t.consumeArgs(1)[0],"pu")})),temml.__defineMacro("\\uniDash","{\\rule{0.672em}{0.06em}}"),temml.__defineMacro("\\triDash","{\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}}"),temml.__defineMacro("\\tripleDash","\\kern0.075em\\raise0.25em{\\triDash}\\kern0.075em"),temml.__defineMacro("\\tripleDashOverLine","\\kern0.075em\\mathrlap{\\raise0.125em{\\uniDash}}\\raise0.34em{\\triDash}\\kern0.075em"),temml.__defineMacro("\\tripleDashOverDoubleLine","\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\triDash}}\\raise0.27em{\\uniDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em"),temml.__defineMacro("\\tripleDashBetweenDoubleLine","\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\uniDash}}\\raise0.27em{\\triDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em");var chemParse=function(t,e){for(var r="",a=t.length&&t[t.length-1].loc.start,n=t.length-1;n>=0;n--)t[n].loc.start>a&&(r+=" ",a=t[n].loc.start),r+=t[n].text,a+=t[n].text.length;return texify.go(mhchemParser.go(r,e))},mhchemParser={go:function(t,e){if(!t)return[];void 0===e&&(e="ce");var r,a="0",n={};n.parenthesisLevel=0,t=(t=(t=t.replace(/\n/g," ")).replace(/[\u2212\u2013\u2014\u2010]/g,"-")).replace(/[\u2026]/g,"...");for(var o=10,i=[];;){r!==t?(o=10,r=t):o--;var c=mhchemParser.stateMachines[e],s=c.transitions[a]||c.transitions["*"];t:for(var u=0;u0))return i;if(m.revisit||(t=p.remainder),!m.toContinue)break t}}if(o<=0)throw["MhchemBugU","mhchem bug U. Please report."]}},concatArray:function(t,e){if(e)if(Array.isArray(e))for(var r=0;r":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(t){return mhchemParser.patterns.findObserveGroups(t,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(t){return mhchemParser.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",!0)},"\\x{}":function(t){return mhchemParser.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}0":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\color{","","","}")},"\\color{(...)}{(...)}1":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\color{","","","}","{","","","}")},"\\color(...){(...)}2":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\ce{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(t){var e;if(e=t.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/))return{match_:e[0],remainder:t.substr(e[0].length)};var r=mhchemParser.patterns.findObserveGroups(t,"","$","$","");return r&&(e=r.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/))?{match_:e[0],remainder:t.substr(e[0].length)}:null},amount2:function(t){return this.amount(t)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(t){if(t.match(/^\([a-z]+\)$/))return null;var e=t.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);return e?{match_:e[0],remainder:t.substr(e[0].length)}:null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(t,e,r,a,n,o,i,c,s,u){var p=function(t,e){if("string"==typeof e)return 0!==t.indexOf(e)?null:e;var r=t.match(e);return r?r[0]:null},m=p(t,e);if(null===m)return null;if(t=t.substr(m.length),null===(m=p(t,r)))return null;var h=function(t,e,r){for(var a=0;e":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:!1},nextState:"2"},q:{action_:{type_:"- after o/d",option:!1},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:!0},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{}},space:{a:{nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". |* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}0":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:!0},as:{action_:["output","sb=true"],nextState:"1",revisit:!0},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:!0},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(t,e){var r;if((t.d||"").match(/^[0-9]+$/)){var a=t.d;t.d=void 0,r=this.output(t),t.b=a}else r=this.output(t);return mhchemParser.actions["o="](t,e),r},"d= kv":function(t,e){t.d=e,t.dType="kv"},"charge or bond":function(t,e){if(t.beginsWithBond){var r=[];return mhchemParser.concatArray(r,this.output(t)),mhchemParser.concatArray(r,mhchemParser.actions.bond(t,e,"-")),r}t.d=e},"- after o/d":function(t,e,r){var a=mhchemParser.patterns.match_("orbital",t.o||""),n=mhchemParser.patterns.match_("one lowercase greek letter $",t.o||""),o=mhchemParser.patterns.match_("one lowercase latin letter $",t.o||""),i=mhchemParser.patterns.match_("$one lowercase latin letter$ $",t.o||""),c="-"===e&&(a&&""===a.remainder||n||o||i);!c||t.a||t.b||t.p||t.d||t.q||a||!o||(t.o="$"+t.o+"$");var s=[];return c?(mhchemParser.concatArray(s,this.output(t)),s.push({type_:"hyphen"})):(a=mhchemParser.patterns.match_("digits",t.d||""),r&&a&&""===a.remainder?(mhchemParser.concatArray(s,mhchemParser.actions["d="](t,e)),mhchemParser.concatArray(s,this.output(t))):(mhchemParser.concatArray(s,this.output(t)),mhchemParser.concatArray(s,mhchemParser.actions.bond(t,e,"-")))),s},"a to o":function(t){t.o=t.a,t.a=void 0},"sb=true":function(t){t.sb=!0},"sb=false":function(t){t.sb=!1},"beginsWithBond=true":function(t){t.beginsWithBond=!0},"beginsWithBond=false":function(t){t.beginsWithBond=!1},"parenthesisLevel++":function(t){t.parenthesisLevel++},"parenthesisLevel--":function(t){t.parenthesisLevel--},"state of aggregation":function(t,e){return{type_:"state of aggregation",p1:mhchemParser.go(e,"o")}},comma:function(t,e){var r=e.replace(/\s*$/,"");return r!==e&&0===t.parenthesisLevel?{type_:"comma enumeration L",p1:r}:{type_:"comma enumeration M",p1:r}},output:function(t,e,r){var a,n,o;t.r?(n="M"===t.rdt?mhchemParser.go(t.rd,"tex-math"):"T"===t.rdt?[{type_:"text",p1:t.rd||""}]:mhchemParser.go(t.rd),o="M"===t.rqt?mhchemParser.go(t.rq,"tex-math"):"T"===t.rqt?[{type_:"text",p1:t.rq||""}]:mhchemParser.go(t.rq),a={type_:"arrow",r:t.r,rd:n,rq:o}):(a=[],(t.a||t.b||t.p||t.o||t.q||t.d||r)&&(t.sb&&a.push({type_:"entitySkip"}),t.o||t.q||t.d||t.b||t.p||2===r?t.o||t.q||t.d||!t.b&&!t.p?t.o&&"kv"===t.dType&&mhchemParser.patterns.match_("d-oxidation$",t.d||"")?t.dType="oxidation":t.o&&"kv"===t.dType&&!t.q&&(t.dType=void 0):(t.o=t.a,t.d=t.b,t.q=t.p,t.a=t.b=t.p=void 0):(t.o=t.a,t.a=void 0),a.push({type_:"chemfive",a:mhchemParser.go(t.a,"a"),b:mhchemParser.go(t.b,"bd"),p:mhchemParser.go(t.p,"pq"),o:mhchemParser.go(t.o,"o"),q:mhchemParser.go(t.q,"pq"),d:mhchemParser.go(t.d,"oxidation"===t.dType?"oxidation":"bd"),dType:t.dType})));for(var i in t)"parenthesisLevel"!==i&&"beginsWithBond"!==i&&delete t[i];return a},"oxidation-output":function(t,e){var r=["{"];return mhchemParser.concatArray(r,mhchemParser.go(e,"oxidation")),r.push("}"),r},"frac-output":function(t,e){return{type_:"frac-ce",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"overset-output":function(t,e){return{type_:"overset",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"underset-output":function(t,e){return{type_:"underset",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"underbrace-output":function(t,e){return{type_:"underbrace",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:mhchemParser.go(e[1])}},"r=":function(t,e){t.r=e},"rdt=":function(t,e){t.rdt=e},"rd=":function(t,e){t.rd=e},"rqt=":function(t,e){t.rqt=e},"rq=":function(t,e){t.rq=e},operator:function(t,e,r){return{type_:"operator",kind_:r||e}}}},a:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},"$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"{text}"}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(t){if(t.text_){var e={type_:"text",p1:t.text_};for(var r in t)delete t[r];return e}}}},pq:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{nextState:"!f",revisit:!0}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{nextState:"f",revisit:!0}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"!f",revisit:!0}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(t,e){return{type_:"state of aggregation subscript",p1:mhchemParser.go(e,"o")}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:mhchemParser.go(e[1],"pq")}}}},bd:{transitions:mhchemParser.createTransitions({empty:{"*":{}},x$:{0:{nextState:"!f",revisit:!0}},formula$:{0:{nextState:"f",revisit:!0}},else:{0:{nextState:"!f",revisit:!0}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(t,e){return{type_:"color",color1:e[0],color2:mhchemParser.go(e[1],"bd")}}}},oxidation:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(t,e){return{type_:"roman numeral",p1:e||""}}}},"tex-math":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var r in t)delete t[r];return e}}}},"tex-math tight":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(t,e){t.o=(t.o||"")+"{"+e+"}"},output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var r in t)delete t[r];return e}}}},"9,9":{transitions:mhchemParser.createTransitions({empty:{"*":{}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return{type_:"commaDecimal"}}}},pu:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(t,e){var r=[];return"+-"===e[0]||"+/-"===e[0]?r.push("\\pm "):e[0]&&r.push(e[0]),e[1]&&(mhchemParser.concatArray(r,mhchemParser.go(e[1],"pu-9,9")),e[2]&&(e[2].match(/[,.]/)?mhchemParser.concatArray(r,mhchemParser.go(e[2],"pu-9,9")):r.push(e[2])),e[3]=e[4]||e[3],e[3]&&(e[3]=e[3].trim(),"e"===e[3]||"*"===e[3].substr(0,1)?r.push({type_:"cdot"}):r.push({type_:"times"}))),e[3]&&r.push("10^{"+e[5]+"}"),r},"number^":function(t,e){var r=[];return"+-"===e[0]||"+/-"===e[0]?r.push("\\pm "):e[0]&&r.push(e[0]),mhchemParser.concatArray(r,mhchemParser.go(e[1],"pu-9,9")),r.push("^{"+e[2]+"}"),r},operator:function(t,e,r){return{type_:"operator",kind_:r||e}},space:function(){return{type_:"pu-space-1"}},output:function(t){var e,r=mhchemParser.patterns.match_("{(...)}",t.d||"");r&&""===r.remainder&&(t.d=r.match_);var a=mhchemParser.patterns.match_("{(...)}",t.q||"");if(a&&""===a.remainder&&(t.q=a.match_),t.d&&(t.d=t.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.d=t.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F")),t.q){t.q=t.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.q=t.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");var n={d:mhchemParser.go(t.d,"pu"),q:mhchemParser.go(t.q,"pu")};"//"===t.o?e={type_:"pu-frac",p1:n.d,p2:n.q}:(e=n.d,n.d.length>1||n.q.length>1?e.push({type_:" / "}):e.push({type_:"/"}),mhchemParser.concatArray(e,n.q))}else e=mhchemParser.go(t.d,"pu-2");for(var o in t)delete t[o];return e}}},"pu-2":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return{type_:"tight cdot"}},"^(-1)":function(t,e){t.rm+="^{"+e+"}"},space:function(){return{type_:"pu-space-2"}},output:function(t){var e=[];if(t.rm){var r=mhchemParser.patterns.match_("{(...)}",t.rm||"");e=r&&""===r.remainder?mhchemParser.go(r.match_,"pu"):{type_:"rm",p1:t.rm}}for(var a in t)delete t[a];return e}}},"pu-9,9":{transitions:mhchemParser.createTransitions({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return{type_:"commaDecimal"}},"output-0":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){var r=t.text_.length%3;0===r&&(r=3);for(var a=t.text_.length-3;a>0;a-=3)e.push(t.text_.substr(a,3)),e.push({type_:"1000 separator"});e.push(t.text_.substr(0,r)),e.reverse()}else e.push(t.text_);for(var n in t)delete t[n];return e},"output-o":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){for(var r=t.text_.length-3,a=0;a":case"→":case"⟶":return"\\yields";case"<-":return"\\yieldsLeft";case"<->":return"\\mesomerism";case"<--\x3e":return"\\yieldsLeftRight";case"<=>":case"⇌":return"\\equilibrium";case"<=>>":return"\\equilibriumRight";case"<<=>":return"\\equilibriumLeft";default:throw assertNever(t),["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(t){switch(t){case"-":case"1":return"{-}";case"=":case"2":return"{=}";case"#":case"3":return"{\\equiv}";case"~":return"{\\tripleDash}";case"~-":return"{\\tripleDashOverLine}";case"~=":case"~--":return"{\\tripleDashOverDoubleLine}";case"-~-":return"{\\tripleDashBetweenDoubleLine}";case"...":return"{{\\cdot}{\\cdot}{\\cdot}}";case"....":return"{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case"->":return"{\\rightarrow}";case"<-":return"{\\leftarrow}";case"<":return"{<}";case">":return"{>}";default:throw assertNever(t),["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(t){switch(t){case"+":return" {}+{} ";case"-":return" {}-{} ";case"=":return" {}={} ";case"<":return" {}<{} ";case">":return" {}>{} ";case"<<":return" {}\\ll{} ";case">>":return" {}\\gg{} ";case"\\pm":return" {}\\pm{} ";case"\\approx":case"$\\approx$":return" {}\\approx{} ";case"v":case"(v)":return" \\downarrow{} ";case"^":case"(^)":return" \\uparrow{} ";default:throw assertNever(t),["MhchemBugT","mhchem bug T. Please report."]}}};function assertNever(t){}function assertString(t){} \ No newline at end of file diff --git a/contrib/physics/README.md b/contrib/physics/README.md deleted file mode 100644 index 5df6d4e6..00000000 --- a/contrib/physics/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# physics extension - -This extension adds to Temml many of the functions from the LaTeX [physics package](https://www.ctan.org/tex-archive/macros/latex/contrib/physics). - -You can download the `physics.js` file from this repository. - -### Usage - -This extension isn't part of core Temml, so the script should be separately included in the HTML page's ``. Place it _after_ the line that calls `temml.js`. - -```html - - -``` - -If you are working sever-side, just use `temml.cjs`. It already includes all the functions in `physics.js`. - -### Syntax - -All the functions in the physics extension are listed in the [physics section](https://temml.org/docs/en/supported.html#physics-and-chemistry) (below the fold) of the Temml docs. diff --git a/contrib/physics/physics.js b/contrib/physics/physics.js deleted file mode 100644 index 961e7f22..00000000 --- a/contrib/physics/physics.js +++ /dev/null @@ -1,131 +0,0 @@ -/* eslint-disable no-undef */ - -/**************************************************** - * - * physics.js - * - * Implements the Physics Package for LaTeX input. - * - * --------------------------------------------------------------------- - * - * The original version of this file is licensed as follows: - * Copyright (c) 2015-2016 Kolen Cheung . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * --------------------------------------------------------------------- - * - * This file has been revised from the original in the following ways: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \Re and \Im are not used, to avoid conflict with existing LaTeX letters. - * - * This revision of the file is released under the MIT license. - * https://mit-license.org/ - */ -temml.__defineMacro("\\quantity", "{\\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\qty", "{\\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\pqty", "{\\left( #1 \\right)}"); -temml.__defineMacro("\\bqty", "{\\left[ #1 \\right]}"); -temml.__defineMacro("\\vqty", "{\\left\\vert #1 \\right\\vert}"); -temml.__defineMacro("\\Bqty", "{\\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\absolutevalue", "{\\left\\vert #1 \\right\\vert}"); -temml.__defineMacro("\\abs", "{\\left\\vert #1 \\right\\vert}"); -temml.__defineMacro("\\norm", "{\\left\\Vert #1 \\right\\Vert}"); -temml.__defineMacro("\\evaluated", "{\\left.#1 \\right\\vert}"); -temml.__defineMacro("\\eval", "{\\left.#1 \\right\\vert}"); -temml.__defineMacro("\\order", "{\\mathcal{O} \\left( #1 \\right)}"); -temml.__defineMacro("\\commutator", "{\\left[ #1 , #2 \\right]}"); -temml.__defineMacro("\\comm", "{\\left[ #1 , #2 \\right]}"); -temml.__defineMacro("\\anticommutator", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\acomm", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\poissonbracket", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\pb", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\vectorbold", "{\\boldsymbol{ #1 }}"); -temml.__defineMacro("\\vb", "{\\boldsymbol{ #1 }}"); -temml.__defineMacro("\\vectorarrow", "{\\vec{\\boldsymbol{ #1 }}}"); -temml.__defineMacro("\\va", "{\\vec{\\boldsymbol{ #1 }}}"); -temml.__defineMacro("\\vectorunit", "{{\\boldsymbol{\\hat{ #1 }}}}"); -temml.__defineMacro("\\vu", "{{\\boldsymbol{\\hat{ #1 }}}}"); -temml.__defineMacro("\\dotproduct", "\\mathbin{\\boldsymbol\\cdot}"); -temml.__defineMacro("\\vdot", "{\\boldsymbol\\cdot}"); -temml.__defineMacro("\\crossproduct", "\\mathbin{\\boldsymbol\\times}"); -temml.__defineMacro("\\cross", "\\mathbin{\\boldsymbol\\times}"); -temml.__defineMacro("\\cp", "\\mathbin{\\boldsymbol\\times}"); -temml.__defineMacro("\\gradient", "{\\boldsymbol\\nabla}"); -temml.__defineMacro("\\grad", "{\\boldsymbol\\nabla}"); -temml.__defineMacro("\\divergence", "{\\grad\\vdot}"); -//temml.__defineMacro("\\div", "{\\grad\\vdot}"); Not included in Temml. Conflicts w/LaTeX \div -temml.__defineMacro("\\curl", "{\\grad\\cross}"); -temml.__defineMacro("\\laplacian", "\\nabla^2"); -temml.__defineMacro("\\tr", "{\\operatorname{tr}}"); -temml.__defineMacro("\\Tr", "{\\operatorname{Tr}}"); -temml.__defineMacro("\\rank", "{\\operatorname{rank}}"); -temml.__defineMacro("\\erf", "{\\operatorname{erf}}"); -temml.__defineMacro("\\Res", "{\\operatorname{Res}}"); -temml.__defineMacro("\\principalvalue", "{\\mathcal{P}}"); -temml.__defineMacro("\\pv", "{\\mathcal{P}}"); -temml.__defineMacro("\\PV", "{\\operatorname{P.V.}}"); -// Temml does not use the next two lines. They conflict with LaTeX letters. -//temml.__defineMacro("\\Re", "{\\operatorname{Re} \\left\\{ #1 \\right\\}}"); -//temml.__defineMacro("\\Im", "{\\operatorname{Im} \\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\qqtext", "{\\quad\\text{ #1 }\\quad}"); -temml.__defineMacro("\\qq", "{\\quad\\text{ #1 }\\quad}"); -temml.__defineMacro("\\qcomma", "{\\text{,}\\quad}"); -temml.__defineMacro("\\qc", "{\\text{,}\\quad}"); -temml.__defineMacro("\\qcc", "{\\quad\\text{c.c.}\\quad}"); -temml.__defineMacro("\\qif", "{\\quad\\text{if}\\quad}"); -temml.__defineMacro("\\qthen", "{\\quad\\text{then}\\quad}"); -temml.__defineMacro("\\qelse", "{\\quad\\text{else}\\quad}"); -temml.__defineMacro("\\qotherwise", "{\\quad\\text{otherwise}\\quad}"); -temml.__defineMacro("\\qunless", "{\\quad\\text{unless}\\quad}"); -temml.__defineMacro("\\qgiven", "{\\quad\\text{given}\\quad}"); -temml.__defineMacro("\\qusing", "{\\quad\\text{using}\\quad}"); -temml.__defineMacro("\\qassume", "{\\quad\\text{assume}\\quad}"); -temml.__defineMacro("\\qsince", "{\\quad\\text{since}\\quad}"); -temml.__defineMacro("\\qlet", "{\\quad\\text{let}\\quad}"); -temml.__defineMacro("\\qfor", "{\\quad\\text{for}\\quad}"); -temml.__defineMacro("\\qall", "{\\quad\\text{all}\\quad}"); -temml.__defineMacro("\\qeven", "{\\quad\\text{even}\\quad}"); -temml.__defineMacro("\\qodd", "{\\quad\\text{odd}\\quad}"); -temml.__defineMacro("\\qinteger", "{\\quad\\text{integer}\\quad}"); -temml.__defineMacro("\\qand", "{\\quad\\text{and}\\quad}"); -temml.__defineMacro("\\qor", "{\\quad\\text{or}\\quad}"); -temml.__defineMacro("\\qas", "{\\quad\\text{as}\\quad}"); -temml.__defineMacro("\\qin", "{\\quad\\text{in}\\quad}"); -temml.__defineMacro("\\differential", "{\\text{d}}"); -temml.__defineMacro("\\dd", "{\\text{d}}"); -temml.__defineMacro("\\derivative", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -temml.__defineMacro("\\dv", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -temml.__defineMacro("\\partialderivative", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}"); -temml.__defineMacro("\\variation", "{\\delta}"); -temml.__defineMacro("\\var", "{\\delta}"); -temml.__defineMacro("\\functionalderivative", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -temml.__defineMacro("\\fdv", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -temml.__defineMacro("\\innerproduct", "{\\left\\langle {#1} \\mid { #2} \\right\\rangle}"); -temml.__defineMacro("\\outerproduct", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\dyad", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\ketbra", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\op", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\expectationvalue", "{\\left\\langle {#1 } \\right\\rangle}"); -temml.__defineMacro("\\expval", "{\\left\\langle {#1 } \\right\\rangle}"); -temml.__defineMacro("\\ev", "{\\left\\langle {#1 } \\right\\rangle}"); -temml.__defineMacro("\\matrixelement", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -temml.__defineMacro("\\matrixel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -temml.__defineMacro("\\mel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); diff --git a/contrib/texvc/README.md b/contrib/texvc/README.md deleted file mode 100644 index 2b6d8cac..00000000 --- a/contrib/texvc/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# texvc extension - -This extension adds to Temml functions available in mediawiki pages. - -It omits the functions deprecated at -https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax - -You can download the `texvc.js` file from this repository. - -### Usage - -This extension isn't part of core Temml, so the script should be separately included in the HTML page's ``. Place it _after_ the line that calls `temml.js`. - -```html - - -``` - -If you are working sever-side, just use `temml.cjs`. It already includes all the functions in `texvc.js`. - -### Syntax - -All the functions in the _texvc_ extension are listed in the [Temml docs](https://temml.org/docs/en/supported.html). diff --git a/contrib/texvc/texvc.js b/contrib/texvc/texvc.js deleted file mode 100644 index ddd5b1aa..00000000 --- a/contrib/texvc/texvc.js +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable no-undef */ - -////////////////////////////////////////////////////////////////////// -// texvc.sty - -// The texvc package contains macros available in mediawiki pages. -// We omit the functions deprecated at -// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax - -// We also omit texvc's \O, which conflicts with \text{\O} - -temml.__defineMacro("\\darr", "\\downarrow"); -temml.__defineMacro("\\dArr", "\\Downarrow"); -temml.__defineMacro("\\Darr", "\\Downarrow"); -temml.__defineMacro("\\lang", "\\langle"); -temml.__defineMacro("\\rang", "\\rangle"); -temml.__defineMacro("\\uarr", "\\uparrow"); -temml.__defineMacro("\\uArr", "\\Uparrow"); -temml.__defineMacro("\\Uarr", "\\Uparrow"); -temml.__defineMacro("\\N", "\\mathbb{N}"); -temml.__defineMacro("\\R", "\\mathbb{R}"); -temml.__defineMacro("\\Z", "\\mathbb{Z}"); -temml.__defineMacro("\\alef", "\\aleph"); -temml.__defineMacro("\\alefsym", "\\aleph"); -temml.__defineMacro("\\bull", "\\bullet"); -temml.__defineMacro("\\clubs", "\\clubsuit"); -temml.__defineMacro("\\cnums", "\\mathbb{C}"); -temml.__defineMacro("\\Complex", "\\mathbb{C}"); -temml.__defineMacro("\\Dagger", "\\ddagger"); -temml.__defineMacro("\\diamonds", "\\diamondsuit"); -temml.__defineMacro("\\empty", "\\emptyset"); -temml.__defineMacro("\\exist", "\\exists"); -temml.__defineMacro("\\harr", "\\leftrightarrow"); -temml.__defineMacro("\\hArr", "\\Leftrightarrow"); -temml.__defineMacro("\\Harr", "\\Leftrightarrow"); -temml.__defineMacro("\\hearts", "\\heartsuit"); -temml.__defineMacro("\\image", "\\Im"); -temml.__defineMacro("\\infin", "\\infty"); -temml.__defineMacro("\\isin", "\\in"); -temml.__defineMacro("\\larr", "\\leftarrow"); -temml.__defineMacro("\\lArr", "\\Leftarrow"); -temml.__defineMacro("\\Larr", "\\Leftarrow"); -temml.__defineMacro("\\lrarr", "\\leftrightarrow"); -temml.__defineMacro("\\lrArr", "\\Leftrightarrow"); -temml.__defineMacro("\\Lrarr", "\\Leftrightarrow"); -temml.__defineMacro("\\natnums", "\\mathbb{N}"); -temml.__defineMacro("\\plusmn", "\\pm"); -temml.__defineMacro("\\rarr", "\\rightarrow"); -temml.__defineMacro("\\rArr", "\\Rightarrow"); -temml.__defineMacro("\\Rarr", "\\Rightarrow"); -temml.__defineMacro("\\real", "\\Re"); -temml.__defineMacro("\\reals", "\\mathbb{R}"); -temml.__defineMacro("\\Reals", "\\mathbb{R}"); -temml.__defineMacro("\\sdot", "\\cdot"); -temml.__defineMacro("\\sect", "\\S"); -temml.__defineMacro("\\spades", "\\spadesuit"); -temml.__defineMacro("\\sub", "\\subset"); -temml.__defineMacro("\\sube", "\\subseteq"); -temml.__defineMacro("\\supe", "\\supseteq"); -temml.__defineMacro("\\thetasym", "\\vartheta"); -temml.__defineMacro("\\weierp", "\\wp"); diff --git a/docs/administration.md b/docs/administration.md deleted file mode 100644 index 321e5dfa..00000000 --- a/docs/administration.md +++ /dev/null @@ -1,385 +0,0 @@ - - - - - - Temml Administration - - - - -
- -# Temml Administration - -# Browser Support - -Temml works in browsers that support MathML. This includes Firefox and Safari. -It will [soon](https://www.igalia.com/2021/08/09/MathML-Progress.html) include -Chrome, Edge, Opera, Brave, and Vivaldi.\ -Temml will never work in Internet Explorer. - -# Installation - -You can download a zip file of Temml from the [releases page][] of the Temml repository -and serve Temml files from your own site. The minimum browser installation needs the -following files. The `css` file and font file must be in the same folder. - -[releases page]: https://github.com/ronkok/Temml/releases - -* temml.min.js -* Temml-Local.css -* Temml.woff2 - -A server-side installation should include `temml.cjs` instead of `temml.min.js`. - -#### Starter template - -```html - - - - - ... - - - - ... - -``` - -# API - -### Overview - -Say that you have an HTMLCollection of elements whose contents should be converted from TeX -strings to math. And also say that you wish to define two macros and a color with document-wide -scope. The code for such a conversion might look like this: - -```js -// Optional preamble. -const macros = temml.definePreamble( - `\\newcommand\\d[0]{\\operatorname{d}\\!} - \\def\\foo{x^2} - \\definecolor{sortaGreen}{RGB}{128,128,0}` -); -// Render all the math. -for (let aSpan of [...mathSpans]) { - const tex = aSpan.textContent; - const displayMode = aSpan.classList.contains("display"); - temml.render(tex, aSpan, { macros, displayMode }); -} -// Optional postProcess to render \ref{} -temml.postProcess(document.body); -``` - -Below, we examine the parts of that code. - -### In-Browser - -To render math in one DOM element, call `temml.render` with a TeX expression -and a DOM element to render into: - -```js -temml.render("c = \\pm\\sqrt{a^2 + b^2}", element); -``` - -### Server-Side - -To generate MathML on the server or to generate an MathML string of the -rendered math, you can use `temml.renderToString`: - -```js -const temml = require('./temml.cjs'); // if in Node.js -const mathML = temml.renderToString("c = \\pm\\sqrt{a^2 + b^2}"); -``` - -### Preamble - -To give document-wide scope to a set of macros or colors, define them in a preamble. - -```js -const macros = temml.definePreamble( - `\\newcommand\\d[0]{\\operatorname{d}\\!} - \\def\\foo{x^2} - \\definecolor{sortaGreen}{RGB}{128,128,0}` -); -``` - -Any valid [Temml macro](supported.html#macros) or [\definecolor](supported.html#style-color-size-and-font) -may be written into a preamble. Then include the resulting macros in the Temml options. - -### Options - -You can provide an object of options as the last argument to `temml.render` and `temml.renderToString`. For example: - -```js -temml.render( - "c = \\pm\\sqrt{a^2 + b^2}", - element, - { displayMode: true, macros } -); -``` - -Available options are: - -- `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`) - -- `macros`: `object`. A collection of custom macros. The easy way to create them is via a preamble, noted just above. Alternatively, you can provide a set of key-value pairs in which each key is a new Temml function name and each value is the expansion of the macro. Example: `macros: {"\\R": "\\mathbb{R}"}`. - -- `annotate`: `boolean`. If `true`, Temml will include an `` element that contains the input TeX string. Note: this will defeat [soft line breaks](./supported.html#line-breaks) in Firefox. (default: `false`) - -- `elementIsMath`: `boolean`. When you call the `temml.render()` function, you pass an `element` as an argument to the function. If that `element` is a span, then allow `elementIsMath` to remain `false` (the default), and Temml will create a new `` element inside the span. It you pass a `` element as the argument, then set `elementIsMath` to `true`. Then Temml will populate it with math contents. - -- `leqno`: `boolean`. If `true`, display math has `\tag`s rendered on the left instead of the right, like `\usepackage[leqno]{amsmath}` in LaTeX. (default: `false`) - -- `preventTagLap`: `boolean`. This option affects the horizontal alignment of `displayMode` math and `\tag`s. The default (`false`) acts in the LaTeX manner and centers the math. That’s good in a wide container, but if the container is narrow, the tag will overlap the math. The `preventTagLap: true` option acts differently. It will first place the tag and then center the math in the remainder of the container, with no overlap. If you are targeting mobile, `preventTagLap: true` is probably a good choice . - -- `colorIsTextColor`: `boolean`. In LaTeX, `\color` is a switch, but in early versions of MathJax and KaTeX, `\color` applied its color to a second argument, the way that LaTeX `\textcolor` works. Set option `colorIsTextColor` to `true` if you want `\color` to work like early MathJax or KaTeX. (default: `false`) - -- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color that unsupported commands and invalid LaTeX are rendered in. (default: `#b22222`) - -- `maxSize`: `[number, number]`. This provides a way to cap all user-specified sizes, e.g. in `\rule{500em}{500em}`. The first number is the cap in `em` units, which will be applied to user-specified relative units. The second number is the cap in CSS `pt` units, which will be applied to user-specified absolute units. The default is `[Infinity, Infinity]`, which allows users to make elements and spaces arbitrarily large. - -- `maxExpand`: `number`. Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to `Infinity`, the macro expander will try to fully expand as in LaTeX. (default: 1000) - -- `strict`: `boolean`. If `false` (similar to MathJax), allow features that make writing LaTeX convenient but are not actually supported by LaTeX. If `true` (LaTeX faithfulness mode), throw an error for any such transgressions. (default: `false`) -- `xml`: `boolean`. If `true`, Temml will write a namespace into the `` element. That namespace is `xmlns="http://www.w3.org/1998/Math/MathML"`. Such a namespace is unnecessary for modern browsers but may be helpful for other user agents. (default: `false`) - -- `trust`: `boolean` or `function` (default: `false`). If `false` (do not trust input), prevent any commands like `\includegraphics` that could enable adverse behavior, rendering them instead in `errorColor`. If `true` (trust input), allow all such commands. Provide a custom function `handler(context)` to customize behavior depending on the context (command, arguments e.g. a URL, etc.). A list of possible contexts: - - - `{command: "\\url", url, protocol}` - - `{command: "\\href", url, protocol}` - - `{command: "\\includegraphics", url, protocol}` - - `{command: "\\class", class}` - - `{command: "\\id", id}` - - `{command: "\\style", style}` - - `{command: "\\data", attributes}` - - Here are some sample trust settings: - - - Forbid specific command: `trust: (context) => context.command !== '\\includegraphics'` - - Allow specific command: `trust: (context) => context.command === '\\url'` - - Allow multiple specific commands: `trust: (context) => ['\\url', '\\href'].includes(context.command)` - - Allow all commands with a specific protocol: `trust: (context) => context.protocol === 'http'` - - Allow all commands with specific protocols: `trust: (context) => ['http', 'https', '_relative'].includes(context.protocol)` - - Allow all commands but forbid specific protocol: `trust: (context) => context.protocol !== 'file'` - - Allow certain commands with specific protocols: `trust: (context) => ['\\url', '\\href'].includes(context.command) && ['http', 'https', '_relative'].includes(context.protocol)` - -## Post Process - -The `postProcess` function implements the AMS functions `\ref` and `\label`. It should be called outside of any loop. - -The main Temml functions, `temml.render` and `temml.renderToString`, each operate on only one element at a time. In contrast, the `postProcess` function makes two passes through the entire document. If you choose not to support `\ref`, `postProcess` can be omitted. - -If Temml is used server-side, `\ref` and `\label` are still implemented at runtime with client-side JavaScript. A small file, `temmlPostProcess.js`, is provided to be installed in place of `temml.min.js`. It exposes one function: - -``` -temml.postProcess(document.body) -``` - -If you do not provide a runtime `postProcess`, everthing in Temml will work except `\ref`. - -If you use the [auto-render extension][https://github.com/ronkok/Temml/tree/main/contrib/auto-render], it includes the post-processor nuances. - -# Fonts - -Temml has several different pre-written CSS files. You should use only one and by that choice, you also choose a math font. There are several math fonts available and each has different advantages. - -**Cambria Math** comes pre-installed in Windows, Macs, and iOS, so it is the light-weight option. Cambria Math lacks roundhand glyphs, so you still have to serve a small (12 kb) font, `Temml.woff2`, in order to support `\mathscr{…}`. Sadly, Cambria Math radicals are sometimes too tall for their content. - -
More… - -You can mitigate the radical problem. It occurs because the font expects a cramped subscript when under a radical and Firefox does not perform that cramp. You can create your own cramp with braces. The expression `f{_c'}` will render just fine when `f_c'` renders poorly. - -
- -**Latin Modern** is a clone of Computer Modern and so is very home-like for readers accustomed to LaTeX documents. Rendering is excellent except that some line thicknesses may be too thin for some screens. This option also needs that additional 12kb `Temml.woff2` file in order to support `\mathscr{…}`. - -**Asana**, **STIX TWO**, and **XITS** can be served without the `Temml.woff2` file. - -Several other math fonts exist and you can try them out at Frédéric Wang’s [Mathematical OpenType Fonts][]. - -Where to find font files: - -- Temml.woff2 can be found in the Temml [dist folder][]. -- STIXTwoMath-Regular.woff2 is located at the STIX [repository](https://github.com/stipub/stixfonts/blob/master/fonts/static_otf_woff2/STIXTwoMath-Regular.woff2). -- The other fonts can be downloaded at [Mathematical OpenType Fonts][]. - -[Mathematical OpenType Fonts]: https://fred-wang.github.io/MathFonts/ - -If you want a different math font size, you can add a rule to your own page's CSS, like this example: - -```css -math { font-size: 125%; } -``` - -# Equation numbering - -In order to place automatic equation numbering in certain AMS environments, Temml contains these CSS rules: - -``` -.tml-eqn::before { - counter-increment: tmlEqnNo; - content: "(" counter(tmlEqnNo) ")"; -} -body { counter-reset: tmlEqnNo; } -``` - -You can overwrite the `content` rule to produce customized equation numbers. -For instance, if chapter three of your book is in its own html file, that file’s -`
` could contain: - -``` - -``` - -Then the automatic equation numbering in that chapter would look like: (3.1) - -If your site does not render automatic numbering properly, check if your other -CSS has overwritten the Temml counter-reset. - -# Extensions - -More Temml functionality can be added via the following extensions: - -* [auto-render][]: Find and render all math in a running HTML page. -* [mhchem][]: Write beautiful chemical equations easily. -* [physics][]: Implement much of the LaTeX `physics` package. -* [texvc][]: Provide functions used in wikimedia. - -[auto-render]: https://github.com/ronkok/Temml/tree/main/contrib/auto-render -[mhchem]: https://github.com/ronkok/Temml/tree/main/contrib/mhchem -[physics]: https://github.com/ronkok/Temml/tree/main/contrib/texvc -[texvc]: https://github.com/ronkok/Temml/tree/main/contrib/texvc - -To install extensions for browser use, include the appropriate file from the `contrib` folder of the Temml repository. Then reference the file in the `` of the HTML page. As in this `mhchem` example: - -```html - - ... - - - - -``` - -The extension reference must come after the reference to `temml.min.js`. - -For server-side use, just use `temml.cjs` instead of `temml.min.js`. `temml.cjs` includes `mhchem`, `physics`, and `texvc`. - -# Security - -Any HTML generated by Temml should be safe from ` - - - - - -
- -

Foreword

- -

This page compares the MathML output from four TeX-to-MathML conversion libraries. You should use Firefox or Safari to view this page because they can render the MathML today. MathML will be viewable in Chrome and Edge soon.

- -

MathJax and KaTeX of course also render math in other formats. This comparison is limited to MathML.

- -

Versions used are: Temml 0.6.9, MathJax 2.7.5, KaTeX 0.13.9, and TeXZilla 1.0.2.0

- -

Symbols

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Symbol/FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
+₮a+b₮\(a+b\)₭a+b₭₸a+b₸a+b
-₮a-b₮\(a-b\)₭a-b₭₸a-b₸a-b
!₮n!₮\(n!\)₭n!₭₸n!₸n!
\!₮a!b₮\(a!b\)₭a!b₭₸a!b₸a\!b
#₮\def\bar#1{#1^2} \bar{y}₮\(\def\bar#1{#1^2} \bar{y}\)₭\def\bar#1{#1^2} \bar{y}₭Not supported\def\bar#1{#1^2} \bar{y}
\#₮\#₮\(\#\)₭\#₭₸\#₸
%₮%a comment₮\(%a comment\)₭%a comment₭Not supported%a comment
\%₮\%₮\(\%\)₭\%₭₸\%₸
&₮\begin{matrix} a & b\cr c & d \end{matrix}₮\(\begin{matrix} a & b\\ c & d \end{matrix}\)₭\begin{matrix} a & b\\ c & d \end{matrix}₭₸\begin{matrix} a & b\\ c & d \end{matrix}₸\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\&₮\&₮\(\&\)₭\&₭₸\&₸
'₮'₮\('\)₭'₭₸'₸
\'₮\text{\'{a}}₮Not supported₭\text{\'{a}}₭₸\text{\'{a}}₸\text{\'{a}}
(₮(₮\((\)₭(₭₸(₸
)₮)₮\()\)₭)₭₸)₸
\₮a\ b₮\(a\ b\)₭a\ b₭Not supporteda\ b
\"₮\text{\"{a}}₮Not supported₭\text{\"{a}}₭₸\text{\"{a}}₸\text{\"{a}}
\$₮\text{\textdollar}₮Not supported₭\text{\textdollar}₭₸\text{\textdollar}₸
\,₮a\,\,{b}₮\(a\,\,{b}\)₭a\,\,{b}₭₸a\,\,{b}₸a\,\,{b}
\.₮\text{\.{a}}₮Not supported₭\text{\.{a}}₭₸\text{\.{a}}₸\text{\.{a}}
\:₮a\:\:{b}₮\(a\:\:{b}\)₭a\:\:{b}₭₸a\:\:{b}₸a\:\:{b}
\;₮a\;\;{b}₮\(a\;\;{b}\)₭a\;\;{b}₭₸a\;\;{b}₸aa\;\;{b}
_₮x_i₮\(x_i\)₭x_i₭₸x_i₸x_i
\_₮\_₮\(\_\)₭\_₭₸\_₸
\`₮\text{\'{a}}₮Not supported₭\text{\'{a}}₭₸\text{\'{a}}₸\text{\'{a}}
<₮<₮\(<\)₭<₭₸<₸
\=₮\text{\={a}}₮Not supported₭\text{\={a}}₭₸\text{\={a}}₸\text{\={a}}
>₮>₮\( > \)₭>₭₸>₸
\>₮a\>\>{b}₮\(a\>\>{b}\)₭a\>\>{b}₭Not supporteda\>\>{b}
[₮[₮\([\)₭[₭₸[₸
]₮]₮\(]\)₭]₭₸]₸
{₮{a}₮\({a}\)₭{a}₭₸{a}₸{a}
}₮{a}₮\({a}\)₭{a}₭₸{a}₸{a}
\{₮\{₮\(\{\)₭\{₭₸\{₸
\}₮\}₮\(\}\)₭\}₭₸\}₸
|₮|₮\(|\)₭|₭₸|₸
\|₮\|₮\(\|\)₭\|₭₸\|₸
~₮\text{no~break}₮\(\text{no~break}\)₭\text{no~break}₭Not supported\text{no~break}
\~₮\text{\~{a}}₮Not supported₭\text{\~{a}}₭₸\text{\~{a}}₸\text{\~{a}}
\\₮\begin{matrix} a & b\\ c & d\end{matrix}₮\(\begin{matrix} a & b\\ c & d\end{matrix}\)₭\begin{matrix} a & b\\ c & d\end{matrix}₭₸\begin{matrix} a & b\\ c & d\end{matrix}₸\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\\₮x \\ y₮\(x \\ y\)₭x \\ y₭₸x \\ y₸x \\ y
^₮x^i₮\(x^i\)₭x^i₭₸x^i₸x^i
\^₮\text{\^{a}}₮Not supported₭\text{\^{a}}₭₸\text{\^{a}}₸\text{\^{a}}
special fraction₮1\kern2mu \text{³⁄₄}₮\(1\kern2mu \text{³⁄₄}\)₭1\kern2mu \text{³⁄₄}₭Not supported1\kern2mu \text{³⁄₄}
- -

A

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\AA₮\text{\AA}₮Not supported₭\text{\AA}₭₸\text{\AA}₸\text{\AA}
\aa₮\text{\aa}₮Not supported₭\text{\aa}₭₸\text{\aa}₸\text{\aa}
\above₮{a \above{2pt} b+1}₮\({a \above{2pt} b+1}\)₭{a \above{2pt} b+1}₭Not supported{a \above{2pt} b+1}
\abovewithdelimsNot supported\(a+1 \abovewithdelims [ ] 1pt b\)Not supportedNot supporteda+1 \abovewithdelims [ ] 1pt b
\acute₮\acute e₮\(\acute e\)₭\acute e₭Not supported\acute e
\AE₮\text{\AE}₮Not supported₭\text{\AE}₭₸\text{\AE}₸\text{\AE}
\ae₮\text{\ae}₮Not supported₭\text{\ae}₭₸\text{\ae}₸\text{\ae}
\alef₮\alef₮\(\alef\)₭\alef₭Not supported
\alefsym₮\alefsym₮\(\alefsym\)₭\alefsym₭Not supported
\aleph₮\aleph₮\(\aleph\)₭\aleph₭₸\aleph₸
{align}₮₮\begin{align}a&=b+c\\d+e&=f\end{align}₮₮\[\begin{align}a &=b+c\\d+e&=f\end{align}\]₭₭\begin{align}a &=b+c\\d+e&=f\end{align}₭₭₸\begin{align}a&=b+c\\d+e&=f\end{align}₸\begin{align}
   a&=b+c \\
   d+e&=f
\end{align}
{align*}₮₮\begin{align*}a&=b+c\\d+e&=f\end{align*}₮₮\[\begin{align*}a &=b+c\\d+e&=f\end{align*}\]₭₭\begin{align*}a &=b+c\\d+e&=f\end{align*}₭₭₸\begin{align}a&=b+c\\d+e&=f\end{align}₸\begin{align*}
   a&=b+c \\
   d+e&=f
\end{align*}
{aligned}₮\begin{aligned}x&=y & a&=b+c\\x'&=y' & a'&=b'\end{aligned}₮\(\begin{aligned}x&=y & a&=b+c\\x'&=y' & a'&=b'\end{aligned}\)₭\begin{aligned}x&=y & a&=b+c\\x'&=y' & a'&=b'\end{aligned}₭₸\begin{aligned}x&=y & a&=b+c\\x'&=y' & a'&=b'\end{aligned}₸\begin{aligned}
x&=y & a&=b+c\\
x'&=y' & a'&=b'
\end{aligned}
{alignat}₮₮\begin{alignat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat}₮₮\[\begin{alignat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat}\]₭₭\begin{alignat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat}₭₭₸\begin{alignat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat}₸
{alignat*}₮₮\begin{alignat*}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat*}₮₮\[\begin{alignat*}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat*}\]₭₭\begin{alignat*}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat*}₭₭₸\begin{alignat*}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat*}₸
{alignedat}₮\begin{alignedat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignedat}₮\(\begin{alignedat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignedat}\)₭\begin{alignedat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignedat}₭₸\begin{alignedat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignedat}₸\begin{alignedat}{2}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{alignedat}
\allowbreakSupportedNot supportedNot supportedNot supported
\Alpha₮\Alpha₮\(\Alpha\)₭\Alpha₭₸\Alpha₸
\alpha₮\alpha₮\(\alpha\)₭\alpha₭₸\alpha₸
\amalg₮\amalg₮\(\amalg\)₭\amalg₭₸\amalg₸
\And₮\And₮\(\And\)₭\And₭Not supported
\andNot supported\(\and\)Not supportedNot supportedDeprecated
\angNot supported\(\ang\)Not supportedNot supportedDeprecated
\angl₮a_{\angl n}₮Not supported
See \enclose
₭a_{\angl n}₭Not supporteda_{\angl n}
\angle₮\angle₮\(\angle\)₭\angle₭₸\angle₸
\angln₮a_\angln₮Not supported
See \enclose
₭a_\angln₭Not supporteda_\angln
\approx₮\approx₮\(\approx\)₭\approx₭₸\approx₸
\approxeq₮\approxeq₮\(\approxeq\)₭\approxeq₭₸\approxeq₸
\arccos₮\arccos x₮\(\arccos x\)₭\arccos x₭₸\arccos x₸
\arcctg₮\arcctg x₮Not supported₭\arcctg x₭Not supported
\arcsin₮\arcsin x₮\(\arcsin x\)₭\arcsin x₭₸\arcsin x₸
\arctan₮\arctan x₮\(\arctan x\)₭\arctan x₭₸\arctan x₸
\arctg₮\arctg x₮Not supported₭\arctg x₭Not supported
\arg₮\arg₮\(\arg\)₭\arg₭₸\arg₸
\argmax₮\begin{matrix}\argmax x \\ \argmax_y x \\\argmax\limits_y x\end{matrix}₮Not supported₭\begin{matrix}\argmax x \\ \argmax_y x \\\argmax\limits_y x\end{matrix}₭Not supported
\argmin₮\argmin₮Not supported₭\argmin₭Not supported
{array}₮\begin{array}{cc}a&b\\c&d\end{array}₮\(\begin{array}{cc}a&b\\c&d\end{array}\)₭\begin{array}{cc}a&b\\c&d\end{array}₭₸\begin{array}{cc}a&b\\c&d\end{array}₸\begin{array}{cc}
   a & b \\
   c & d
\end{array}
{array}
with lines
₮\begin{array}{c|c:c}a & b & c \\ \hline d & e & f \\ \hdashline g & h & i\end{array}₮\(\begin{array}{c|c:c}a & b & c \\ \hline d & e & f \\ \hdashline g & h & i\end{array}\)₭\begin{array}{c|c:c}a & b & c \\ \hline d & e & f \\ \hdashline g & h & i\end{array}₭Not supported\begin{array}{c|c:c}
a & b & c \\ \hline
d & e & f\\
\hdashline g & h & i
\end{array}
\arrayNot supported\(\array{ a & b+1 \\ c+1 & d }\)Not supported₸\array{ a & b+1 \\ c+1 & d }₸\array{ a & b+1 \\ c+1 & d }
\arraystretch₮\def\arraystretch{1.5}\begin{array}{cc}a&b\\c&d\end{array}₮\(\def\arraystretch{1.5}\begin{array}{cc}a&b\\c&d\end{array}\)₭\def\arraystretch{1.5}\begin{array}{cc}a&b\\c&d\end{array}₭₸\def\arraystretch{1.5}\begin{array}{cc}a&b\\c&d\end{array}₸\def\arraystretch{1.5}
\begin{array}{cc}
   a & b \\
   c & d
\end{array}
\ArrowvertNot supported\(\Arrowvert\)Not supportedNot supported
\arrowvertNot supported\(\arrowvert\)Not supportedNot supported
\ast₮\ast₮\(\ast\)₭\ast₭₸\ast₸
\asymp₮\asymp₮\(\asymp\)₭\asymp₭₸\asymp₸
\atop₮{a \atop b}₮\({a \atop b}\)₭{a \atop b}₭₸{a \atop b}₸{a \atop b}
\atopwithdelimsNot supported\(a \atopwithdelims [ ] b\)Not supportedNot supporteda \atopwithdelims [ ] b
- -

B

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\backepsilon₮\backepsilon₮\(\backepsilon\)₭\backepsilon₭₸\backepsilon₸
\backprime₮\backprime₮\(\backprime\)₭\backprime₭₸\backprime₸
\backsim₮\backsim₮\(\backsim\)₭\backsim₭₸\backsim₸
\backsimeq₮\backsimeq₮\(\backsimeq\)₭\backsimeq₭₸\backsimeq₸
\backslash₮\backslash₮\(\backslash\)₭\backslash₭₸\backslash₸
\ballotx₮\ballotx₮Not supportedNot supportedNot supported
\bar₮\bar{y}₮\(\bar{y}\)₭\bar{y}₭₸\bar{y}₸\bar{y}
\barwedge₮\barwedge₮\(\barwedge\)₭\barwedge₭₸\barwedge₸
\Bbb₮\Bbb{ABC}₮\(\Bbb{ABC}\)₭\Bbb{ABC}₭Not supported\Bbb{ABC}
\Bbbk₮\Bbbk₮\(\Bbbk\)₭\Bbbk₭Not supported
\bboxNot supportedRequires extensionNot supportedNot supported
\bcancel₮\bcancel{5}₮\(\bcancel{5}\)₭\bcancel{5}₭Not supported\bcancel{5}
\because₮\because₮\(\because\)₭\because₭₸\because₸
\begin₮\begin{matrix} a & b\\ c & d\end{matrix}₮\(\begin{matrix} a & b\\ c & d\end{matrix}\)₭\begin{matrix} a & b\\ c & d\end{matrix}₭₸\begin{matrix} a & b\\ c & d\end{matrix}₸\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\begingroup₮\begingroup a \endgroup₮\(\begingroup a \endgroup\)₭\begingroup a \endgroup₭Not supported\begingroup a\endgroup
\Beta₮\Beta₮\(\Beta\)₭\Beta₭₸\Beta₸
\beta₮\beta₮\(\beta\)₭\beta₭₸\beta₸
\beth₮\beth₮\(\beth\)₭\beth₭₸\beth₸
\between₮\between₮\(\between\)₭\between₭₸\between₸
\bf₮\bf AaBb12₮\(\bf AaBb12\)₭\bf AaBb12₭Not supported\bf AaBb12
\big₮\big(\big)₮\(\big(\big)\)₭\big(\big)₭₸\big(\big)₸\big(\big)
\Big₮\Big(\Big)₮\(\Big(\Big)\)₭\Big(\Big)₭₸\Big(\Big)₸\Big(\Big)
\bigcap₮\bigcap_0^n x \; \displaystyle \bigcap_0^n x₮\(\bigcap_0^n x \; \displaystyle \bigcap_0^n x\)₭\bigcap_0^n x \; \displaystyle \bigcap_0^n x₭₸\bigcap₸
\bigcirc₮\bigcirc₮\(\bigcirc\)₭\bigcirc₭₸\bigcirc₸
\bigcup₮\bigcup_0^n x \; \displaystyle \bigcup_0^n x₮\(\bigcup_0^n x \; \displaystyle \bigcup_0^n x\)₭\bigcup_0^n x \; \displaystyle \bigcup_0^n x₭₸\bigcup₸
\bigg₮\bigg(\bigg)₮\(\bigg(\bigg)\)₭\bigg(\bigg)₭₸\bigg(\bigg)₸\bigg(\bigg)
\Bigg₮\Bigg(\Bigg)₮\(\Bigg(\Bigg)\)₭\Bigg(\Bigg)₭₸\Bigg(\Bigg)₸\Bigg(\Bigg)
\biggl₮\biggl(₮\(\biggl(\)₭\biggl(₭₸\biggl(₸\biggl(
\Biggl₮\Biggl(₮\(\Biggl(\)₭\Biggl(₭₸\Biggl(₸\Biggl(
\biggm₮\biggm\vert₮\(\biggm\vert\)₭\biggm\vert₭₸\biggm\vert₸\biggm\vert
\Biggm₮\Biggm\vert₮\(\Biggm\vert\)₭\Biggm\vert₭₸\Biggm\vert₸\Biggm\vert
\biggr₮\biggr)₮\(\biggr)\)₭\biggr)₭₸\biggr)₸\biggr)
\Biggr₮\Biggr)₮\(\Biggr)\)₭\Biggr)₭₸\Biggr)₸\Biggr)
\bigl₮\bigl(₮\(\bigl(\)₭\bigl(₭₸\bigl(₸\bigl(
\Bigl₮\Bigl(₮\(\Bigl(\)₭\Bigl(₭₸\Bigl(₸\Bigl(
\bigm₮\bigm\vert₮\(\bigm\vert\)₭\bigm\vert₭₸\bigm\vert₸\bigm\vert
\Bigm₮\Bigm\vert₮\(\Bigm\vert\)₭\Bigm\vert₭₸\Bigm\vert₸\Bigm\vert
\bigodot₮\bigodot_0^n x \; \displaystyle \bigodot_0^n x₮\(\bigodot_0^n x \; \displaystyle \bigodot_0^n x\)₭\bigodot_0^n x \; \displaystyle \bigodot_0^n x₭₸\bigodot₸
\bigominusNot supportedNot supportedNot supported₸\bigominus₸
\bigoplus₮\bigoplus_0^n x \; \displaystyle \bigoplus_0^n x₮\(\bigoplus_0^n x \; \displaystyle \bigoplus_0^n x\)₭\bigoplus_0^n x \; \displaystyle \bigoplus_0^n x₭₸\bigoplus₸
\bigoslashNot supportedNot supportedNot supported₸\bigoslash₸
\bigotimes₮\bigotimes_0^n x \; \displaystyle \bigotimes_0^n x₮\(\bigotimes_0^n x \; \displaystyle \bigotimes_0^n x\)₭\bigotimes_0^n x \; \displaystyle \bigotimes_0^n x₭₸\bigotimes₸
\bigr₮\bigr)₮\(\bigr)\)₭\bigr)₭₸\bigr)₸\bigr)
\Bigr₮\Bigr)₮\(\Bigr)\)₭\Bigr)₭₸\Bigr)₸\Bigr)
\bigsqcapNot supportedNot supportedNot supported₸\bigsqcap₸
\bigsqcup₮\bigsqcup_0^n x \; \displaystyle \bigsqcup_0^n x₮\(\bigsqcup_0^n x \; \displaystyle \bigsqcup_0^n x\)₭\bigsqcup_0^n x \; \displaystyle \bigsqcup_0^n x₭₸\bigsqcup₸
\bigstar₮\bigstar₮\(\bigstar\)₭\bigstar₭₸\bigstar₸
\bigtriangledown₮\bigtriangledown₮\(\bigtriangledown\)₭\bigtriangledown₭₸\bigtriangledown₸
\bigtriangleup₮\bigtriangleup₮\(\bigtriangleup\)₭\bigtriangleup₭₸\bigtriangleup₸
\biguplus₮\biguplus_0^n x \; \displaystyle \biguplus_0^n x₮\(\biguplus_0^n x \; \displaystyle \biguplus_0^n x\)₭\biguplus_0^n x \; \displaystyle \biguplus_0^n x₭₸\biguplus₸
\bigvee₮\bigvee_0^n x \; \displaystyle \bigvee_0^n x₮\(\bigvee_0^n x \; \displaystyle \bigvee_0^n x\)₭\bigvee_0^n x \; \displaystyle \bigvee_0^n x₭₸\bigvee₸
\bigwedge₮\bigwedge_0^n x \; \displaystyle \bigwedge_0^n x₮\(\bigwedge_0^n x \; \displaystyle \bigwedge_0^n x\)₭\bigwedge_0^n x \; \displaystyle \bigwedge_0^n x₭₸\bigwedge₸
\binom₮\binom n k₮\(\binom n k\)₭\binom n k₭₸\binom n k₸\binom n k
\blacklozenge₮\blacklozenge₮\(\blacklozenge\)₭\blacklozenge₭₸\blacklozenge₸
\blacksquare₮\blacksquare₮\(\blacksquare\)₭\blacksquare₭₸\blacksquare₸
\blacktriangle₮\blacktriangle₮\(\blacktriangle\)₭\blacktriangle₭₸\blacktriangle₸
\blacktriangledown₮\blacktriangledown₮\(\blacktriangledown\)₭\blacktriangledown₭₸\blacktriangledown₸
\blacktriangleleft₮\blacktriangleleft₮\(\blacktriangleleft\)₭\blacktriangleleft₭₸\blacktriangleleft₸
\blacktriangleright₮\blacktriangleright₮\(\blacktriangleright\)₭\blacktriangleright₭₸\blacktriangleright₸
\bm₮\bm{AaBb}₮Not supported₭\bm{AaBb}₭Not supported\bm{AaBb}
{Bmatrix}₮\begin{Bmatrix}a&b\\c&d\end{Bmatrix}₮\(\begin{Bmatrix}a&b\\c&d\end{Bmatrix}\)₭\begin{Bmatrix}a&b\\c&d\end{Bmatrix}₭₸\begin{Bmatrix}a&b\\c&d\end{Bmatrix}₸\begin{Bmatrix}
   a & b \\
   c & d
\end{Bmatrix}
{bmatrix}₮\begin{bmatrix}a&b\\c&d\end{bmatrix}₮\(\begin{bmatrix}a&b\\c&d\end{bmatrix}\)₭\begin{bmatrix}a&b\\c&d\end{bmatrix}₭₸\begin{bmatrix}a&b\\c&d\end{bmatrix}₸\begin{bmatrix}
   a & b \\
   c & d
\end{bmatrix}
\bmod₮a \bmod b₮\(a \bmod b\)₭a \bmod b₭Not supporteda \bmod b
\bold₮\bold{AaBb123}₮\(\bold{AaBb123}\)₭\bold{AaBb123}₭Not supported\bold{AaBb123}
\boldsymbol₮\boldsymbol{AaBb0}₮\(\boldsymbol{AaBb0}\)₭\boldsymbol{AaBb0}₭₸\boldsymbol{AaBb0}₸\boldsymbol{AaBb0}
\bot₮\bot₮\(\bot\)₭\bot₭₸\bot₸
\Bot₮\Bot₮Not supportedNot supportedNot supported
\bowtie₮\bowtie₮\(\bowtie\)₭\bowtie₭₸\bowtie₸
\Box₮\Box₮\(\Box\)₭\Box₭₸\Box₸
\boxdot₮\boxdot₮\(\boxdot\)₭\boxdot₭₸\boxdot₸
\boxed₮\boxed{ab}₮\(\boxed{ab}\)₭\boxed{ab}₭₸\boxed{ab}₸\boxed{ab}
\boxminus₮\boxminus₮\(\boxminus\)₭\boxminus₭₸\boxminus₸
\boxplus₮\boxplus₮\(\boxplus\)₭\boxplus₭₸\boxplus₸
\boxtimes₮\boxtimes₮\(\boxtimes\)₭\boxtimes₭₸\boxtimes₸
\Bra₮\Bra{\psi}₮Requires extension₭\Bra{\psi}₭Not supported\Bra{\psi}
\bra₮\bra{\psi}₮Requires extension₭\bra{\psi}₭Not supported\bra{\psi}
\brace₮{n\brace k}₮\({n\brace k}\)₭{n\brace k}₭Not supported{n\brace k}
\brack₮{n\brack k}₮\({n\brack k}\)₭{n\brack k}₭Not supported{n\brack k}
\braket₮\braket{\phi|\psi}₮Not supported₭\braket{\phi|\psi}₭Not supported\braket{\phi|\psi}
\Braket₮\Braket{ϕ|\frac{∂^2}{∂ t^2}|ψ}₮Requires extenstionNot supportedNot supported\Braket{ϕ|\frac{∂^2}{∂ t^2}|ψ}
\breve₮\breve{eu}₮\(\breve{eu}\)₭\breve{eu}₭Not supported\breve{eu}
\buildrelNot supported\(\buildrel \rm def \over {:=}\)Not supported₸\buildrel \rm def \over {:=}₸\buildrel \rm def \over {:=}
\bull₮\bull₮\(\bull\)₭\bull₭Not supported
\bullet₮\bullet₮\(\bullet\)₭\bullet₭₸\bullet₸
\Bumpeq₮\Bumpeq₮\(\Bumpeq\)₭\Bumpeq₭₸\Bumpeq₸
\bumpeq₮\bumpeq₮\(\bumpeq\)₭\bumpeq₭₸\bumpeq₸
- -

C

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\CNot supported\(\C\)Not supportedNot supportedDeprecated
\c₮\text{\c{c}}₮Not supported₭\text{\c{c}}₭Not supported\text{\c{c}}
\cal₮\cal ABC₮Not supported₭\cal ABC₭Not supported\cal ABC
\cancel₮\cancel{5}₮\(\cancel{5}\)₭\cancel{5}₭Not supported\cancel{5}
\cancelto₮\cancelto{0}{x}₮Not supportedNot supportedNot supported
\Cap₮\Cap₮\(\Cap\)₭\Cap₭₸\Cap₸
\cap₮\cap₮\(\cap\)₭\cap₭₸\cap₸
{cases}₮\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}₮\(\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}\)₭\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}₭₸\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}₸\begin{cases}
   a &\text{if } b \\
   c &\text{if } d
\end{cases}
\casesNot supported\(\cases{ x & \text{if } x\ge 0\\ -x & \text{if } x\lt 0}\)Not supported₸\cases{ x & \text{if } x\ge 0\\ -x & \text{if } x\lt 0}₸\cases{x & \text{if } x\ge 0\\
- -x & \text{if } x\lt 0} -
{CD}₮₮\begin{CD} A @>a>> B\\@VbVV @AAcA \\ C @= D\end{CD}₮₮\(\begin{CD} A @>a>> B\\@VbVV @AAcA \\ C @= D\end{CD}\)₭₭\begin{CD} A @>a>> B\\@VbVV @AAcA \\ C @= D\end{CD}₭₭Not supported
\cdot₮\cdot₮\(\cdot\)₭\cdot₭₸\cdot₸
\cdotp₮\cdotp₮\(\cdotp\)₭\cdotp₭₸\cdotp₸
\cdots₮\cdots₮\(\cdots\)₭\cdots₭₸\cdots₸
\ce₮\ce{A\bond{~}B\bond{~-}C}₮\(\ce{A\bond{~}B\bond{~-}C}\)₭\ce{A\bond{~}B\bond{~-}C}₭Not supported\ce{A\bond{~}B\bond{~-}C}
Requires `mhchem` extension
\ceeNot supported\(\cee{C6H5-CHO}\)Not supportedNot supportedDeprecated by mhchem
\centerdot₮a\centerdot b₮\(a\centerdot b\)₭a\centerdot b₭Not supportedIn LaTeX, \centerdot is a small
square on the baseline, not
a centered dot.
\cfNot supported\(\cf{C6H5-CHO}\)Not supportedNot supportedDeprecated by mhchem
\cfrac₮\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}₮\(\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}\)₭\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}₭Not supported\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}
\char₮\char"263a₮Not supported
See \unicode
₭\char"263a₭Not supported\char"263a
\check₮\check{oe}₮\(\check{oe}\)₭\check{oe}₭₸\check{oe}₸\check{oe}
\ch₮\ch₮Not supported₭\ch₭Not supported
\checkmark₮\checkmark₮\(\checkmark\)₭\checkmark₭Not supported
\Chi₮\Chi₮\(\Chi\)₭\Chi₭Not supported
\chi₮\chi₮\(\chi\)₭\chi₭₸\chi₸
\choose₮{n+1 \choose k+2}₮\({n+1 \choose k+2}\)₭{n+1 \choose k+2}₭₸{n+1 \choose k+2}₸{n+1 \choose k+2}
\circ₮\circ₮\(\circ\)₭\circ₭₸\circ₸
\circeq₮\circeq₮\(\circeq\)₭\circeq₭₸\circeq₸
\circlearrowleft₮\circlearrowleft₮\(\circlearrowleft\)₭\circlearrowleft₭₸\circlearrowleft₸
\circlearrowright₮\circlearrowright₮\(\circlearrowright\)₭\circlearrowright₭₸\circlearrowright₸
\circledast₮\circledast₮\(\circledast\)₭\circledast₭₸\circledast₸
\circledcirc₮\circledcirc₮\(\circledcirc\)₭\circledcirc₭₸\circledcirc₸
\circleddash₮\circleddash₮\(\circleddash\)₭\circleddash₭₸\circleddash₸
\circledR₮\circledR₮\(\circledR\)₭\circledR₭Not supported
\circledS₮\circledS₮\(\circledS\)₭\circledS₭Not supported
\class₮ab\class{mathHighlight}{cdef}gh₮Not supportedNot supportedNot supportedab\class{mathHighlight}{cdef}gh
\clineNot supportedNot supportedNot supportedNot supported
\clubs₮\clubs₮\(\clubs\)₭\clubs₭Not supported
\clubsuit₮\clubsuit₮\(\clubsuit\)₭\clubsuit₭₸\clubsuit₸
\cnums₮\cnums₮\(\cnums\)₭\cnums₭Not supported
\coh₮\coh₮Not supportedNot supportedNot supported
\colon₮\colon₮\(\colon\)₭\colon₭₸\colon₸
\Colonapprox₮\Colonapprox₮Not supported₭\Colonapprox₭₸\Colonapprox₸
\colonapprox₮\colonapprox₮Not supported₭\colonapprox₭₸\colonapprox₸
\Coloneq₮\Coloneq₮Not supported₭\Coloneq₭₸\Coloneq₸
\coloneq₮\coloneq₮Not supported₭\coloneq₭₸\coloneq₸
\Coloneqq₮\Coloneqq₮Not supported₭\Coloneqq₭₸\Coloneqq₸
\coloneqq₮a \coloneqq b₮Not supported₭a \coloneqq b₭₸a \coloneqq b₸
\Colonsim₮\Colonsim₮Not supported₭\Colonsim₭₸\Colonsim₸
\colonsim₮\colonsim₮Not supported₭\colonsim₭₸\colonsim₸
\color₮\color{#0000FF} AaBb123₮\(\color{#0000FF} AaBb123\)₭\color{#0000FF} AaBb123₭₸\color{#0000FF} AaBb123₸\color{#0000FF} AaBb123
\colorbox₮\colorbox{red}{Black on red}₮\(\colorbox{red}{Black on red}\)₭\colorbox{red}{Black on red}₭₸\colorbox{red}{Black on red}₸\colorbox{red}{Black on red}
\complement₮\complement₮\(\complement\)₭\complement₭₸\complement₸
\Complex₮\Complex₮\(\Complex\)₭\Complex₭Not supported
\cong₮\cong₮\(\cong\)₭\cong₭₸\cong₸
\Coppa₮\Coppa₮Not supportedNot supportedNot supported
\coppa₮\coppa₮Not supportedNot supportedNot supported
\coprod₮\coprod_0^n x \; \displaystyle \coprod_0^n x₮\(\coprod_0^n x \; \displaystyle \coprod_0^n x\)₭\coprod_0^n x \; \displaystyle \coprod_0^n x₭₸\coprod₸
\copyright₮\copyright₮Not supported₭\copyright₭Not supported
\cos₮\cos x₮\(\cos x\)₭\cos x₭₸\cos x₸
\cosec₮\cosec x₮Not supported₭\cosec x₭Not supported
\cosh₮\cosh x₮\(\cosh x\)₭\cosh x₭₸\cosh x₸
\cot₮\cot x₮\(\cot x\)₭\cot x₭₸\cot x₸
\cotg₮\cotg x₮Not supported₭\cotg x₭Not supported
\coth₮\coth x₮\(\coth x\)₭\coth x₭₸\coth x₸
\cr₮\begin{matrix} a & b\cr c & d \end{matrix}₮\(\begin{matrix} a & b\\ c & d \end{matrix}\)₭\begin{matrix} a & b\\ c & d \end{matrix}₭₸\begin{matrix} a & b\\ c & d \end{matrix}₸\begin{matrix}
   a & b \cr
   c & d
\end{matrix}
\csc₮\csc x₮\(\csc x\)₭\csc x₭₸\csc x₸
\cssIdNot supportedNot supportedNot supported
\ctg₮\ctg x₮Not supported₭\ctg x₭Not supported
\cth₮\cth x₮Not supported₭\cth x₭Not supported
\Cup₮\Cup₮\(\Cup\)₭\Cup₭₸\Cup₸
\cup₮\cup₮\(\cup\)₭\cup₭₸\cup₸
\curlyeqprec₮\curlyeqprec₮\(\curlyeqprec\)₭\curlyeqprec₭₸\curlyeqprec₸
\curlyeqsucc₮\curlyeqsucc₮\(\curlyeqsucc\)₭\curlyeqsucc₭₸\curlyeqsucc₸
\curlyvee₮\curlyvee₮\(\curlyvee\)₭\curlyvee₭₸\curlyvee₸
\curlywedge₮\curlywedge₮\(\curlywedge\)₭\curlywedge₭₸\curlywedge₸
\curvearrowleft₮\curvearrowleft₮\(\curvearrowleft\)₭\curvearrowleft₭₸\curvearrowleft₸
\curvearrowright₮\curvearrowright₮\(\curvearrowright\)₭\curvearrowright₭₸\curvearrowright₸
- -

D

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\dag₮\dag₮Not supported₭\dag₭Not supported
\Dagger₮\Dagger₮\(\Dagger\)₭\Dagger₭Not supported
\dagger₮\dagger₮\(\dagger\)₭\dagger₭₸\dagger₸
\daleth₮\daleth₮\(\daleth\)₭\daleth₭₸\daleth₸
\Darr₮\Darr₮\(\Darr\)₭\Darr₭Not supported
\dArr₮\dArr₮\(\dArr\)₭\dArr₭Not supported
\darr₮\darr₮\(\darr\)₭\darr₭₸\darr₸
{darray}₮\begin{array}{cc}a & b\\c & d\end{array}₮\(\begin{array}{cc}a & b\\c & d\end{array}\)₭\begin{array}{cc}a & b\\c & d\end{array}₭₸\begin{array}{cc}a & b\\c & d\end{array}₸\begin{darray}{cc}
   a & b \\
   c & d
\end{darray}
\dashleftarrow₮\dashleftarrow₮\(\dashleftarrow\)₭\dashleftarrow₭₸\dashleftarrow₸
\dashrightarrow₮\dashrightarrow₮\(\dashrightarrow\)₭\dashrightarrow₭₸\dashrightarrow₸
\dashv₮\dashv₮\(\dashv\)₭\dashv₭₸\dashv₸
\dbinom₮\dbinom n k₮\(\dbinom n k\)₭\dbinom n k₭Not supported\dbinom n k
\dblcolon₮\dblcolon₮Not supported₭\dblcolon₭₸\dblcolon₸
{dcases}₮\begin{dcases}a&\text{if }b\\c&\text{if }d\end{dcases}₮Not supported₭\begin{dcases}a&\text{if }b\\c&\text{if }d\end{dcases}₭₸\begin{dcases}a&\text{if }b\\c&\text{if }d\end{dcases}₸\begin{dcases}
   a &\text{if } b \\
   c &\text{if } d
\end{dcases}
\ddag₮\ddag₮Not supported₭\ddag₭Not supported
\ddagger₮\ddagger₮\(\ddagger\)₭\ddagger₭₸\ddagger₸
\ddddot₮\ddddot x₮Not supportedNot supported₸\ddddot x₸
\dddot₮\dddot x₮Not supportedNot supported₸\dddot x₸
\ddot₮\ddot x₮\(\ddot x\)₭\ddot x₭₸\ddot x₸\ddot x
\ddots₮\ddots₮\(\ddots\)₭\ddots₭₸\ddots₸
\DeclareMathOperatorNot supported\(\DeclareMathOperator - {\myOp}{myOp} - \myOp(x)\) - Not supportedNot supported
\def₮\def\foo{x^2} \foo + \foo₮\(\def\foo{x^2} \foo + \foo\)₭\def\foo{x^2} \foo + \foo₭Not supported\def\foo{x^2} \foo + \foo
\definecolor₮\definecolor{sortaGreen}{RGB}{128,128,0} \color{sortaGreen} F=ma₮Not supportedNot supportedNot supported
\deg₮\deg x₮\(\deg x\)₭\deg x₭₸\deg x₸
\degree₮\degree₮Not supported₭\degree₭₸\degree₸
\delta₮\delta₮\(\delta\)₭\delta₭₸\delta₸
\Delta₮\Delta₮\(\Delta\)₭\Delta₭₸\Delta₸
\det₮\begin{matrix}\det x \\ \det_y x \\\det\limits_y x\end{matrix}₮\(\begin{matrix}\det x \\ \det_y x \\\det\limits_y x\end{matrix}\)₭\begin{matrix}\det x \\ \det_y x \\\det\limits_y x\end{matrix}₭₸\det₸
\DigammaNot supported\(\Digamma\)Not supportedNot supported
\digamma₮\digamma₮\(\digamma\)₭\digamma₭₸\digamma₸
\dfrac₮\dfrac{a-1}{b-1}₮\(\dfrac{a-1}{b-1}\)₭\dfrac{a-1}{b-1}₭Not supported\dfrac{a-1}{b-1}
\diagdown₮\diagdown₮\(\diagdown\)₭\diagdown₭Not supported
\diagup₮\diagup₮\(\diagup\)₭\diagup₭Not supported
\Diamond₮\Diamond₮\(\Diamond\)₭\Diamond₭₸\Diamond₸
\diamond₮\diamond₮\(\diamond\)₭\diamond₭₸\diamond₸
\diamonds₮\diamonds₮\(\diamonds\)₭\diamonds₭Not supported
\diamondsuit₮\diamondsuit₮\(\diamondsuit\)₭\diamondsuit₭₸\diamondsuit₸
\dim₮\dim x₮\(\dim x\)₭\dim x₭₸\dim x₸
\displaylinesNot supported\(\displaylines{a\\ a+b=c+d}\)Not supported₸\displaylines{a\\ a+b=c+d}₸\displaylines{a\\ a+b=c+d}
\displaystyle₮\displaystyle\sum_0^n₮\(\displaystyle\sum_0^n\)₭\displaystyle\sum_0^n₭₸\displaystyle\sum_0^n₸\displaystyle\sum_0^n
\div₮\div₮\(\div\)₭\div₭₸\div₸
\divideontimes₮\divideontimes₮\(\divideontimes\)₭\divideontimes₭₸\divideontimes₸
\dot₮\dot x₮\(\dot x\)₭\dot x₭₸\dot x₸\dot x
\Doteq₮\Doteq₮\(\Doteq\)₭\Doteq₭₸\Doteq₸
\doteq₮\doteq₮\(\doteq\)₭\doteq₭₸\doteq₸
\doteqdot₮\doteqdot₮\(\doteqdot\)₭\doteqdot₭₸\doteqdot₸
\dotplus₮\dotplus₮\(\dotplus\)₭\dotplus₭₸\dotplus₸
\dots₮x_1 + \dots + x_n₮\(x_1 + \dots + x_n\)₭x_1 + \dots + x_n₭₸x_1 + \dots + x_n₸x_1 + \dots + x_n
\dotsb₮x_1 +\dotsb + x_n₮\(x_1 +\dotsb + x_n\)₭x_1 +\dotsb + x_n₭Not supportedx_1 +\dotsb + x_n
\dotsc₮x,\dotsc,y₮\(x,\dotsc,y\)₭x,\dotsc,y₭Not supportedx,\dotsc,y
\dotsi₮\int_{A_1}\int_{A_2}\dotsi₮\(\int_{A_1}\int_{A_2}\dotsi\)₭\int_{A_1}\int_{A_2}\dotsi₭Not supported\int_{A_1}\int_{A_2}\dotsi
\dotsm₮x_1 x_2 \dotsm x_n₮\(x_1 x_2 \dotsm x_n\)₭x_1 x_2 \dotsm x_n₭Not supportedx_1 x_2 \dotsm x_n
\dotso₮\dotso₮\(\dotso\)₭\dotso₭Not supported
\doublebarwedge₮\doublebarwedge₮\(\doublebarwedge\)₭\doublebarwedge₭₸\doublebarwedge₸
\doublecap₮\doublecap₮\(\doublecap\)₭\doublecap₭Not supported
\doublecup₮\doublecup₮\(\doublecup\)₭\doublecup₭Not supported
\Downarrow₮\Downarrow₮\(\Downarrow\)₭\Downarrow₭₸\Downarrow₸
\downarrow₮\downarrow₮\(\downarrow\)₭\downarrow₭₸\downarrow₸
\downdownarrows₮\downdownarrows₮\(\downdownarrows\)₭\downdownarrows₭₸\downdownarrows₸
\downharpoonleft₮\downharpoonleft₮\(\downharpoonleft\)₭\downharpoonleft₭₸\downharpoonleft₸
\downharpoonright₮\downharpoonright₮\(\downharpoonright\)₭\downharpoonright₭₸\downharpoonright₸
{drcases}₮\begin{drcases}a&\text{if }b\\c&\text{if }d\end{drcases}₮Not supported₭\begin{drcases}a&\text{if }b\\c&\text{if }d\end{drcases}₭₸\begin{drcases}a&\text{if }b\\c&\text{if }d\end{drcases}₸\begin{drcases}
   a&\text{if }b\\
   c&\text{if }d
\end{drcases}
- -

E

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\ell₮\ell₮\(\ell\)₭\ell₭₸\ell₸
\elseNot supportedNot supportedNot supportedNot supported
\empty₮\empty₮\(\empty\)₭\empty₭₸\empty₸
\emptyset₮\emptyset₮\(\emptyset\)₭\emptyset₭₸\emptyset₸
\encloseNot supported
See \longdiv,
\angl, \phase
\(\enclose{longdiv}{500}\)
\(\enclose{actuarial}{500}\)
\(\enclose{phasorangle}{500}\)
Not supportedNot supported\enclose{longdiv}{500}
\enclose{actuarial}{500}
\enclose{phasorangle}{500}
Non-standard
\end₮\begin{matrix} a & b\\ c & d\end{matrix}₮\(\begin{matrix} a & b\\ c & d\end{matrix}\)₭\begin{matrix} a & b\\ c & d\end{matrix}₭₸\begin{matrix} a & b\\ c & d\end{matrix}₸\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\endgroup₮\begingroup a \endgroup₮\(\begingroup a \endgroup\)₭\begingroup a \endgroup₭Not supported\begingroup a\endgroup
\enspace₮a\enspace b₮\(a\enspace b\)₭a\enspace b₭Not supporteda\enspace b
\Epsilon₮\Epsilon₮\(\Epsilon\)₭\Epsilon₭Not supported
\epsilon₮\epsilon₮\(\epsilon\)₭\epsilon₭₸\epsilon₸
\eqalignNot supported\(\eqalign{3x - 4y &= 5\\x + 7 &= -2y}\)Not supported₸\eqalign{3x - 4y &= 5\\x + 7 &= -2y}₸
\eqalignnoNot supported\(\eqalignno{3x - 4y &= 5 &(\dagger) \\ x + 7 &= -2y &(\ddagger)\\ z &= 2}\)Not supportedNot supported
\eqcirc₮\eqcirc₮\(\eqcirc\)₭\eqcirc₭₸\eqcirc₸
\Eqcolon₮\Eqcolon₮Not supported₭\Eqcolon₭₸\Eqcolon₸
\eqcolon₮\eqcolon₮Not supported₭\eqcolon₭₸\eqcolon₸
{equation}₮₮\begin{equation}\label{maxwell}\begin{split}∇·𝐃&=ρ_v \\ ∇·𝐁&=0 \end{split}\end{equation}₮₮\[\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}\]₭₭\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}₭₭Not supported\begin{equation}
\begin{split}
   ∇·𝐃&=ρ_v \\
   ∇·𝐁&=0
\end{split}
\end{equation}
{equation*}₮₮\begin{equation*}\begin{split}∇·𝐃&=ρ_v \\ ∇·𝐁&=0 \end{split}\end{equation*}₮₮\[\begin{equation*}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation*}\]₭₭\begin{equation*}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation*}₭₭Not supported
{eqnarray}Not supported\(\begin{eqnarray} -y &=& (x-1)^2 \\ - &=& (x-1)(x-1) \\ - &=& x^2 - 2x + 1 -\end{eqnarray}\)Not supportedNot supported
{eqnarray*}Not supported\(\begin{eqnarray*} -y &=& (x-1)^2 \\ - &=& (x-1)(x-1) \\ - &=& x^2 - 2x + 1 -\end{eqnarray*}\)Not supportedNot supported
\Eqqcolon₮\Eqqcolon₮Not supported₭\Eqqcolon₭₸\Eqqcolon₸
\eqqcolon₮\eqqcolon₮Not supported₭\eqqcolon₭₸\eqqcolon₸
\eqref₮\eqref{maxwell}₮Not supportedNot supportedNot supported
\eqsim₮\eqsim₮\(\eqsim\)₭\eqsim₭₸\eqsim₸
\eqslantgtr₮\eqslantgtr₮\(\eqslantgtr\)₭\eqslantgtr₭₸\eqslantgtr₸
\eqslantless₮\eqslantless₮\(\eqslantless\)₭\eqslantless₭₸\eqslantless₸
\equiv₮\equiv₮\(\equiv\)₭\equiv₭₸\equiv₸
\Eta₮\Eta₮\(\Eta\)₭\Eta₭₸\Eta₸
\eta₮\eta₮\(\eta\)₭\eta₭₸\eta₸
\eth₮\eth₮\(\eth\)₭\eth₭₸\eth₸
\euro₮\euro₮\(\euro\)Not supportedNot supported
\exist₮\exist₮\(\exist\)₭\exist₭Not supported
\exists₮\exists₮\(\exists\)₭\exists₭₸\exists₸
\exp₮\exp x₮\(\exp x\)₭\exp x₭₸\exp x₸
- -

F

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\fallingdotseq₮\fallingdotseq₮\(\fallingdotseq\)₭\fallingdotseq₭₸\fallingdotseq₸
\fbox₮\fbox{Hi there!}₮\(\fbox{Hi there!}\)₭\fbox{Hi there!}₭Not supported\fbox{Hi there!}
\fcolorbox₮\fcolorbox{red}{aqua}{A}₮\(\fcolorbox{red}{aqua}{A}\)₭\fcolorbox{red}{aqua}{A}₭Not supported\fcolorbox{red}{aqua}{A}
\female₮\female₮Not supportedNot supportedNot supported\female
\fiNot supportedNot supportedNot supportedNot supported
\Finv₮\Finv₮\(\Finv\)₭\Finv₭Not supported
\flat₮\flat₮\(\flat\)₭\flat₭₸\flat₸
\footnotesize₮\footnotesize footnotesize₮Not supported₭\footnotesize footnotesize₭Not supported\footnotesize footnotesize
\forall₮\forall₮\(\forall\)₭\forall₭₸\forall₸
\frac₮\frac{a+b}{c+d}₮\(\frac{a+b}{c+d}\)₭\frac{a+b}{c+d}₭₸\frac{a+b}{c+d}₸\frac{a+b}{c+d}
\frak₮\frak{AaBb}₮\(\frak{AaBb}\)₭\frak{AaBb}₭Not supported\frak{AaBb}
\frown₮\frown₮\(\frown\)₭\frown₭₸\frown₸
- -

G

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\Game₮\Game₮\(\Game\)₭\Game₭Not supported
\Gamma₮\Gamma₮\(\Gamma\)₭\Gamma₭₸\Gamma₸
\gamma₮\gamma₮\(\gamma\)₭\gamma₭₸\gamma₸
{gather}₮₮\begin{gather}a=b\\e=b+c\end{gather}₮₮\(\begin{gather}a=b\\e=b+c\end{gather}\)₭₭\begin{gather}a=b\\e=b+c\end{gather}₭₭₸\begin{gather}a=b\\e=b+c\end{gather}₸\begin{gather}
   a=b \\
   e=b+c
\end{gather}
{gather*}₮₮\begin{gather*}a=b\\e=b+c\end{gather*}₮₮\(\begin{gather*}a=b\\e=b+c\end{gather*}\)₭₭\begin{gather*}a=b\\e=b+c\end{gather*}₭₭₸\begin{gather*}a=b\\e=b+c\end{gather*}₸\begin{gather*}
   a=b \\
   e=b+c
\end{gather*}
{gathered}₮\begin{gathered}a=b\\e=b+c\end{gathered}₮\(\begin{gathered}a=b\\e=b+c\end{gathered}\)₭\begin{gathered}a=b\\e=b+c\end{gathered}₭₸\begin{gathered}a=b\\e=b+c\end{gathered}₸\begin{gathered}
   a=b \\
   e=b+c
\end{gathered}
\gcd₮\begin{matrix}\gcd x \\ \gcd_y x \\\gcd\limits_y x\end{matrix}₮\(\begin{matrix}\gcd x \\ \gcd_y x \\\gcd\limits_y x\end{matrix}\)₭\begin{matrix}\gcd x \\ \gcd_y x \\\gcd\limits_y x\end{matrix}₭₸\begin{matrix}\gcd x \\ \gcd_y x \\\gcd\limits_y x\end{matrix}₸
\gdefNot supportedNot supported₭\gdef\bar#1{#1^2} \bar{y} + \bar{y}₭Not supported\gdef\bar#1{#1^2} \bar{y} + \bar{y}
\ge₮\ge₮\(\ge\)₭\ge₭₸\ge₸
\geneuroNot supported\(\geneuro\)Not supportedNot supported
\geneuronarrowNot supported\(\geneuronarrow\)Not supportedNot supported
\geneurowideNot supported\(\geneurowide\)Not supportedNot supported
\genfrac₮\genfrac ( ] {2pt}{0}a{a+1}₮\(\genfrac ( ] {2pt}{0}a{a+1}\)₭\genfrac ( ] {2pt}{0}a{a+1}₭Not supported\genfrac ( ] {2pt}{0}a{a+1}
\geq₮\geq₮\(\geq\)₭\geq₭₸\geq₸
\geqq₮\geqq₮\(\geqq\)₭\geqq₭₸\geqq₸
\geqslant₮\geqslant₮\(\geqslant\)₭\geqslant₭₸\geqslant₸
\gets₮\gets₮\(\gets\)₭\gets₭Not supported
\gg₮\gg₮\(\gg\)₭\gg₭₸\gg₸
\ggg₮\ggg₮\(\ggg\)₭\ggg₭₸\ggg₸
\gggtr₮\gggtr₮\(\gggtr\)₭\gggtr₭Not supported
\gimel₮\gimel₮\(\gimel\)₭\gimel₭₸\gimel₸
\globalNot supported\(\global\def\add#1#2{#1+#2} \add 2 3\)₭\global\def\add#1#2{#1+#2} \add 2 3₭Not supported\global\def\add#1#2{#1+#2} \add 2 3
\gnapprox₮\gnapprox₮\(\gnapprox\)₭\gnapprox₭₸\gnapprox₸
\gneq₮\gneq₮\(\gneq\)₭\gneq₭₸\gneq₸
\gneqq₮\gneqq₮\(\gneqq\)₭\gneqq₭₸\gneqq₸
\gnsim₮\gnsim₮\(\gnsim\)₭\gnsim₭₸\gnsim₸
\grave₮\grave{eu}₮\(\grave{eu}\)₭\grave{eu}₭Not supported\grave{eu}
\gt₮a \gt b₮\(a \gt b\)₭a \gt b₭₸a \gt b₸a \gt b
\gtrdot₮\gtrdot₮\(\gtrdot\)₭\gtrdot₭₸\gtrdot₸
\gtrapprox₮\gtrapprox₮\(\gtrapprox\)₭\gtrapprox₭₸\gtrapprox₸
\gtreqless₮\gtreqless₮\(\gtreqless\)₭\gtreqless₭₸\gtreqless₸
\gtreqqless₮\gtreqqless₮\(\gtreqqless\)₭\gtreqqless₭₸\gtreqqless₸
\gtrless₮\gtrless₮\(\gtrless\)₭\gtrless₭₸\gtrless₸
\gtrsim₮\gtrsim₮\(\gtrsim\)₭\gtrsim₭₸\gtrsim₸
\gvertneqq₮\gvertneqq₮\(\gvertneqq\)₭\gvertneqq₭₸\gvertneqq₸
- -

H

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\H₮\text{\H{a}}₮Not supported₭\text{\H{a}}₭₸\text{\H{a}}₸\text{\H{a}}
\Harr₮\Harr₮\(\Harr\)₭\Harr₭Not supported
\hArr₮\hArr₮Not supported₭\hArr₭Not supported
\harr₮\harr₮\(\harr\)₭\harr₭Not supported
\hat₮\hat{\theta}₮\(\hat{\theta}\)₭\hat{\theta}₭₸\hat{\theta}₸\hat{\theta}
\hbar₮\hbar₮\(\hbar\)₭\hbar₭₸\hbar₸
\hbox₮\hbox{in a box}₮\(\hbox{in a box}\)₭\hbox{in a box}₭Not supported\hbox{in a box}
\hdashline₮\begin{matrix}a&b\\ \hdashline c &d\end{matrix}₮\(\begin{matrix}a&b\\ \hdashline c &d\end{matrix}\)₭\begin{matrix}a&b\\ \hdashline c &d\end{matrix}₭Not supported\begin{matrix}
   a & b \\
   \hdashline
   c & d
\end{matrix}
\hearts₮\hearts₮\(\hearts\)₭\hearts₭Not supported
\heartsuit₮\heartsuit₮\(\heartsuit\)₭\heartsuit₭₸\heartsuit₸
\hfilNot supportedSee \hfillNot supportedNot supported
\hfillNot supported\(\begin{matrix}xxxxxx & xxxxxx & xxxxxx \\ ab & \hfil ab & ab\hfil\\ \end{matrix}\)Not supportedNot supported
\hline₮\begin{matrix}a&b\\ \hline c &d\end{matrix}₮\(\begin{matrix}a&b\\ \hline c &d\end{matrix}\)₭\begin{matrix}a&b\\ \hline c &d\end{matrix}₭Not supported\begin{matrix}
   a & b \\ \hline
   c & d
\end{matrix}
\hom₮\hom x₮\(\hom x\)₭\hom x₭₸\hom x₸
\hookleftarrow₮\hookleftarrow₮\(\hookleftarrow\)₭\hookleftarrow₭₸\hookleftarrow₸
\hookrightarrow₮\hookrightarrow₮\(\hookrightarrow\)₭\hookrightarrow₭₸\hookrightarrow₸
\hphantom₮a\hphantom{bc}d₮\(a\hphantom{bc}d\)₭a\hphantom{bc}d₭Not supporteda\hphantom{bc}d
\href₮\href{https://www.mathjax.org/}{\text{MathJax}}₮\(\href{https://MathJax.org/}{\text{MathJax}}\)₭\href{https://MathJax.org/}{\text{MathJax}}₭Not supported\href{https://www.mathjax.org/}{\text{MathJax}}
\hskip₮w\hskip1em i\hskip2em d₮\(w\hskip1em i\hskip2em d\)₭w\hskip1em i\hskip2em d₭Not supportedw\hskip1em i\hskip2em d
\hslash₮\hslash₮\(\hslash\)₭\hslash₭₸\hslash₸
\hspace₮s\hspace7ex k₮\(s\hspace7ex k\)₭s\hspace7ex k₭Not supporteds\hspace7ex k
\htmlClass₮\htmlClass{foo}{x}₮Not supportedNot supportedNot supported\htmlClass{foo}{x}
\htmlData₮\htmlData{foo=a, bar=b}{x}₮Not supportedNot supportedNot supported\htmlData{foo=a, bar=b}{x}
\htmlId₮\htmlId{bar}{x}₮Not supportedNot supportedNot supported\htmlId{bar}{x}
\htmlStyle₮\htmlStyle{color: red;}{x}₮Not supportedNot supportedNot supported\htmlStyle{color: red;}{x}}
\huge₮\huge huge₮\(\huge huge\)₭\huge huge₭Not supported\huge huge
\Huge₮\Huge Huge₮\(\Huge Huge\)₭\Huge Huge₭Not supported\Huge Huge
- -

I

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\i₮\text{\i}₮Not supported₭\text{\i}₭₸\text{\i}₸\text{\i}
\idotsint₮\idotsint₮Not supportedNot supportedNot supported
\iddotsNot supportedNot supportedNot supportedNot supported
\ifNot supportedNot supportedNot supportedNot supported
\iff₮A\iff B₮\(A\iff B\)₭A\iff B₭₸A\iff B₸A\iff B
\ifmodeNot supportedNot supportedNot supportedNot supported
\ifxNot supportedNot supportedNot supportedNot supported
\iiiintNot supportedNot supportedNot supportedNot supported
\iiint₮\iiint_0^n x \; \displaystyle \iiint_0^n x₮\(\iiint_0^n x \; \displaystyle \iiint_0^n x\)₭\iiint_0^n x \; \displaystyle \iiint_0^n x₭₸\iiint₸
\iint₮\iint_0^n x \; \displaystyle \iint_0^n x₮\(\iint_0^n x \; \displaystyle \iint_0^n x\)₭\iint_0^n x \; \displaystyle \iint_0^n x₭₸\iint₸
\Im₮\Im₮\(\Im\)₭\Im₭₸\Im₸
\image₮\image₮\(\image\)₭\image₭Not supported
\imageof₮\imageof₮Not supported₭\imageof₭Not supported
\imath₮\imath₮\(\imath\)₭\imath₭₸\imath₸
\impliedby₮P\impliedby Q₮\(P\impliedby Q\)₭P\impliedby Q₭₸P\impliedby Q₸P\impliedby Q
\implies₮P\implies Q₮\(P\implies Q\)₭P\implies Q₭₸P\implies Q₸P\implies Q
\in₮\in₮\(\in\)₭\in₭₸\in₸
\includegraphics₮\includegraphics[height=0.8em, totalheight=0.9em, width=0.9em, alt=KA logo]{https://cdn.kastatic.org/images/apple-touch-icon-57x57-precomposed.new.png}₮Not supported₭\includegraphics[height=0.8em, totalheight=0.9em, width=0.9em, alt=KA logo]{https://cdn.kastatic.org/images/apple-touch-icon-57x57-precomposed.new.png}₭Not supported
\incoh₮\incoh₮Not supportedNot supportedNot supported
\inf₮\begin{matrix}\inf x \\ \inf_y x \\\inf\limits_y x\end{matrix}₮\(\begin{matrix}\inf x \\ \inf_y x \\\inf\limits_y x\end{matrix}\)₭\begin{matrix}\inf x \\ \inf_y x \\\inf\limits_y x\end{matrix}₭₸\inf₸
\infin₮\infin₮\(\infin\)₭\infin₭Not supported
\infty₮\infty₮\(\infty\)₭\infty₭₸\infty₸
\injlim₮\begin{matrix}\injlim x \\ \injlim_y x \\\injlim\limits_y x\end{matrix}₮\(\begin{matrix}\injlim x \\ \injlim_y x \\\injlim\limits_y x\end{matrix}\)₭\begin{matrix}\injlim x \\ \injlim_y x \\\injlim\limits_y x\end{matrix}₭Not supported\injlim x
\injlim_y x
\injlim\limits_y x
\int₮\int_0^n x \; \displaystyle \int_0^n x₮\(\int_0^n x \; \displaystyle \int_0^n x\)₭\int_0^n x \; \displaystyle \int_0^n x₭₸\int₸
\intercal₮\intercal₮\(\intercal\)₭\intercal₭₸\intercal₸
\intop₮\intop_0^n x \; \displaystyle \intop_0^n x₮\(\intop_0^n x \; \displaystyle \intop_0^n x\)₭\intop_0^n x \; \displaystyle \intop_0^n x₭Not supported
\invamp₮\invamp₮Not supportedNot supportedNot supported
\Iota₮\Iota₮\(\Iota\)₭\Iota₭₸\Iota₸
\iota₮\iota₮\(\iota\)₭\iota₭₸\iota₸
\isin₮\isin₮\(\isin\)₭\isin₭Not supported
\it₮{\it AaBb}₮\({\it AaBb}\)₭{\it AaBb}₭Not supported{\it AaBb}
- -

JK

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\j₮\text{\j}₮Not supported₭\text{\j}₭₸\text{\j}₸\text{\j}
\jmath₮\jmath₮\(\jmath\)₭\jmath₭₸\jmath₸
\Join₮\Join₮\(\Join\)₭\Join₭Not supported
\Kappa₮\Kappa₮\(\Kappa\)₭\Kappa₭₸\Kappa₸
\kappa₮\kappa₮\(\kappa\)₭\kappa₭₸\kappa₸
\ker₮\ker x₮\(\ker x\)₭\ker x₭₸\ker x₸
\kern₮I\kern-2.5pt R₮\(I\kern-2.5pt R\)₭I\kern-2.5pt R₭Not supportedI\kern-2.5pt R
\Ket₮\Ket{\psi}₮Requires extension₭\Ket{\psi}₭Not supported\Ket{\psi}
\ket₮\ket{\psi}₮Requires extension₭\ket{\psi}₭Not supported\ket{\psi}
\Koppa₮\Koppa₮Not supportedNot supportedNot supported
\koppa₮\koppa₮Not supportedNot supportedNot supported
- -

L

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\LNot supportedNot supportedNot supportedNot supported
\lNot supportedNot supportedNot supportedNot supported
\Lambda₮\Lambda₮\(\Lambda\)₭\Lambda₭₸\Lambda₸
\lambda₮\lambda₮\(\lambda\)₭\lambda₭₸\lambda₸
\labelSee {equation}SupportedNot supported
\land₮\land₮\(\land\)₭\land₭Not supported
\lang₮\lang A\rangle₮\(\lang A\rangle\)₭\lang A\rangle₭₸\lang A\rangle₸\lang A\rangle
\langle₮\langle A\rangle₮\(\langle A\rangle\)₭\langle A\rangle₭₸\langle A\rangle₸\langle A\rangle
\Larr₮\Larr₮\(\Larr\)₭\Larr₭Not supported
\lArr₮\lArr₮\(\lArr\)₭\lArr₭Not supported
\larr₮\larr₮\(\larr\)₭\larr₭Not supported
\large₮\large large₮\(\large large\)₭\large large₭Not supported\large large
\Large₮\Large Large₮\(\Large Large\)₭\Large Large₭Not supported\Large Large
\LARGE₮\LARGE LARGE₮\(\LARGE LARGE\)₭\LARGE LARGE₭Not supported\LARGE LARGE
\LaTeX₮\LaTeX₮\(\LaTeX\)₭\LaTeX₭Not supported
\lBrace₮\lBrace₮Not supported₭\lBrace₭Not supported
\lbrace₮\lbrace₮\(\lbrace\)₭\lbrace₭₸\lbrace₸
\lbrack₮\lbrack₮\(\lbrack\)₭\lbrack₭₸\lbrack₸
\lceil₮\lceil₮\(\lceil\)₭\lceil₭₸\lceil₸
\lcroofNot supportedNot supportedNot supportedNot supportedSee \enclose
\ldotp₮\ldotp₮\(\ldotp\)₭\ldotp₭Not supported
\ldots₮\ldots₮\(\ldots\)₭\ldots₭₸\ldots₸
\le₮\le₮\(\le\)₭\le₭₸\le₸
\leadsto₮\leadsto₮\(\leadsto\)₭\leadsto₭Not supported
\left₮\left\lbrace \frac ab \right.₮\(\left\lbrace \frac ab \right.\)₭\left\lbrace \frac ab \right.₭₸\left\lbrace \frac ab \right.₸\left\lbrace \frac ab \right.
\leftarrow₮\leftarrow₮\(\leftarrow\)₭\leftarrow₭₸\leftarrow₸
\Leftarrow₮\Leftarrow₮\(\Leftarrow\)₭\Leftarrow₭₸\Leftarrow₸
\leftarrowtail₮\leftarrowtail₮\(\leftarrowtail\)₭\leftarrowtail₭₸\leftarrowtail₸
\leftharpoondown₮\leftharpoondown₮\(\leftharpoondown\)₭\leftharpoondown₭₸\leftharpoondown₸
\leftharpoonup₮\leftharpoonup₮\(\leftharpoonup\)₭\leftharpoonup₭₸\leftharpoonup₸
\leftleftarrows₮\leftleftarrows₮\(\leftleftarrows\)₭\leftleftarrows₭₸\leftleftarrows₸
\Leftrightarrow₮\Leftrightarrow₮\(\Leftrightarrow\)₭\Leftrightarrow₭₸\Leftrightarrow₸
\leftrightarrow₮\leftrightarrow₮\(\leftrightarrow\)₭\leftrightarrow₭₸\leftrightarrow₸
\leftrightarrows₮\leftrightarrows₮\(\leftrightarrows\)₭\leftrightarrows₭₸\leftrightarrows₸
\leftrightharpoons₮\leftrightharpoons₮\(\leftrightharpoons\)₭\leftrightharpoons₭₸\leftrightharpoons₸
\leftrightsquigarrow₮\leftrightsquigarrow₮\(\leftrightsquigarrow\)₭\leftrightsquigarrow₭₸\leftrightsquigarrow₸
\leftrootNot supported\(\sqrt[3\leftroot1]{x}\)Not supportedNot supported
\leftthreetimes₮\leftthreetimes₮\(\leftthreetimes\)₭\leftthreetimes₭₸\leftthreetimes₸
\leq₮\leq₮\(\leq\)₭\leq₭₸\leq₸
\leqalignnoNot supportedNot supportedNot supported
\leqq₮\leqq₮\(\leqq\)₭\leqq₭₸\leqq₸
\leqslant₮\leqslant₮\(\leqslant\)₭\leqslant₭₸\leqslant₸
\lessapprox₮\lessapprox₮\(\lessapprox\)₭\lessapprox₭₸\lessapprox₸
\lessdot₮\lessdot₮\(\lessdot\)₭\lessdot₭₸\lessdot₸
\lesseqgtr₮\lesseqgtr₮\(\lesseqgtr\)₭\lesseqgtr₭₸\lesseqgtr₸
\lesseqqgtr₮\lesseqqgtr₮\(\lesseqqgtr\)₭\lesseqqgtr₭₸\lesseqqgtr₸
\lessgtr₮\lessgtr₮\(\lessgtr\)₭\lessgtr₭₸\lessgtr₸
\lesssim₮\lesssim₮\(\lesssim\)₭\lesssim₭₸\lesssim₸
\letNot supportedNot supportedNot supported
\lfloor₮\lfloor₮\(\lfloor\)₭\lfloor₭₸\lfloor₸
\lg₮\lg₮\(\lg\)₭\lg₭₸\lg₸
\lgroup₮\lgroup₮\(\lgroup\)₭\lgroup₭Not supported
\lhd₮\lhd₮\(\lhd\)₭\lhd₭₸\lhd₸
\lim₮\begin{matrix}\lim x \\ \lim_y x \\\lim\limits_y x\end{matrix}₮\(\begin{matrix}\lim x \\ \lim_y x \\\lim\limits_y x\end{matrix}\)₭\begin{matrix}\lim x \\ \lim_y x \\\lim\limits_y x\end{matrix}₭₸\lim_y x₸\lim x
\lim_y x
\lim\limits_y x
\liminf₮\begin{matrix}\liminf x \\ \liminf_y x \\\liminf\limits_y x\end{matrix}₮\(\begin{matrix}\liminf x \\ \liminf_y x \\\liminf\limits_y x\end{matrix}\)₭\begin{matrix}\liminf x \\ \liminf_y x \\\liminf\limits_y x\end{matrix}₭₸\liminf₸
\limits₮\lim\limits_x₮\(\lim\limits_x\)₭\lim\limits_x₭Not supported\lim\limits_x
\limsup₮\begin{matrix}\limsup x \\ \limsup_y x \\\limsup\limits_y x\end{matrix}₮\(\begin{matrix}\limsup x \\ \limsup_y x \\\limsup\limits_y x\end{matrix}\)₭\begin{matrix}\limsup x \\ \limsup_y x \\\limsup\limits_y x\end{matrix}₭₸\limsup₸
\ll₮\ll₮\(\ll\)₭\ll₭₸\ll₸
\llap₮{=}\llap{/\,}₮\({=}\llap{/\,}\)₭{=}\llap{/\,}₭Not supported{=}\llap{/\,}
\llbracket₮\llbracket₮Not supported₭\llbracket₭Not supported
\llcorner₮\llcorner a \lrcorner₮\(\llcorner a \lrcorner\)₭\llcorner a \lrcorner₭Not supported
\Lleftarrow₮\Lleftarrow₮\(\Lleftarrow\)₭\Lleftarrow₭₸\Lleftarrow₸
\lll₮\lll₮\(\lll\)₭\lll₭₸\lll₸
\llless₮\llless₮\(\llless\)₭\llless₭Not supported
\lmoustache₮\lmoustache₮\(\lmoustache\)₭\lmoustache₭₸\lmoustache₸
\ln₮\ln x₮\(\ln x\)₭\ln x₭₸\ln x₸
\lnapprox₮\lnapprox₮\(\lnapprox\)₭\lnapprox₭₸\lnapprox₸
\lneq₮\lneq₮\(\lneq\)₭\lneq₭₸\lneq₸
\lneqq₮\lneqq₮\(\lneqq\)₭\lneqq₭₸\lneqq₸
\longdiv₮\longdiv{45.2}₮Not supported
See \enclose
₭\longdiv{45.2}₭Not supported\longdiv{45.2}
\lnot₮\lnot₮\(\lnot\)₭\lnot₭Not supported
\lnsim₮\lnsim₮\(\lnsim\)₭\lnsim₭₸\lnsim₸
\log₮\begin{matrix}\log x \\ \log_y x \\ \log\limits_y x\end{matrix}₮\(\begin{matrix}\log x \\ \log_y x \\ \log\limits_y x\end{matrix}\)₭\begin{matrix}\log x \\ \log_y x \\ \log\limits_y x\end{matrix}₭₸\begin{matrix}\log x \\ \log_y x \\ \log\limits_y x\end{matrix}₸\log x
\log_y x
\log\limits_y x
\Longleftarrow₮\Longleftarrow₮\(\Longleftarrow\)₭\Longleftarrow₭₸\Longleftarrow₸
\longleftarrow₮\longleftarrow₮\(\longleftarrow\)₭\longleftarrow₭₸\longleftarrow₸
\Longleftrightarrow₮\Longleftrightarrow₮\(\Longleftrightarrow\)₭\Longleftrightarrow₭₸\Longleftrightarrow₸
\longleftrightarrow₮\longleftrightarrow₮\(\longleftrightarrow\)₭\longleftrightarrow₭₸\longleftrightarrow₸
\longmapsto₮\longmapsto₮\(\longmapsto\)₭\longmapsto₭₸\longmapsto₸
\Longrightarrow₮\Longrightarrow₮\(\Longrightarrow\)₭\Longrightarrow₭₸\Longrightarrow₸
\longrightarrow₮\longrightarrow₮\(\longrightarrow\)₭\longrightarrow₭₸\longrightarrow₸
\looparrowleft₮\looparrowleft₮\(\looparrowleft\)₭\looparrowleft₭₸\looparrowleft₸
\looparrowright₮\looparrowright₮\(\looparrowright\)₭\looparrowright₭₸\looparrowright₸
\lor₮\lor₮\(\lor\)₭\lor₭Not supported
\lower₮l\lower 2pt{owe}r₮\(l\lower 2pt{owe}r\)₭l\lower 2pt{owe}r₭Not supportedl\lower 2pt{owe}r
\lozenge₮\lozenge₮\(\lozenge\)₭\lozenge₭₸\lozenge₸
\lparen₮\lparen₮Not supported₭\lparen₭Not supported
\Lrarr₮\Lrarr₮\(\Lrarr\)₭\Lrarr₭Not supported
\lrArr₮\lrArr₮\(\lrArr\)₭\lrArr₭Not supported
\lrarr₮\lrarr₮\(\lrarr\)₭\lrarr₭Not supported
\lrcorner₮\lrcorner₮\(\lrcorner\)₭\lrcorner₭Not supported
\lq₮\lq₮Not supported₭\lq₭₸\lq₸
\Lsh₮\Lsh₮\(\Lsh\)₭\Lsh₭₸\Lsh₸
\lt₮\lt₮\(\lt\)₭\lt₭₸\lt₸
\ltimes₮\ltimes₮\(\ltimes\)₭\ltimes₭₸\ltimes₸
\lVert₮\lVert₮\(\lVert\)₭\lVert₭Not supported
\lvert₮\lvert₮\(\lvert\)₭\lvert₭Not supported
\lvertneqq₮\lvertneqq₮\(\lvertneqq\)₭\lvertneqq₭₸\lvertneqq₸
- -

M

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\male₮\male₮Not supportedNot supportedNot supported\male
\maltese₮\maltese₮\(\maltese\)₭\maltese₭Not supported
\mapsto₮\mapsto₮\(\mapsto\)₭\mapsto₭₸\mapsto₸
\mathbb₮\mathbb{AB}₮\(\mathbb{AB}\)₭\mathbb{AB}₭₸\mathbb{AB}₸\mathbb{AB}
\mathbf₮\mathbf{AaBb123}₮\(\mathbf{AaBb123}\)₭\mathbf{AaBb123}₭₸\mathbf{AaBb123}₸\mathbf{AaBb123}
\mathbin₮a\mathbin{!}b₮\(a\mathbin{!}b\)₭a\mathbin{!}b₭₸a\mathbin{!}b₸a\mathbin{!}b
\mathcal₮\mathcal{AaBb123}₮\(\mathcal{AaBb123}\)₭\mathcal{AaBb123}₭₸\mathcal{AaBb123}₸\mathcal{AaBb123}
\mathchoice₮a\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b₮\(a\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b\)₭a\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b₭Not supporteda\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b
\mathclap₮\displaystyle\sum_{\mathclap{1\le i\le n}} x_{i}₮Not supported₭\displaystyle\sum_{\mathclap{1\le i\le n}} x_{i}₭₸\displaystyle\sum_{\mathclap{1\le i\le n}} x_{i}₸\sum_{\mathclap{1\le i\le n}} x_{i}
\mathclose₮a + (b\mathclose\gt + c₮\(a + (b\mathclose\gt + c\)₭a + (b\mathclose\gt + c₭Not supporteda + (b\mathclose\gt + c
\mathellipsis₮\mathellipsis₮Not supported₭\mathellipsis₭Not supported
\mathfrak₮\mathfrak{AaBb}₮\(\mathfrak{AaBb}\)₭\mathfrak{AaBb}₭₸\mathfrak{AaBb}₸\mathfrak{AaBb}
\mathinner₮ab\mathinner{\text{inside}}cd₮\(ab\mathinner{\text{inside}}cd\)₭ab\mathinner{\text{inside}}cd₭Not supportedab\mathinner{\text{inside}}cd
\mathit₮\mathit{AaBb}₮\(\mathit{AaBb}\)₭\mathit{AaBb}₭₸\mathit{AaBb}₸\mathit{AaBb}
\mathllap₮{\mathrlap{\,/}{=}}₮Not supported₭{\mathrlap{\,/}{=}}₭₸{\mathrlap{\,/}{=}}₸\mathrlap{\,/}{=}
\mathnormal₮\mathnormal{AaBb\theta}₮Not supported₭\mathnormal{AaBb\theta}₭Not supported\mathnormal{AaBb\theta}
\mathop₮a \mathop{x} b₮\(a \mathop{x} b\)₭a \mathop{x} b₭₸a \mathop{x} b₸a \mathop{x} b
\mathopen₮a + \mathopen\lt b) + c₮\(a + \mathopen\lt b) + c\)₭a + \mathopen\lt b) + c₭₸a + \mathopen\lt b) + c₸a + \mathopen\lt b) + c
\mathord₮1\mathord{,}234{,}567₮\(1\mathord{,}234{,}567\)₭1\mathord{,}234{,}567₭Not supported1\mathord{,}234{,}567
\mathpunct₮A\mathpunct{-}B₮\(A\mathpunct{-}B\)₭A\mathpunct{-}B₭Not supportedA\mathpunct{-}B
\mathraiseboxNot supportedNot supportedNot supported₸h\mathraisebox{2pt}{ighe}r₸
\mathrel₮a \mathrel{\#} b₮\(a \mathrel{\#} b\)₭a \mathrel{\#} b₭₸a \mathrel{#} b₸a \mathrel{\#} b
\mathrlap₮{\displaystyle \int_0^{\mathrlap{2\pi}} x \,\mathrm{d} x}₮Not supported₭{\displaystyle \int_0^{\mathrlap{2\pi}} x \,\mathrm{d} x}₭₸{\displaystyle \int_0^{\mathrlap{2\pi}} x \,\mathrm{d} x}₸\int_0^{\mathrlap{2\pi}} x\,\mathrm{d} x
\mathring₮\mathring{a}₮\(\mathring{a}\)₭\mathring{a}₭Not supported\mathring{a}
\mathrm₮\mathrm{AaBb12\theta}₮\(\mathrm{AaBb12\theta}\)₭\mathrm{AaBb12\theta}₭₸\mathrm{AaBb12\theta}₸\mathrm{AaBb12\theta}
\mathscr₮\mathscr{AB}₮\(\mathscr{AB}\)₭\mathscr{AB}₭₸\mathscr{AB}₸\mathscr{AaBb123}
\mathsf₮\mathsf{AaBb123}₮\(\mathsf{AaBb123}\)₭\mathsf{AaBb123}₭₸\mathsf{AaBb123}₸\mathsf{AaBb123}
\mathsterling₮\mathsterling₮Not supported₭\mathsterling₭Not supported
\mathstrut₮\sqrt{\mathstrut\alpha}₮\(\sqrt{\mathstrut\alpha}\)₭\sqrt{\mathstrut\alpha}₭Not supported\sqrt{\mathstrut\alpha}
\mathtip₮\mathtip{a=b}{tip}₮Not supportedNot supportedNot supported\mathtip{a=b}{tip}s
\mathtt₮\mathtt{AaBb123}₮\(\mathtt{AaBb123}\)₭\mathtt{AaBb123}₭₸\mathtt{AaBb123}₸\mathtt{AaBb123}
\matrixNot supported\(\matrix{a & b \\ c & d}\)Not supported₸\matrix{a & b \\ c & d}₸\matrix{a & b \\ c & d}
{matrix}₮\begin{matrix}\frac A B&b\\\frac A B&d\end{matrix}₮\(\begin{matrix}\frac A B&b\\\frac A B&d\end{matrix}\)₭\begin{matrix}\frac A B&b\\\frac A B&d\end{matrix}₭₸\begin{matrix}\frac A B&b\\\frac A B&d\end{matrix}₸\begin{matrix}
   \frac A B & b \\
   \frac A B & d
\end{matrix}
\max₮\begin{matrix}\max x \\ \max_y x \\\max\limits_y x\end{matrix}₮\(\begin{matrix}\max x \\ \max_y x \\\max\limits_y x\end{matrix}\)₭\begin{matrix}\max x \\ \max_y x \\\max\limits_y x\end{matrix}₭₸\max₸
\mboxNot supported\(\mbox{in a box}\)Not supportedNot supported\mbox{in a box}
\measuredangle₮\measuredangle₮\(\measuredangle\)₭\measuredangle₭₸\measuredangle₸
\medspace₮a\medspace b₮Not supported₭a\medspace b₭₸a\medspace b₸a\medspace b
\mho₮\mho₮\(\mho\)₭\mho₭₸\mho₸
\mid₮\{x∈ℝ\mid x > 0\}₮\(\{x∈ℝ\mid x>0\}\)₭\{x∈ℝ\mid x > 0\}₭₸\{x∈ℝ\mid x>0\}₸\{x∈ℝ\mid x>0\}
\middle₮P\left(A\middle\vert B\right)₮\(P\left(A\middle\vert B\right)\)₭P\left(A\middle\vert B\right)₭Not supportedP\left(A\middle\vert B\right)
\min₮\begin{matrix}\min x \\ \min_y x \\\min\limits_y x\end{matrix}₮\(\begin{matrix}\min x \\ \min_y x \\\min\limits_y x\end{matrix}\)₭\begin{matrix}\min x \\ \min_y x \\\min\limits_y x\end{matrix}₭₸\min₸
\minusoNot supported
See \standardstate
Not supported₭\minuso₭Not supported
\mitNot supported\(\mit{\Gamma\Theta}\)Not supportedNot supported\mit{\Gamma\Theta}
\mkern₮a\mkern18mu b₮\(a\mkern18mu b\)₭a\mkern18mu b₭Not supporteda\mkern18mu b
\mmlToken?Not supportedNot supportedNot supported
\mod₮3\equiv 5 \mod 2₮\(3\equiv 5 \mod 2\)₭3\equiv 5 \mod 2₭₸3\equiv 5 \mod 2₸3\equiv 5 \mod 2
\models₮\models₮\(\models\)₭\models₭₸\models₸
\moveleftNot supported\(O\moveleft3pt O\)Not supportedNot supportedO\moveleft3pt O
\moverightNot supported\(O\moveright3pt O\)Not supportedNot supportedO\moveright3pt O
\mp₮\mp₮\(\mp\)₭\mp₭₸\mp₸
\mskip₮a\mskip{10mu}b₮\(a\mskip{10mu}b\)₭a\mskip{10mu}b₭₸a\mskip{10mu}b₸a\mskip{10mu}b
\mspaceNot supported\(a\mspace18mu b\)Not supportedNot supporteda\mspace18mu b
\Mu₮\Mu₮\(\Mu\)₭\Mu₭₸\Mu₸
\mu₮\mu₮\(\mu\)₭\mu₭₸\mu₸
\multicolumnNot supportedNot supportedNot supportedNot supported
{multline}₮₮\begin{multline} -\rm first\ line \\ -\rm second\ line \\ -\rm third\ line -\end{multline}₮₮\[\begin{multline} - \rm first\ line \\ - \rm second\ line \\ - \rm third\ line - \end{multline}\]Not supportedNot supported
{multline*}₮₮\begin{multline*} -\rm first\ line \\ -\rm second\ line \\ -\rm third\ line -\end{multline*}₮₮\[\begin{multline*} - \rm first\ line \\ - \rm second\ line \\ - \rm third\ line - \end{multline*}\]Not supportedNot supported
\multimap₮\multimap₮\(\multimap\)₭\multimap₭₸\multimap₸
\multimapboth₮\multimapboth₮Not supportedNot supportedNot supported
\multimapinv₮\multimapinv₮Not supportedNot supportedNot supported
- -

N

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\N₮\N₮\(\N\)₭\N₭Not supported
\nabla₮\nabla₮\(\nabla\)₭\nabla₭₸\nabla₸
\natnums₮\natnums₮\(\natnums\)₭\natnums₭Not supported
\natural₮\natural₮\(\natural\)₭\natural₭₸\natural₸
\negmedspace₮a\negmedspace b₮\(a\negmedspace b\)₭a\negmedspace b₭₸a\negmedspace b₸a\negmedspace b
\ncong₮\ncong₮\(\ncong\)₭\ncong₭₸\ncong₸
\ne₮\ne₮\(\ne\)₭\ne₭₸\ne₸
\nearrow₮\nearrow₮\(\nearrow\)₭\nearrow₭₸\nearrow₸
\neg₮\neg₮\(\neg\)₭\neg₭₸\neg₸
\negthickspace₮a\negthickspace b₮\(a\negthickspace b\)₭a\negthickspace b₭Not supporteda\negthickspace b
\negthinspace₮a\negthinspace b₮\(a\negthinspace b\)₭a\negthinspace b₭Not supporteda\negthinspace b
\neq₮\neq₮\(\neq\)₭\neq₭₸\neq₸
\newcommand₮\newcommand\chk{\checkmark} \chk₮\(\newcommand\chk{\checkmark} \chk\)₭\newcommand\chk{\checkmark} \chk₭Not supported\newcommand\chk{\checkmark} \chk
\newenvironmentNot supported\(\newenvironment{tinyit}{\tiny\it}{\normalsize\rm}\begin{tinyit}Really small.\end{tinyit}\)Not supportedNot supported\newenvironment{tinyit}{\tiny\it}{\normalsize\rm}
\begin{tinyit}Really small.\end{tinyit}
\NewextarrowNot supported\(\Newextarrow{\xrightharpoonup}{5,10}{0x21C0} A \xrightharpoonup{\text{note}} B\)Not supportedNot supported\Newextarrow{\xrightharpoonup}{5,10}{0x21C0}
A \xrightharpoonup{\text{note}} B
\newextarrowNot supported<Not supportedNot supportedNot supportedSpelling per LaTeX.
\newline₮a\newline b₮Not supported₭a\newline b₭Not supporteda\newline b
\nexists₮\nexists₮\(\nexists\)₭\nexists₭₸\nexists₸
\ngeq₮\ngeq₮\(\ngeq\)₭\ngeq₭₸\ngeq₸
\ngeqq₮\ngeqq₮\(\ngeqq\)₭\ngeqq₭₸\ngeqq₸
\ngeqslant₮\ngeqslant₮\(\ngeqslant\)₭\ngeqslant₭₸\ngeqslant₸
\ngtr₮\ngtr₮\(\ngtr\)₭\ngtr₭₸\ngtr₸
\ni₮\ni₮\(\ni\)₭\ni₭₸\ni₸
\nleftarrow₮\nleftarrow₮\(\nleftarrow\)₭\nleftarrow₭₸\nleftarrow₸
\nLeftarrow₮\nLeftarrow₮\(\nLeftarrow\)₭\nLeftarrow₭₸\nLeftarrow₸
\nLeftrightarrow₮\nLeftrightarrow₮\(\nLeftrightarrow\)₭\nLeftrightarrow₭₸\nLeftrightarrow₸
\nleftrightarrow₮\nleftrightarrow₮\(\nleftrightarrow\)₭\nleftrightarrow₭₸\nleftrightarrow₸
\nleq₮\nleq₮\(\nleq\)₭\nleq₭₸\nleq₸
\nleqq₮\nleqq₮\(\nleqq\)₭\nleqq₭₸\nleqq₸
\nleqslant₮\nleqslant₮\(\nleqslant\)₭\nleqslant₭₸\nleqslant₸
\nless₮\nless₮\(\nless\)₭\nless₭₸\nless₸
\nmid₮\nmid₮\(\nmid\)₭\nmid₭₸\nmid₸
\nobreakNot supportedNot supportedNot supportedNot supported
\nobreakspace₮a\nobreakspace b₮\(a\nobreakspace b\)₭a\nobreakspace b₭Not supporteda\nobreakspace b
\nolimits₮\lim\nolimits_x₮\(\lim\nolimits_x\)₭\lim\nolimits_x₭Not supported\lim\nolimits_x
\normalsize₮\normalsize normalsize₮\(\normalsize normalsize\)₭\normalsize normalsize₭Not supported\normalsize normalsize
\not₮\not =₮\(\not =\)₭\not =₭₸\not =₸\not =
\notagNot supportedNot supportedNot supported
\notin₮\notin₮\(\notin\)₭\notin₭₸\notin₸
\notni₮\notni₮Not supported₭\notni₭₸\notni₸
\nparallel₮\nparallel₮\(\nparallel\)₭\nparallel₭₸\nparallel₸
\nprec₮\nprec₮\(\nprec\)₭\nprec₭₸\nprec₸
\npreceq₮\npreceq₮\(\npreceq\)₭\npreceq₭₸\npreceq₸
\nRightarrow₮\nRightarrow₮\(\nRightarrow\)₭\nRightarrow₭₸\nRightarrow₸
\nrightarrow₮\nrightarrow₮\(\nrightarrow\)₭\nrightarrow₭₸\nrightarrow₸
\nshortmid₮\nshortmid₮\(\nshortmid\)₭\nshortmid₭₸\nshortmid₸
\nshortparallel₮\nshortparallel₮\(\nshortparallel\)₭\nshortparallel₭₸\nshortparallel₸
\nsim₮\nsim₮\(\nsim\)₭\nsim₭₸\nsim₸
\nsubset₮\nsubset₮Not supportedNot supported₸\nsubset₸
\nsubseteq₮\nsubseteq₮\(\nsubseteq\)₭\nsubseteq₭₸\nsubseteq₸
\nsubseteqq₮\nsubseteqq₮\(\nsubseteqq\)₭\nsubseteqq₭₸\nsubseteqq₸
\nsucc₮\nsucc₮\(\nsucc\)₭\nsucc₭₸\nsucc₸
\nsucceq₮\nsucceq₮\(\nsucceq\)₭\nsucceq₭₸\nsucceq₸
\nsupset₮\nsupset₮Not supportedNot supported₸\nsupset₸
\nsupseteq₮\nsupseteq₮\(\nsupseteq\)₭\nsupseteq₭₸\nsupseteq₸
\nsupseteqq₮\nsupseteqq₮\(\nsupseteqq\)₭\nsupseteqq₭Not supported
\ntriangleleft₮\ntriangleleft₮\(\ntriangleleft\)₭\ntriangleleft₭₸\ntriangleleft₸
\ntrianglelefteq₮\ntrianglelefteq₮\(\ntrianglelefteq\)₭\ntrianglelefteq₭₸\ntrianglelefteq₸
\ntriangleright₮\ntriangleright₮\(\ntriangleright\)₭\ntriangleright₭₸\ntriangleright₸
\ntrianglerighteq₮\ntrianglerighteq₮\(\ntrianglerighteq\)₭\ntrianglerighteq₭₸\ntrianglerighteq₸
\Nu₮\Nu₮\(\Nu\)₭\Nu₭₸\Nu₸
\nu₮\nu₮\(\nu\)₭\nu₭₸\nu₸
\nVDash₮\nVDash₮\(\nVDash\)₭\nVDash₭₸\nVDash₸
\nVdash₮\nVdash₮\(\nVdash\)₭\nVdash₭₸\nVdash₸
\nvDash₮\nvDash₮\(\nvDash\)₭\nvDash₭₸\nvDash₸
\nvdash₮\nvdash₮\(\nvdash\)₭\nvdash₭₸\nvdash₸
\nwarrow₮\nwarrow₮\(\nwarrow\)₭\nwarrow₭₸\nwarrow₸
- -

O

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\O₮\text{\O}₮Not supported₭\text{\O}₭₸\text{\O}₸\text{\O}
\o₮\text{\o}₮Not supported₭\text{\o}₭₸\text{\o}₸\text{\o}
\oc₮\oc₮Not supportedNot supportedNot supported
\odv₮\odv{f}{x}₮Not supportedNot supportedNot supported\odv{f}{x}
\odv*`₮\odv*{f}{x}₮Not supportedNot supportedNot supported\odv*{f}{x}
\odot₮\odot₮\(\odot\)₭\odot₭₸\odot₸
\OE₮\text{\OE}₮Not supported₭\text{\OE}₭₸\text{\OE}₸\text{\OE}
\oe₮\text{\oe}₮Not supported₭\text{\oe}₭₸\text{\oe}₸\text{\oe}
\officialeuroNot supported
See \euro
\(\officialeuro\)Not supportedNot supported
\oiiint₮\oiiint_0^n x \; \displaystyle \oiiint_0^n x₮\(\oiiint_0^n x \; \displaystyle \oiiint_0^n x\)₭\oiiint_0^n x \; \displaystyle \oiiint_0^n x₭₸\oiiint₸
\oiint₮\oiint_0^n x \; \displaystyle \oiint_0^n x₮\(\oiint_0^n x \; \displaystyle \oiint_0^n x\)₭\oiint_0^n x \; \displaystyle \oiint_0^n x₭₸\oiint₸
\oint₮\oint_0^n x \; \displaystyle \oint_0^n x₮\(\oint_0^n x \; \displaystyle \oint_0^n x\)₭\oint_0^n x \; \displaystyle \oint_0^n x₭₸\oint₸
\oldstyleNot supported
See \oldstylenums
\(\oldstyle 0123456\)Not supportedNot supported\oldstyle 0123456
\oldstylenums₮\oldstylenums{123}₮Not supportedNot supportedNot supported\oldstylenums{123}
\omega₮\omega₮\(\omega\)₭\omega₭₸\omega₸
\Omega₮\Omega₮\(\Omega\)₭\Omega₭₸\Omega₸
\Omicron₮\Omicron₮\(\Omicron\)₭\Omicron₭Not supported
\omicron₮\omicron₮\(\omicron\)₭\omicron₭₸\omicron₸
\ominus₮\ominus₮\(\ominus\)₭\ominus₭₸\ominus₸
\operatorname₮\operatorname{asin} x₮\(\operatorname{asin} x\)₭\operatorname{asin} x₭₸\operatorname{asin} x₸\operatorname{asin} x
\operatorname*₮\begin{matrix}\operatorname*{asin} x \\ \operatorname*{asin}_y x \\ \operatorname*{asin}\limits_y x\end{matrix}₮\(\begin{matrix}\operatorname*{asin} x \\ \operatorname*{asin}_y x \\ \operatorname*{asin}\limits_y x\end{matrix}\)₭\begin{matrix}\operatorname*{asin} x \\ \operatorname*{asin}_y x \\ \operatorname*{asin}\limits_y x\end{matrix}₭₸\operatorname*{func}\limits_a^b(x)₸\operatorname*{asin} x
\operatorname*{asin}_y x
\operatorname*{asin}\limits_y x\end
\oplus₮\oplus₮\(\oplus\)₭\oplus₭₸\oplus₸
\orNot supportedNot supportedNot supportedNot supported
\origof₮\origof₮Not supported₭\origof₭Not supported
\oslash₮\oslash₮\(\oslash\)₭\oslash₭₸\oslash₸
\otimes₮\otimes₮\(\otimes\)₭\otimes₭₸\otimes₸
\over₮{a+1 \over b+2}+c₮\({a+1 \over b+2}+c\)₭{a+1 \over b+2}+c₭₸{a+1 \over b+2}+c₸{a+1 \over b+2}+c
\overbrace₮\overbrace{x+⋯+x}^{n\text{ times}}₮\(\overbrace{x+⋯+x}^{n\text{ times}}\)₭\overbrace{x+⋯+x}^{n\text{ times}}₭₸\overbrace{x+⋯+x}^{n\text{ times}}₸\overbrace{x+⋯+x}^{n\text{ times}}
\overbracketNot supportedNot supportedNot supportedNot supported
\overgroup₮\overgroup{AB}₮Not supported₭\overgroup{AB}₭₸\overgroup{AB}₸\overgroup{AB}
\overleftarrow₮\overleftarrow{AB}₮\(\overleftarrow{AB}\)₭\overleftarrow{AB}₭₸\overleftarrow{AB}₸\overleftarrow{AB}
\overleftharpoon₮\overleftharpoon{AB}₮Not supported₭\overleftharpoon{AB}₭₸\overleftharpoon{AB}₸\overleftharpoon{AB}
\overleftrightarrow₮\overleftrightarrow{AB}₮\(\overleftrightarrow{AB}\)₭\overleftrightarrow{AB}₭₸\overleftrightarrow{AB}₸\overleftrightarrow{AB}
\overline₮\overline{\text{a long argument}}₮\(\overline{\text{a long argument}}\)₭\overline{\text{a long argument}}₭₸\overline{\text{a long argument}}₸\overline{\text{a long argument}}
\overlinesegmentNot supportedNot supportedNot supportedNot supported
\overparen₮\overparen{AB}₮\(\overparen{AB}\)Not supported₸\overparen{AB}₸See \overgroup
\Overrightarrow₮\Overrightarrow{AB}₮Not supported₭\Overrightarrow{AB}₭Not supported\Overrightarrow{AB}
\overrightarrow₮\overrightarrow{AB}₮\(\overrightarrow{AB}\)₭\overrightarrow{AB}₭₸\overrightarrow{AB}₸\overrightarrow{AB}
\overrightharpoon₮\overrightharpoon{ac}₮Not supported₭\overrightharpoon{ac}₭₸\overrightharpoon{ac}₸\overrightharpoon{ac}
\overset₮\overset{!}{=}₮\(\overset{!}{=}\)₭\overset{!}{=}₭₸\overset{!}{=}₸\overset{!}{=}
\overwithdelimsNot supported\(a \overwithdelims [ ] b\)Not supportedNot supported
\owns₮\owns₮\(\owns\)₭\owns₭Not supported
- -

P

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\P₮\text{\P}₮Not supported₭\text{\P}₭₸\text{\P}₸\text{\P}
\pagecolor?Not supportedNot supportedNot supportedDeprecated
\parallel₮\parallel₮\(\parallel\)₭\parallel₭₸\parallel₸
\parr₮\parr₮Not supportedNot supportedNot supported
\part??Not supportedNot supportedNot supportedDeprecated
\partial₮\partial₮\(\partial\)₭\partial₭₸\partial₸
\permil₮\permil₮Not supportedNot supportedNot supported
\pdv₮\pdv{f}{x,y}₮Not supportedNot supportedNot supported\pdv{f}{x,y}
\pdv*₮\pdv*{f}{x,y}₮Not supportedNot supportedNot supported\pdv*{f}{x,y}
\perp₮\perp₮\(\perp\)₭\perp₭₸\perp₸
\phantom₮\Gamma^{\phantom{i}j}_{i\phantom{j}k}₮\(\Gamma^{\phantom{i}j}_{i\phantom{j}k}\)₭\Gamma^{\phantom{i}j}_{i\phantom{j}k}₭₸\Gamma^{\phantom{i}j}_{i\phantom{j}k}₸\Gamma^{\phantom{i}j}_{i\phantom{j}k}
\phase₮120\text{V}\phase{78.2\degree}₮Not supported
See \enclose
₭120\text{V}\phase{78.2\degree}₭Not supported120\text{V}\phase{78.2\degree}
\Phi₮\Phi₮\(\Phi\)₭\Phi₭₸\Phi₸
\phi₮\phi₮\(\phi\)₭\phi₭₸\phi₸
\Pi₮\Pi₮\(\Pi\)₭\Pi₭₸\Pi₸
\pi₮\pi₮\(\pi\)₭\pi₭₸\pi₸
{picture}Not supportedNot supportedNot supportedNot supported
\pitchfork₮\pitchfork₮\(\pitchfork\)₭\pitchfork₭₸\pitchfork₸
\plim₮\plim₮Not supported₭\plim₭Not supported
\plusmn₮\plusmn₮\(\plusmn\)₭\plusmn₭Not supported
\pm₮\pm₮\(\pm\)₭\pm₭₸\pm₸
\pmatrixNot supported\(\pmatrix{a&b\\c&d}\)Not supported₸\pmatrix{a&b\\c&d}₸See {pmatrix}
{pmatrix}₮\begin{pmatrix}a&b\\c&d\end{pmatrix}₮\(\begin{pmatrix}a&b\\c&d\end{pmatrix}\)₭\begin{pmatrix}a&b\\c&d\end{pmatrix}₭₸\begin{pmatrix}a&b\\c&d\end{pmatrix}₸\begin{pmatrix}
   a & b \\
   c & d
\end{pmatrix}
\pmb₮\pmb{\mu}₮\(\pmb{\mu}\)₭\pmb{\mu}₭Not supported\pmb{\mu}
\pmod₮x\pmod a₮\(x\pmod a\)₭x\pmod a₭Not supportedx\pmod a
\pod₮x \pod a₮\(x \pod a\)₭x \pod a₭Not supportedx \pod a
\pounds₮\pounds₮Not supported₭\pounds₭Not supported
\Pr₮\begin{matrix}\Pr x \\ \Pr_y x \\\Pr\limits_y x\end{matrix}₮\(\begin{matrix}\Pr x \\ \Pr_y x \\\Pr\limits_y x\end{matrix}\)₭\begin{matrix}\Pr x \\ \Pr_y x \\\Pr\limits_y x\end{matrix}₭₸\Pr₸
\prec₮\prec₮\(\prec\)₭\prec₭₸\prec₸
\precapprox₮\precapprox₮\(\precapprox\)₭\precapprox₭₸\precapprox₸
\preccurlyeq₮\preccurlyeq₮\(\preccurlyeq\)₭\preccurlyeq₭₸\preccurlyeq₸
\preceq₮\preceq₮\(\preceq\)₭\preceq₭₸\preceq₸
\precnapprox₮\precnapprox₮\(\precnapprox\)₭\precnapprox₭₸\precnapprox₸
\precneqq₮\precneqq₮\(\precneqq\)₭\precneqq₭₸\precneqq₸
\precnsim₮\precnsim₮\(\precnsim\)₭\precnsim₭₸\precnsim₸
\precsim₮\precsim₮\(\precsim\)₭\precsim₭₸\precsim₸
\prescript₮\prescript{a}{2}{\mathbf{C}}^{5+}_{2}₮Not supported₭\prescript{a}{2}{\mathbf{C}}^{5+}_{2}₭Not supported\prescript{a}{2}{\mathbf{C}}^{5+}_{2}
\prime₮\prime₮\(\prime\)₭\prime₭₸\prime₸
\prod₮\prod_0^n x \; \displaystyle \prod_0^n x₮\(\prod_0^n x \; \displaystyle \prod_0^n x\)₭\prod_0^n x \; \displaystyle \prod_0^n x₭₸\prod₸
\projlim₮\projlim_n x₮\(\projlim_n x\)₭\projlim_n x₭Not supported\projlim_n x
\propto₮\propto₮\(\propto\)₭\propto₭₸\propto₸
\providecommand₮\providecommand\greet{\text{Hello}} \greet₮Not supported₭\providecommand\greet{\text{Hello}} \greet₭Not supported\providecommand\greet{\text{Hello}} \greet
\psi₮\psi₮\(\psi\)₭\psi₭₸\psi₸
\Psi₮\Psi₮\(\Psi\)₭\Psi₭₸\Psi₸
\pu₮{123~\mathchoice{\textstyle\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}}₮\({123~\mathchoice{\textstyle\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}}\)₭{123~\mathchoice{\textstyle\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}}₭Not supported\pu{123 kJ//mol}
- -

QR

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\QNot supported\(\Q\)Not supportedNot supportedSee \Bbb{Q}
\qquad₮a\qquad\qquad{b}₮\(a\qquad\qquad{b}\)₭a\qquad\qquad{b}₭₸a\qquad\qquad{b}₸a\qquad\qquad{b}
\quad₮a\quad\quad{b}₮\(a\quad\quad{b}\)₭a\quad\quad{b}₭₸a\quad\quad{b}₸a\quad\quad{b}
\R₮\R₮\(\R\)₭\R₭Not supported
\r₮\text{\r{a}}₮\(\text{\r{a}}\)₭\text{\r{a}}₭₸\text{\r{a}}₸\text{\r{a}}
\raise₮h\raise{2pt}{ighe}r₮\(h\raise{2pt}{ighe}r\)₭h\raise{2pt}{ighe}r₭Not supportedh\raise{2pt}{ighe}r
\raisebox₮h\raisebox{2pt}{ighe}r₮Not supported₭h\raisebox{2pt}{ighe}r₭Not supportedh\raisebox{2pt}{ighe}r
\rang₮\langle A\rang₮\(\langle A\rang\)₭\langle A\rang₭₸\langle A\rang₸\langle A\rang
\rangle₮\langle A\rangle₮\(\langle A\rangle\)₭\langle A\rangle₭₸\langle A\rangle₸\langle A\rangle
\Rarr₮\Rarr₮\(\Rarr\)₭\Rarr₭Not supported
\rArr₮\rArr₮\(\rArr\)₭\rArr₭Not supported
\rarr₮\rarr₮\(\rarr\)₭\rarr₭Not supported
\rBrace₮\rBrace₮Not supported₭\rBrace₭Not supported
\rbrace₮\rbrace₮\(\rbrace\)₭\rbrace₭₸\rbrace₸
\rbrack₮\rbrack₮\(\rbrack\)₭\rbrack₭₸\rbrack₸
{rcases}₮\begin{rcases}a&\text{if }b\\c&\text{if }d\end{rcases}₮Not supported₭\begin{rcases}a&\text{if }b\\c&\text{if }d\end{rcases}₭₸\begin{rcases}a&\text{if }b\\c&\text{if }d\end{rcases}₸\begin{rcases}
   a&\text{if }b\\
   c&\text{if }d
\end{rcases}
\rceil₮\rceil₮\(\rceil\)₭\rceil₭₸\rceil₸
\Re₮\Re₮\(\Re\)₭\Re₭₸\Re₸
\real₮\real₮\(\real\)₭\real₭Not supported
\Reals₮\Reals₮\(\Reals\)₭\Reals₭Not supported
\reals₮\reals₮\(\reals\)₭\reals₭Not supported
\ref₮\ref{maxwell}₮SupportedNot supportedNot supported\ref{maxwell}
\relaxNot supportedNot supported
\renewcommand₮\def\hail{Hi!}\renewcommand\hail{\text{Ahoy!}} \hail₮\(\def\hail{Hi!}\renewcommand\hail{\text{Ahoy!}} \hail\)₭\def\hail{Hi!}\renewcommand\hail{\text{Ahoy!}} \hail₭Not supported\def\hail{Hi!}
\renewcommand\hail{\text{Ahoy!}}
\hail
\renewenvironmentNot supportedNot supportedNot supported
\requireNot supportedNot supportedNot supported
\restriction₮\restriction₮\(\restriction\)₭\restriction₭Not supported
\rfloor₮\rfloor₮\(\rfloor\)₭\rfloor₭₸\rfloor₸
\rgroup₮\rgroup₮\(\rgroup\)₭\rgroup₭Not supported
\rhd₮\rhd₮\(\rhd\)₭\rhd₭₸\rhd₸
\Rho₮\Rho₮\(\Rho\)₭\Rho₭₸\Rho₸
\rho₮\rho₮\(\rho\)₭\rho₭₸\rho₸
\right₮\left.\frac a b\right)₮\(\left.\frac a b\right)\)₭\left.\frac a b\right)₭₸\left.\frac a b\right)₸\left.\frac a b\right)
\Rightarrow₮\Rightarrow₮\(\Rightarrow\)₭\Rightarrow₭₸\Rightarrow₸
\rightarrow₮\rightarrow₮\(\rightarrow\)₭\rightarrow₭₸\rightarrow₸
\rightarrowtail₮\rightarrowtail₮\(\rightarrowtail\)₭\rightarrowtail₭₸\rightarrowtail₸
\rightharpoondown₮\rightharpoondown₮\(\rightharpoondown\)₭\rightharpoondown₭₸\rightharpoondown₸
\rightharpoonup₮\rightharpoonup₮\(\rightharpoonup\)₭\rightharpoonup₭₸\rightharpoonup₸
\rightleftarrows₮\rightleftarrows₮\(\rightleftarrows\)₭\rightleftarrows₭₸\rightleftarrows₸
\rightleftharpoons₮\rightleftharpoons₮\(\rightleftharpoons\)₭\rightleftharpoons₭₸\rightleftharpoons₸
\rightrightarrows₮\rightrightarrows₮\(\rightrightarrows\)₭\rightrightarrows₭₸\rightrightarrows₸
\rightsquigarrow₮\rightsquigarrow₮\(\rightsquigarrow\)₭\rightsquigarrow₭₸\rightsquigarrow₸
\rightthreetimes₮\rightthreetimes₮\(\rightthreetimes\)₭\rightthreetimes₭₸\rightthreetimes₸
\risingdotseq₮\risingdotseq₮\(\risingdotseq\)₭\risingdotseq₭₸\risingdotseq₸
\rlap₮\rlap{\,/}{=}₮\(\rlap{\,/}{=}\)₭\rlap{\,/}{=}₭Not supported\rlap{\,/}{=}
\rm₮\rm AaBb12\theta₮\(\rm AaBb12\theta\)₭\rm AaBb12\theta₭Not supported\rm AaBb12\theta
\rmoustache₮\rmoustache₮\(\rmoustache\)₭\rmoustache₭₸\rmoustache₸
\rootNot supported\(\root 3 \of x\)Not supported₸\root{3}{x}₸MathJax and TeXZilla differ in syntax:
\root 3 \of x vs. \root{3}{x}
\rotateboxNot supportedNot supportedNot supportedNot supported
\rparen₮\rparen₮Not supported₭\rparen₭Not supported
\rq₮\rq₮Not supported₭\rq₭₸\rq₸
\Rrightarrow₮\Rrightarrow₮\(\Rrightarrow\)₭\Rrightarrow₭₸\Rrightarrow₸
\rrbracket₮\rrbracket₮Not supported₭\rrbracket₭Not supported
\Rsh₮\Rsh₮\(\Rsh\)₭\Rsh₭₸\Rsh₸
\rtimes₮\rtimes₮\(\rtimes\)₭\rtimes₭₸\rtimes₸
\RuleNot supported\(x\Rule{3px}{0.5ex}{2ex}x\)Not supportedNot supportedNon-standard
\rule₮x\color{blue}\rule[6pt]{2ex}{1ex}x₮\(x\color{blue}\rule[6pt]{2ex}{1ex}x\)₭x\color{blue}\rule[6pt]{2ex}{1ex}x₭Not supportedx\color{blue}\rule[6pt]{2ex}{1ex}x
\rVert₮\rVert₮\(\rVert\)₭\rVert₭Not supported
\rvert₮\rvert₮\(\rvert\)₭\rvert₭Not supported
- -

S

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\S₮\text{\S}₮Not supported₭\text{\S}₭₸\text{\S}₸\text{\S}
\Sampi₮\Sampi₮Not supportedNot supportedNot supported
\sampi₮\sampi₮Not supportedNot supportedNot supported
\scaleboxNot supportedNot supportedNot supportedNot supported
\scoh₮\scoh₮Not supportedNot supportedNot supported
\scrNot supported\(\scr M\)Not supportedNot supported\scr M
\scriptscriptstyle₮\scriptscriptstyle \frac cd₮\(\scriptscriptstyle \frac cd\)₭\scriptscriptstyle \frac cd₭Not supported\scriptscriptstyle \frac cd
\scriptsize₮\scriptsize scriptsize₮\(\scriptsize scriptsize\)₭\scriptsize scriptsize₭₸\scriptsize scriptsize₸\scriptsize scriptsize
\scriptstyle₮\frac ab + {\scriptstyle \frac cd}₮\(\frac ab + {\scriptstyle \frac cd}\)₭\frac ab + {\scriptstyle \frac cd}₭Not supported\frac ab + {\scriptstyle \frac cd}
\sdot₮\sdot₮\(\sdot\)₭\sdot₭Not supported
\searrow₮\searrow₮\(\searrow\)₭\searrow₭₸\searrow₸
\sec₮\sec₮\(\sec\)₭\sec₭₸\sec₸
\sect₮\text{\sect}₮Not supported₭\text{\sect}₭Not supported\text{\sect}
\set₮\set{ x | x<5 }₮Requires extensionNot supportedNot supported\Set{x|x<5}
\Set₮\Set{ x | x<\frac 1 2 }₮Requires extensionNot supportedNot supported\Set{ x | x<\frac 1 2 }
\setlengthNot supportedNot supportedNot supportedNot supported
\setminus₮\setminus₮\(\setminus\)₭\setminus₭₸\setminus₸
\sf₮\sf AaBb123₮\(\sf AaBb123\)₭\sf AaBb123₭Not supported\sf AaBb123
\sgn₮\sgn₮Not supportedNot supportedNot supported
\sharp₮\sharp₮\(\sharp\)₭\sharp₭₸\sharp₸
\shift₮\shift₮Not supportedNot supportedNot supported
\shneg₮\shneg₮Not supportedNot supportedNot supported
\shortmid₮\shortmid₮\(\shortmid\)₭\shortmid₭₸\shortmid₸
\shortparallel₮\shortparallel₮\(\shortparallel\)₭\shortparallel₭₸\shortparallel₸
\shoveleftNot supported\(\begin{multline*} -\rm first\ line \\ -\shoveleft{\rm 2nd} \\ -\rm third\ line -\end{multline*}\)Not supportedNot supported
\shoverightNot supported\(\begin{multline*} -\rm first\ line \\ -\shoveright{\rm 2nd} \\ -\rm third\ line -\end{multline*}\)Not supportedNot supported
\shpos₮\shpos₮Not supportedNot supportedNot supported
\sideset₮\sideset{_1^2}{_3^4}\sum₮Not supportedNot supported₸\sideset{_1^2}{_3^4}\sum₸
\Sigma₮\Sigma₮\(\Sigma\)₭\Sigma₭₸\Sigma₸
\sigma₮\sigma₮\(\sigma\)₭\sigma₭₸\sigma₸
\sim₮\sim₮\(\sim\)₭\sim₭₸\sim₸
\simeq₮\simeq₮\(\simeq\)₭\simeq₭₸\simeq₸
\sin₮\sin x₮\(\sin x\)₭\sin x₭₸\sin x₸
\sincoh₮\sincoh₮Not supportedNot supportedNot supported
\sinh₮\sinh x₮\(\sinh x\)₭\sinh x₭₸\sinh x₸
\sixptsize₮\sixptsize sixptsize₮Not supported₭\sixptsize sixptsize₭Not supported\sixptsize sixptsize
\sh₮\sh₮Not supported₭\sh₭Not supported
\skewNot supported\(\hat A\skew9\hat A\)Not supportedNot supported\hat A\skew9\hat A
\skipNot supportedNot supportedNot supportedNot supported
\small₮\small small₮\(\small small\)₭\small small₭Not supported\small small
\smallfrown₮\smallfrown₮\(\smallfrown\)₭\smallfrown₭₸\smallfrown₸
\smallint₮\smallint_0^n x \; \smallint\limits_0^n x \; \displaystyle \smallint_0^n x₮\(\smallint_0^n x \; \smallint\limits_0^n x \; \displaystyle \smallint_0^n x\)₭\smallint_0^n x \; \smallint\limits_0^n x \; \displaystyle \smallint_0^n x₭Not supported - \smallint_0^n x
\smallint\limits_0^n x
\displaystyle \smallint_0^n x -
{smallmatrix}₮\begin{smallmatrix}a & b\\c & d\end{smallmatrix}₮\(\begin{smallmatrix}a & b\\c & d\end{smallmatrix}\)₭\begin{smallmatrix}a & b\\c & d\end{smallmatrix}₭₸\begin{smallmatrix}a & b\\c & d\end{smallmatrix}₸\begin{smallmatrix}a & b\\
c & d\end{smallmatrix}
\smallsetminus₮\smallsetminus₮\(\smallsetminus\)₭\smallsetminus₭₸\smallsetminus₸
\smallsmile₮\smallsmile₮\(\smallsmile\)₭\smallsmile₭₸\smallsmile₸
\smash₮\left(x^{\smash{2}}\right)₮\(\left(x^{\smash{2}}\right)\)₭\left(x^{\smash{2}}\right)₭Not supported\left(x^{\smash{2}}\right)
\smile₮\smile₮\(\smile\)₭\smile₭₸\smile₸
\smiley₮\smiley₮Not supportedNot supportedNot supportedwasysym
\sout₮\sout{abc}₮Not supported₭\sout{abc}₭Not supported\sout{abc}
\SpaceNot supported\(a\Space{5px}{4ex}{2ex}^b_c d\)Not supportedNot supporteda\Space{5px}{4ex}{2ex}^b_c d
\space₮a\space{b}₮\(a\space{b}\)₭a\space{b}₭₸a\space{b}₸a\space{b}
\spades₮\spades₮\(\spades\)₭\spades₭Not supported
\spadesuit₮\spadesuit₮\(\spadesuit\)₭\spadesuit₭₸\spadesuit₸
\sphericalangle₮\sphericalangle₮\(\sphericalangle\)₭\sphericalangle₭₸\sphericalangle₸
{split}₮₮\begin{equation}\begin{split}∇·𝐃&=ρ_v \\ ∇·𝐁&=0 \end{split}\end{equation}₮₮\[\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}\]₭₭\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}₭₭Not supported\begin{equation}
\begin{split}
   ∇·𝐃&=ρ_v \\
   ∇·𝐁&=0
\end{split}
\end{equation}
\sqcap₮\sqcap₮\(\sqcap\)₭\sqcap₭₸\sqcap₸
\sqcup₮\sqcup₮\(\sqcup\)₭\sqcup₭₸\sqcup₸
\square₮\square₮\(\square\)₭\square₭₸\square₸
\sqrt₮\sqrt[3]{x}₮\(\sqrt[3]{x}\)₭\sqrt[3]{x}₭₸\sqrt[3]{x}₸\sqrt[3]{x}
\sqsubset₮\sqsubset₮\(\sqsubset\)₭\sqsubset₭₸\sqsubset₸
\sqsubseteq₮\sqsubseteq₮\(\sqsubseteq\)₭\sqsubseteq₭₸\sqsubseteq₸
\sqsupset₮\sqsupset₮\(\sqsupset\)₭\sqsupset₭₸\sqsupset₸
\sqsupseteq₮\sqsupseteq₮\(\sqsupseteq\)₭\sqsupseteq₭₸\sqsupseteq₸
\ss₮\text{\ss}₮Not supported₭\text{\ss}₭₸\text{\ss}₸\text{\ss}
\stackrel₮\stackrel{!}{=}₮\(\stackrel{!}{=}\)₭\stackrel{!}{=}₭₸\stackrel{!}{=}₸\stackrel{!}{=}
\star₮\star₮\(\star\)₭\star₭₸\star₸
\Stigma₮\Stigma₮Not supportedNot supportedNot supported
\stigma₮\stigma₮Not supportedNot supportedNot supported
\strictif₮\strictif₮Not supportedNot supportedNot supported
\strictfi₮\strictfi₮Not supportedNot supportedNot supported
\strutNot supported\(\boxed{ab\strut}\)Not supportedNot supported\boxed{ab\strut}
\styleNot supported\(\frac{\style{color:red}{x+1}}{y+2}\)Not supportedNot supported\frac{\style{color:red}{x+1}}{y+2}
Non standard
\sub₮\sub₮\(\sub\)₭\sub₭Not supported
{subarray}₮\begin{subarray}{c} a \\ c \end{subarray}₮\(\begin{subarray}{c} a \\ c \end{subarray}\)₭\begin{subarray}{c} a \\ c \end{subarray}₭Not supported\sum_{\begin{subarray}
   {c} a \\
   c
\end{subarray}}
\sube₮\sube₮\(\sube\)₭\sube₭Not supported
\Subset₮\Subset₮\(\Subset\)₭\Subset₭₸\Subset₸
\subset₮\subset₮\(\subset\)₭\subset₭₸\subset₸
\subseteq₮\subseteq₮\(\subseteq\)₭\subseteq₭₸\subseteq₸
\subseteqq₮\subseteqq₮\(\subseteqq\)₭\subseteqq₭₸\subseteqq₸
\subsetneq₮\subsetneq₮\(\subsetneq\)₭\subsetneq₭₸\subsetneq₸
\subsetneqq₮\subsetneqq₮\(\subsetneqq\)₭\subsetneqq₭₸\subsetneqq₸
\substack₮\displaystyle\sum_{\substack{1\lt i\lt 3 \\ 1\le j\lt 5}}a_{ij}₮\(\displaystyle\sum_{\substack{1\lt i\lt 3 \\ 1\le j\lt 5}}a_{ij}\)₭\displaystyle\sum_{\substack{1\lt i\lt 3 \\ 1\le j\lt 5}}a_{ij}₭₸\displaystyle\sum_{\substack{1\lt i\lt 3 \\ 1\le j\lt 5}}a_{ij}₸\sum_{\substack{1\lt i\lt 3 \\
1\le j\lt 5}}a_{ij}
\succ₮\succ₮\(\succ\)₭\succ₭₸\succ₸
\succapprox₮\succapprox₮\(\succapprox\)₭\succapprox₭₸\succapprox₸
\succcurlyeq₮\succcurlyeq₮\(\succcurlyeq\)₭\succcurlyeq₭₸\succcurlyeq₸
\succeq₮\succeq₮\(\succeq\)₭\succeq₭₸\succeq₸
\succnapprox₮\succnapprox₮\(\succnapprox\)₭\succnapprox₭₸\succnapprox₸
\succneqq₮\succneqq₮\(\succneqq\)₭\succneqq₭₸\succneqq₸
\succnsim₮\succnsim₮\(\succnsim\)₭\succnsim₭₸\succnsim₸
\succsim₮\succsim₮\(\succsim\)₭\succsim₭₸\succsim₸
\sum₮\sum_0^n x \; \displaystyle \sum_0^n x₮\(\sum_0^n x \; \displaystyle \sum_0^n x\)₭\sum_0^n x \; \displaystyle \sum_0^n x₭₸\sum_0^n x₸
\sup₮\begin{matrix}\sup x \\ \sup_y x \\\sup\limits_y x\end{matrix}₮\(\begin{matrix}\sup x \\ \sup_y x \\\sup\limits_y x\end{matrix}\)₭\begin{matrix}\sup x \\ \sup_y x \\\sup\limits_y x\end{matrix}₭₸\begin{matrix}\sup x \\ \sup_y x \\\sup\limits_y x\end{matrix}₸
\supe₮\supe₮\(\supe\)₭\supe₭₸\supe₸
\Supset₮\Supset₮\(\Supset\)₭\Supset₭₸\Supset₸
\supset₮\supset₮\(\supset\)₭\supset₭₸\supset₸
\supseteq₮\supseteq₮\(\supseteq\)₭\supseteq₭₸\supseteq₸
\supseteqq₮\supseteqq₮\(\supseteqq\)₭\supseteqq₭₸\supseteqq₸
\supsetneq₮\supsetneq₮\(\supsetneq\)₭\supsetneq₭₸\supsetneq₸
\supsetneqq₮\supsetneqq₮\(\supsetneqq\)₭\supsetneqq₭₸\supsetneqq₸
\surd₮\surd₮\(\surd\)₭\surd₭₸\surd₸
\swarrow₮\swarrow₮\(\swarrow\)₭\swarrow₭₸\swarrow₸
- -

T

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\tag₮₮\tag{3.1c} a^2+b^2=c^2₮₮\(\tag{3.1c} a^2+b^2=c^2\)₭₭\tag{3.1c} a^2+b^2=c^2₭₭Not supported\tag{3.1c} a^2+b^2=c^2
\tag*₮₮\tag*{3.1c} a^2+b^2=c^2₮₮\(\tag*{3.1c} a^2+b^2=c^2\)₭₭\tag*{3.1c} a^2+b^2=c^2₭₭Not supported\tag*{3.1c} a^2+b^2=c^2
\tan₮\tan x₮\(\tan x\)₭\tan x₭₸\tan x₸
\tanh₮\tanh x₮\(\tanh x\)₭\tanh x₭₸\tanh x₸
\Tau₮\Tau₮\(\Tau\)₭\Tau₭₸\Tau₸
\tau₮\tau₮\(\tau\)₭\tau₭₸\tau₸
\tbinom₮\tbinom n k₮\(\tbinom n k\)₭\tbinom n k₭₸\tbinom n k₸\tbinom n k
\TeX₮\TeX₮\(\TeX\)₭\TeX₭Not supported
\text₮\text{ yes }\&\text{ no }₮\(\text{ yes }\&\text{ no }\)₭\text{ yes }\&\text{ no }₭₸\text{ yes }\&\text{ no }₸\text{ yes }\&\text{ no }
\text₮\text{MMM$M\mkern2mu M$M}₮\(\text{MMM$M\mkern2mu M$M}\)₭\text{MMM$M\mkern2mu M$M}₭₸\text{MMM$M\mkern2mu M$M}₸\text{MMM$M\mkern2mu M$M}
\textasciitilde₮\text{\textasciitilde}₮Not supported₭\text{\textasciitilde}₭₸\text{\textasciitilde}₸\text{\textasciitilde}
\textasciicircum₮\text{\textasciicircum}₮Not supported₭\text{\textasciicircum}₭₸\text{\textasciicircum}₸\text{\textasciicircum}
\textbackslash₮\text{\textbackslash}₮Not supported₭\text{\textbackslash}₭₸\text{\textbackslash}₸\text{\textbackslash}
\textbar₮\text{\textbar}₮Not supported₭\text{\textbar}₭₸\text{\textbar}₸\text{\textbar}
\textbardbl₮\text{\textbardbl}₮Not supported₭\text{\textbardbl}₭₸\text{\textbardbl}₸\text{\textbardbl}
\textbf₮\textbf{AaBb123}₮\(\textbf{AaBb123}\)₭\textbf{AaBb123}₭₸\textbf{AaBb123}₸\textbf{AaBb123}
\textbraceleft₮\text{\textbraceleft}₮Not supported₭\text{\textbraceleft}₭₸\text{\textbraceleft}₸\text{\textbraceleft}
\textbraceright₮\text{\textbraceright}₮Not supported₭\text{\textbraceright}₭₸\text{\textbraceright}₸\text{\textbraceright}
\textcircledNot supportedNot supportedNot supported₸\text{\textcircled a}₸\text{\textcircled a}
\textcolor₮\textcolor{blue}{F=ma}₮\(\textcolor{blue}{F=ma}\)₭\textcolor{blue}{F=ma}₭₸\textcolor{blue}{F=ma}₸\textcolor{blue}{F=ma}
\textdagger₮\text{\textdagger}₮Not supported₭\text{\textdagger}₭₸\text{\textdagger}₸\text{\textdagger}
\textdaggerdbl₮\text{\textdaggerdbl}₮Not supported₭\text{\textdaggerdbl}₭₸\text{\textdaggerdbl}₸\text{\textdaggerdbl}
\textdegree₮\text{\textdegree}₮Not supported₭\text{\textdegree}₭₸\text{\textdegree}₸\text{\textdegree}
\textdollar₮\text{\textdollar}₮Not supported₭\text{\textdollar}₭₸\text{\textdollar}₸\text{\textdollar}
\textellipsis₮\text{\textellipsis}₮Not supported₭\text{\textellipsis}₭₸\text{\textellipsis}₸\text{\textellipsis}
\textemdash₮\text{\textemdash}₮Not supported₭\text{\textemdash}₭₸\text{\textemdash}₸\text{\textemdash}
\textendash₮\text{\textendash}₮Not supported₭\text{\textendash}₭₸\text{\textendash}₸\text{\textendash}
\textgreater₮\text{\textgreater}₮Not supported₭\text{\textgreater}₭₸\text{\textgreater}₸\text{\textgreater}
\textit₮\textit{AaBb}₮\(\textit{AaBb}\)₭\textit{AaBb}₭₸\textit{AaBb}₸\textit{AaBb}
\textless₮\text{\textless}₮Not supported₭\text{\textless}₭₸\text{\textless}₸\text{\textless}
\textnormal₮\textnormal{AB}₮Not supported₭\textnormal{AB}₭₸\textnormal{AB}₸\textnormal{AB}
\textquotedblleft₮\text{\textquotedblleft}₮Not supported₭\text{\textquotedblleft}₭₸\text{\textquotedblleft}₸\text{\textquotedblleft}
\textquotedblright₮\text{\textquotedblright}₮Not supported₭\text{\textquotedblright}₭₸\text{\textquotedblright}₸\text{\textquotedblright}
\textquoteleft₮\text{\textquoteleft}₮Not supported₭\text{\textquoteleft}₭₸\text{\textquoteleft}₸\text{\textquoteleft}
\textquoteright₮\text{\textquoteright}₮Not supported₭\text{\textquoteright}₭₸\text{\textquoteright}₸\text{\textquoteright}
\textregistered₮\text{\textregistered}₮Not supported₭\text{\textregistered}₭₸\text{\textregistered}₸\text{\textregistered}
\textrm₮\textrm{AaBb123}₮\(\textrm{AaBb123}\)₭\textrm{AaBb123}₭₸\textrm{AaBb123}₸\textrm{AaBb123}
\textscNot supportedNot supportedNot supportedNot supported
\textsf₮\textsf{AaBb123}₮\(\textsf{AaBb123}\)₭\textsf{AaBb123}₭₸\textsf{AaBb123}₸\textsf{AaBb123}
\textsterling₮\text{\textsterling}₮Not supported₭\text{\textsterling}₭₸\text{\textsterling}₸\text{\textsterling}
\textstyle₮\textstyle\sum_0^n₮\(\textstyle\sum_0^n\)₭\textstyle\sum_0^n₭₸\textstyle\sum_0^n₸\textstyle\sum_0^n
\texttip₮\texttip{\text{hover here}}{tip}₮Not supportedNot supportedNot supported\texttip{\text{hover here}}{tip}
\texttt₮\texttt{AaBb123}₮\(\texttt{AaBb123}\)₭\texttt{AaBb123}₭₸\texttt{AaBb123}₸\texttt{AaBb123}
\textunderscore₮\text{\textunderscore}₮Not supported₭\text{\textunderscore}₭Not supported\text{\textunderscore}
\textvisiblespaceNot supported\(a\textvisiblespace b\)Not supportedNot supported
\tfrac₮\displaystyle \tfrac a b₮\(\displaystyle \tfrac a b\)₭\displaystyle \tfrac a b₭₸\displaystyle \tfrac a b₸\displaystyle \tfrac a b
\tg₮\tg₮Not supported₭\tg₭Not supported
\th₮\th₮Not supported₭\th₭Not supported
\therefore₮\therefore₮\(\therefore\)₭\therefore₭₸\therefore₸
\Theta₮\Theta₮\(\Theta\)₭\Theta₭₸\Theta₸
\theta₮\theta₮\(\theta\)₭\theta₭₸\theta₸
\thetasym₮\thetasym₮\(\thetasym\)₭\thetasym₭₸\thetasym₸
\thickapprox₮\thickapprox₮\(\thickapprox\)₭\thickapprox₭₸\thickapprox₸
\thicksim₮\thicksim₮\(\thicksim\)₭\thicksim₭₸\thicksim₸
\thickspace₮a\thickspace b₮Not supported₭a\thickspace b₭₸a\thickspace b₸a\thickspace b
\thinspace₮a\thinspace b₮\(a\thinspace b\)₭a\thinspace b₭₸a\thinspace b₸a\thinspace b
\tilde₮\tilde M₮\(\tilde M\)₭\tilde M₭₸\tilde M₸\tilde M
\times₮\times₮\(\times\)₭\times₭₸\times₸
\Tiny₮{\Tiny A B}₮Not supportedNot supportedNot supportedNon standard
\tiny₮\tiny tiny₮\(\tiny tiny\)₭\tiny tiny₭Not supported\tiny tiny
\to₮\to₮\(\to\)₭\to₭₸\to₸
\toggle₮\toggle{\text{Click Here}}{Ouch}\endtoggle₮Not supportedNot supported₸\toggle{\text{Hey!}}{\text{Click Here}}₸
\top₮\top₮\(\top\)₭\top₭₸\top₸
\triangle₮\triangle₮\(\triangle\)₭\triangle₭₸\triangle₸
\triangledown₮\triangledown₮\(\triangledown\)₭\triangledown₭₸\triangledown₸
\triangleleft₮\triangleleft₮\(\triangleleft\)₭\triangleleft₭₸\triangleleft₸
\trianglelefteq₮\trianglelefteq₮\(\trianglelefteq\)₭\trianglelefteq₭₸\trianglelefteq₸
\triangleq₮\triangleq₮\(\triangleq\)₭\triangleq₭₸\triangleq₸
\triangleright₮\triangleright₮\(\triangleright\)₭\triangleright₭₸\triangleright₸
\trianglerighteq₮\trianglerighteq₮\(\trianglerighteq\)₭\trianglerighteq₭₸\trianglerighteq₸
\tt₮{\tt AaBb123}₮\({\tt AaBb123}\)₭{\tt AaBb123}₭Not supported{\tt AaBb123}
\twoheadleftarrow₮\twoheadleftarrow₮\(\twoheadleftarrow\)₭\twoheadleftarrow₭₸\twoheadleftarrow₸
\twoheadrightarrow₮\twoheadrightarrow₮\(\twoheadrightarrow\)₭\twoheadrightarrow₭₸\twoheadrightarrow₸
- -

U

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\u₮\text{\u{a}}₮Not supported₭\text{\u{a}}₭₸\text{\u{a}}₸\text{\u{a}}
\Uarr₮\Uarr₮\(\Uarr\)₭\Uarr₭Not supported
\uArr₮\uArr₮\(\uArr\)₭\uArr₭Not supported
\uarr₮\uarr₮\(\uarr\)₭\uarr₭Not supported
\ulcorner₮\ulcorner₮\(\ulcorner\)₭\ulcorner₭Not supported
\underbrace₮\underbrace{x+⋯+x}_{n\text{ times}}₮\(\underbrace{x+⋯+x}_{n\text{ times}}\)₭\underbrace{x+⋯+x}_{n\text{ times}}₭₸\underbrace{x+⋯+x}_{n\text{ times}}₸\underbrace{x+⋯+x}_{n\text{ times}}
\underbracketNot supportedNot supportedNot supportedNot supported
\undergroup₮\undergroup{AB}₮Not supported₭\undergroup{AB}₭Not supported\undergroup{AB}
\underleftarrow₮\underleftarrow{AB}₮\(\underleftarrow{AB}\)₭\underleftarrow{AB}₭Not supported\underleftarrow{AB}
\underleftrightarrow₮\underleftrightarrow{AB}₮\(\underleftrightarrow{AB}\)₭\underleftrightarrow{AB}₭Not supported\underleftrightarrow{AB}
\underrightarrow₮\underrightarrow{AB}₮\(\underrightarrow{AB}\)₭\underrightarrow{AB}₭Not supported\underrightarrow{AB}
\underline₮\underline{\text{a long argument}}₮\(\underline{\text{a long argument}}\)₭\underline{\text{a long argument}}₭₸\underline{\text{a long argument}}₸\underline{\text{a long argument}}
\underlinesegmentNot supportedNot supportedNot supportedNot supported
\underparen₮\underparen{abc}₮Not supportedNot supportedNot supported\underparen{abc}
\underrightarrow₮\underrightarrow{AB}₮\(\underrightarrow{AB}\)₭\underrightarrow{AB}₭Not supported\underrightarrow{AB}
\underset₮\underset{!}{=}₮\(\underset{!}{=}\)₭\underset{!}{=}₭₸\underset{!}{=}₸\underset{!}{=}
\unicodeNot supported
See \char
\(\unicode{x263a}\)Not supportedNot supported\unicode{x263a}
See \char for alternate.
\unlhd₮\unlhd₮\(\unlhd\)₭\unlhd₭₸\unlhd₸
\unrhd₮\unrhd₮\(\unrhd\)₭\unrhd₭₸\unrhd₸
\upalpha₮\upalpha₮Not supported₭\upalpha₭Not supported
\Uparrow₮\Uparrow₮\(\Uparrow\)₭\Uparrow₭₸\Uparrow₸
\uparrow₮\uparrow₮\(\uparrow\)₭\uparrow₭₸\uparrow₸
\upbeta₮\upbeta₮Not supported₭\upbeta₭Not supported
\upchi₮\upchi₮Not supported₭\upchi₭Not supported
\updelta₮\updelta₮Not supported₭\updelta₭Not supported
\Updownarrow₮\Updownarrow₮\(\Updownarrow\)₭\Updownarrow₭₸\Updownarrow₸
\updownarrow₮\updownarrow₮\(\updownarrow\)₭\updownarrow₭₸\updownarrow₸
\upeta₮\upeta₮Not supported₭\upeta₭Not supported
\upepsilon₮\upepsilon₮Not supported₭\upepsilon₭Not supported
\upgamma₮\upgamma₮Not supported₭\upgamma₭Not supported
\upharpoonleft₮\upharpoonleft₮\(\upharpoonleft\)₭\upharpoonleft₭₸\upharpoonleft₸
\upharpoonright₮\upharpoonright₮\(\upharpoonright\)₭\upharpoonright₭₸\upharpoonright₸
\upiota₮\upiota₮Not supported₭\upiota₭Not supported
\upkappa₮\upkappa₮Not supported₭\upkappa₭Not supported
\uplambda₮\uplambda₮Not supported₭\uplambda₭Not supported
\uplus₮\uplus₮\(\uplus\)₭\uplus₭₸\uplus₸
\upmu₮\upmu₮Not supported₭\upmu₭Not supported
\upnu₮\upnu₮Not supported₭\upnu₭Not supported
\upomega₮\upomega₮Not supported₭\upomega₭Not supported
\upomicron₮\upomicron₮Not supported₭\upomicron₭Not supported
\upphi₮\upphi₮Not supported₭\upphi₭Not supported
\uppi₮\uppi₮Not supported₭\uppi₭Not supported
\uppsi₮\uppsi₮Not supported₭\uppsi₭Not supported
\uprho₮\uprho₮Not supported₭\uprho₭Not supported
\uprootNot supported\(\sqrt[3\uproot2]{x}\)Not supportedNot supported\sqrt[3\uproot2]{x}
\upsigma₮\upsigma₮Not supported₭\upsigma₭Not supported
\Upsilon₮\Upsilon₮\(\Upsilon\)₭\Upsilon₭₸\Upsilon₸
\upsilon₮\upsilon₮\(\upsilon\)₭\upsilon₭₸\upsilon₸
\uptau₮\uptau₮Not supported₭\uptau₭Not supported
\uptheta₮\uptheta₮Not supported₭\uptheta₭Not supported
\upuparrows₮\upuparrows₮\(\upuparrows\)₭\upuparrows₭₸\upuparrows₸
\upupsilon₮\upupsilon₮Not supported₭\upupsilon₭Not supported
\upxi₮\upxi₮Not supported₭\upxi₭Not supported
\upzeta₮\upzeta₮Not supported₭\upzeta₭Not supported
\urcorner₮\urcorner₮\(\urcorner\)₭\urcorner₭Not supported
\url₮\url{https://temml.org/}₮Not supported₭\url{https://temml.org/}₭Not supported\url{https://temml.org/}
\utilde₮\utilde{AB}₮Not supported₭\utilde{AB}₭Not supported\utilde{AB}
- -

V

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\v₮\text{\v{a}}₮Not supported₭\text{\v{a}}₭₸\text{\v{a}}₸\text{\v{a}}
\varcoppa₮\varcoppa₮Not supportedNot supportedNot supported
\varDelta₮\varDelta₮\(\varDelta\)₭\varDelta₭Not supported
\varepsilon₮\varepsilon₮\(\varepsilon\)₭\varepsilon₭₸\varepsilon₸
\varGamma₮\varGamma₮\(\varGamma\)₭\varGamma₭Not supported
\varinjlim₮\varinjlim\limits_n x₮\(\varinjlim\limits_n x\)₭\varinjlim\limits_n x₭Not supported\varinjlim\limits_n x
\varkappa₮\varkappa₮\(\varkappa\)₭\varkappa₭₸\varkappa₸
\varLambda₮\varLambda₮\(\varLambda\)₭\varLambda₭Not supported
\varliminf₮\varliminf\limits_n x₮\(\varliminf\limits_n x\)₭\varliminf\limits_n x₭Not supported\varliminf\limits_n x
\varlimsup₮\varlimsup\limits_n x₮\(\varlimsup\limits_n x\)₭\varlimsup\limits_n x₭Not supported\varlimsup\limits_n x
\varnothing₮\varnothing₮\(\varnothing\)₭\varnothing₭₸\varnothing₸
\varOmega₮\varOmega₮\(\varOmega\)₭\varOmega₭Not supported
\varPhi₮\varPhi₮\(\varPhi\)₭\varPhi₭Not supported
\varphi₮\varphi₮\(\varphi\)₭\varphi₭₸\varphi₸
\varPi₮\varPi₮\(\varPi\)₭\varPi₭Not supported
\varpi₮\varpi₮\(\varpi\)₭\varpi₭₸\varpi₸
\varprojlim₮\varprojlim\limits_n x₮\(\varprojlim\limits_n x\)₭\varprojlim\limits_n x₭Not supported\varprojlim\limits_n x
\varpropto₮\varpropto₮\(\varpropto\)₭\varpropto₭₸\varpropto₸
\varPsi₮\varPsi₮\(\varPsi\)₭\varPsi₭Not supported
\varrho₮\varrho₮\(\varrho\)₭\varrho₭₸\varrho₸
\varSigma₮\varSigma₮\(\varSigma\)₭\varSigma₭Not supported
\varsigma₮\varsigma₮\(\varsigma\)₭\varsigma₭₸\varsigma₸
\varstigmaNot supported\(\varstigma\)Not supportedNot supported
\varsubsetneq₮\varsubsetneq₮\(\varsubsetneq\)₭\varsubsetneq₭₸\varsubsetneq₸
\varsubsetneqq₮\varsubsetneqq₮\(\varsubsetneqq\)₭\varsubsetneqq₭₸\varsubsetneqq₸
\varsupsetneq₮\varsupsetneq₮\(\varsupsetneq\)₭\varsupsetneq₭₸\varsupsetneq₸
\varsupsetneqq₮\varsupsetneqq₮\(\varsupsetneqq\)₭\varsupsetneqq₭₸\varsupsetneqq₸
\varTheta₮\varTheta₮\(\varTheta\)₭\varTheta₭Not supported
\vartheta₮\vartheta₮\(\vartheta\)₭\vartheta₭₸\vartheta₸
\vartriangle₮\vartriangle₮\(\vartriangle\)₭\vartriangle₭₸\vartriangle₸
\vartriangleleft₮\vartriangleleft₮\(\vartriangleleft\)₭\vartriangleleft₭₸\vartriangleleft₸
\vartriangleright₮\vartriangleright₮\(\vartriangleright\)₭\vartriangleright₭₸\vartriangleright₸
\varUpsilon₮\varUpsilon₮\(\varUpsilon\)₭\varUpsilon₭Not supported
\varXi₮\varXi₮\(\varXi\)₭\varXi₭Not supported
\vcentcolon₮\mathrel{\vcentcolon =}₮Not supported₭\mathrel{\vcentcolon =}₭Not supported\mathrel{\vcentcolon =}
\vcenterNot supportedNot supportedNot supportedNot supported
\Vdash₮\Vdash₮\(\Vdash\)₭\Vdash₭₸\Vdash₸
\vDash₮\vDash₮\(\vDash\)₭\vDash₭₸\vDash₸
\vdash₮\vdash₮\(\vdash\)₭\vdash₭₸\vdash₸
\vdots₮\vdots₮\(\vdots\)₭\vdots₭₸\vdots₸
\vec₮\vec{F}₮\(\vec{F}\)₭\vec{F}₭₸\vec{F}₸\vec{F}
\vee₮\vee₮\(\vee\)₭\vee₭₸\vee₸
\veebar₮\veebar₮\(\veebar\)₭\veebar₭₸\veebar₸
\verb₮\verb!\frac a b!₮\(\verb!\frac a b!\)₭\verb!\frac a b!₭Not supported\verb!\frac a b!
\Vert₮\Vert₮\(\Vert\)₭\Vert₭₸\Vert₸
\vert₮\vert₮\(\vert\)₭\vert₭₸\vert₸
\vfilNot supportedNot supportedNot supportedNot supported
\vfillNot supportedNot supportedNot supportedNot supported
\vlineNot supportedNot supportedNot supportedNot supported
{Vmatrix}₮\begin{Vmatrix}a&b\\c&d\end{Vmatrix}₮\(\begin{Vmatrix}a&b\\c&d\end{Vmatrix}\)₭\begin{Vmatrix}a&b\\c&d\end{Vmatrix}₭₸\begin{Vmatrix}a&b\\c&d\end{Vmatrix}₸\begin{Vmatrix}
   a & b \\
   c & d
\end{Vmatrix}
{vmatrix}₮\begin{vmatrix}a&b\\c&d\end{vmatrix}₮\(\begin{vmatrix}a&b\\c&d\end{vmatrix}\)₭\begin{vmatrix}a&b\\c&d\end{vmatrix}₭₸\begin{vmatrix}a&b\\c&d\end{vmatrix}₸\begin{vmatrix}
   a & b \\
   c & d
\end{vmatrix}
\vphantom₮\overline{\vphantom{M}a}₮\(\overline{\vphantom{M}a}\)₭\overline{\vphantom{M}a}₭Not supported\overline{\vphantom{M}a}
\Vvdash₮\Vvdash₮\(\Vvdash\)₭\Vvdash₭₸\Vvdash₸
- -

W

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\wedge₮\wedge₮\(\wedge\)₭\wedge₭₸\wedge₸
\weierp₮\weierp₮\(\weierp\)₭\weierp₭Not supported
\widecheck₮\widecheck{AB}₮Not supported₭\widecheck{AB}₭₸\widecheck{AB}₸\widecheck{AB}
\widehat₮\widehat{AB}₮\(\widehat{AB}\)₭\widehat{AB}₭₸\widehat{AB}₸\widehat{AB}
\wideparen₮\wideparen{AB}₮Not supportedNot supportedNot supported -
\widetilde₮\widetilde{AB}₮\(\widetilde{AB}\)₭\widetilde{AB}₭₸\widetilde{AB}₸\widetilde{AB}
\with₮\with₮Not supportedNot supportedNot supported -
\wn₮\wn₮Not supportedNot supportedNot supported
\wp₮\wp₮\(\wp\)₭\wp₭₸\wp₸
\wr₮\wr₮\(\wr\)₭\wr₭₸\wr₸
- -

X

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\xcancel₮\xcancel{ABC}₮\(\xcancel{ABC}\)₭\xcancel{ABC}₭Not supported\xcancel{ABC}
\Xi₮\Xi₮\(\Xi\)₭\Xi₭₸\Xi₸
\xi₮\xi₮\(\xi\)₭\xi₭₸\xi₸
\xhookleftarrow₮\xhookleftarrow{abc}₮Not supported₭\xhookleftarrow{abc}₭₸\xhookleftarrow{abc}₸\xhookleftarrow{abc}
\xhookrightarrow₮\xhookrightarrow{abc}₮Not supported₭\xhookrightarrow{abc}₭₸\xhookrightarrow{abc}₸\xhookrightarrow{abc}
\xLeftarrow₮\xLeftarrow{abc}₮Not supported₭\xLeftarrow{abc}₭₸\xLeftarrow{abc}₸\xLeftarrow{abc}
\xleftarrow₮\xleftarrow{abc}₮\(\xleftarrow{abc}\)₭\xleftarrow{abc}₭₸\xleftarrow{abc}₸\xleftarrow{abc}
\xleftharpoondown₮\xleftharpoondown{abc}₮Not supported₭\xleftharpoondown{abc}₭Not supported\xleftharpoondown{abc}
\xleftharpoonup₮\xleftharpoonup{abc}₮Not supported₭\xleftharpoonup{abc}₭Not supported\xleftharpoonup{abc}
\xLeftrightarrow₮\xLeftrightarrow{abc}₮Not supported₭\xLeftrightarrow{abc}₭₸\xLeftrightarrow{abc}₸\xLeftrightarrow{abc}
\xleftrightarrow₮\xleftrightarrow{abc}₮\(\xleftrightarrow{abc}\)₭\xleftrightarrow{abc}₭₸\xleftrightarrow{abc}₸\xleftrightarrow{abc}
\xleftrightharpoons₮\xleftrightharpoons{abc}₮Not supported₭\xleftrightharpoons{abc}₭₸\xleftrightharpoons{abc}₸\xleftrightharpoons{abc}
\xlongequal₮\xlongequal{abc}₮\(\xlongequal{abc}\)₭\xlongequal{abc}₭Not supported\xlongequal{abc}
\xmapsto₮\xmapsto{abc}₮\(\xmapsto{abc}\)₭\xmapsto{abc}₭₸\xmapsto{abc}₸\xmapsto{abc}
\xRightarrow₮\xRightarrow{abc}₮Not supported₭\xRightarrow{abc}₭₸\xRightarrow{abc}₸\xRightarrow{abc}
\xrightarrow₮\begin{matrix}A \xrightarrow{abc} B\\ A \xrightarrow[ghi]{abcdef} B \end{matrix}₮\(\begin{matrix}A \xrightarrow{abc} B\\ A \xrightarrow[ghi]{abcdef} B \end{matrix}\)₭\begin{matrix}A \xrightarrow{abc} B\\ A \xrightarrow[ghi]{abcdef} B \end{matrix}₭₸\begin{matrix}A \xrightarrow{abc} B\\ A \xrightarrow[ghi]{abcdef} B \end{matrix}₸A \xrightarrow{abc} B
A \xrightarrow[ghi]{abcdef} B
\xrightharpoondown₮\xrightharpoondown{abc}₮Not supported₭\xrightharpoondown{abc}₭Not supported\xrightharpoondown{abc}
\xrightharpoonup₮\xrightharpoonup{abc}₮Not supported₭\xrightharpoonup{abc}₭Not supported\xrightharpoonup{abc}
\xrightleftharpoons₮\xrightleftharpoons{abc}₮\(\xrightleftharpoons{abc}\)₭\xrightleftharpoons{abc}₭₸\xrightleftharpoons{abc}₸\xrightleftharpoons{abc}
\xtofrom₮\xtofrom{abc}₮\(\xtofrom{abc}\)₭\xtofrom{abc}₭Not supported\xtofrom{abc}
\xtwoheadleftarrow₮\xtwoheadleftarrow{abc}₮\(\xtwoheadleftarrow{abc}\)₭\xtwoheadleftarrow{abc}₭Not supported\xtwoheadleftarrow{abc}
\xtwoheadrightarrow₮\xtwoheadrightarrow{abc}₮\(\xtwoheadrightarrow{abc}\)₭\xtwoheadrightarrow{abc}₭Not supported\xtwoheadrightarrow{abc}
- -

YZ

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\yen₮\yen₮\(\yen\)₭\yen₭Not supported
\Z₮\Z₮\(\Z\)₭\Z₭Not supported
\Zeta₮\Zeta₮\(\Zeta\)₭\Zeta₭₸\Zeta₸
\zeta₮\zeta₮\(\zeta\)₭\zeta₭₸\zeta₸
- -
- -

Copyright © 2021, 2022 Ron Kok. Released under the MIT License

- -
- -
- - - - - - - - - \ No newline at end of file diff --git a/docs/support_table.md b/docs/support_table.md deleted file mode 100644 index 690b61b0..00000000 --- a/docs/support_table.md +++ /dev/null @@ -1,1570 +0,0 @@ - - - - - - Temml Support Table - - - - - - - -
- -# Support Table - -**Temml** is a JavaScript library that converts TeX math-mode functions to MathML. -This page provides an alphabetically sorted list of TeX functions that Temml -supports and some functions that it does not support. There is a similar page, -with functions [sorted by type](supported.html). - -To read this page, use a browser that supports MathML, such as Firefox or Safari. -Chrome and Edge will support MathML [soon](https://www.igalia.com/2021/08/09/MathML-Progress.html). - -Some functions are provided by an extension and are listed as such. They will -be available only in pages that include the extension. - -If you know the shape of a character, but not its name, -[Detexify](http://detexify.kirelabs.org/classify.html) can help. - - -## Symbols - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\!|$`n!`|`n!`|| -|\\\!|$`a\!b`|`a\!b`|| -|#|$`\def\bar#1{#1^2} \bar{y}`|`\def\bar#1{#1^2} \bar{y}`|| -|\\#|$`\#`||| -|%||`%this is a comment`|| -|\\%|$`\%`||| -|&|$`\begin{matrix} a & b\\ c & d \end{matrix}`|`\begin{matrix}`
   `a & b \\`
   `c & d`
`\end{matrix}`|| -|\\&|$`\&`||| -|'|$`'`||| -|\\\'|$`\text{\'{a}}`|`\text{\'{a}}`|| -|(|$`(`||| -|)|$`)`||| -|\\ |$`a\ b`|`a\ b`|| -|\\"|$`\text{\"{a}}`|`\text{\"{a}}`|| -|\\$ | $`\text{\textdollar}`||| -|\\,|$`a\,\,{b}`|`a\,\,{b}`|| -|\\.|$`\text{\.{a}}`|`\text{\.{a}}`|| -|\\:|$`a\:\:{b}`|`a\:\:{b}`|| -|\\;|$`a\;\;{b}`|a`\;\;{b}`|| -| \_ | $`x_i` | `x_i` || -|\\_|$`\_`||| -|\\\` | $``\text{\`{a}}`` | ``\text{\'{a}}`` || -|$`<`|$`<`||| -|\\=|$`\text{\={a}}`|`\text{\={a}}`|| -| >|$`>`||| -|\\>|$`a\>\>{b}`|`a\>\>{b}`|| -|\[|$`[`||| -|\]|$`]`||| -|{|$`{a}`|`{a}`|| -|}|$`{a}`|`{a}`|| -|\\{|$`\{`||| -|\\}|$`\}`||| -| \| |$`\vert`||| -| \\\| |$`\Vert`||| -|~|$`\text{no~no~no~breaks}`|`\text{no~no~no~breaks}`|| -|\\~|$`\text{\~{a}}`|`\text{\~{a}}`|| -|\\\\|$`\begin{matrix} a & b\\ c & d\end{matrix}`|`\begin{matrix}`
   `a & b \\`
   `c & d`
`\end{matrix}`|| -|^|$`x^i`|`x^i`|| -|\\^|$`\text{\^{a}}`|`\text{\^{a}}`|| - -## A - -
- -| Function | Rendered | Source or Comment| Package -|----------------|-------------|------------------|-----------| -|\AA|$`\text{\AA}`|`\text{\AA}`||| -|\aa|$`\text{\aa}`|`\text{\aa}`||| -|\above|$`{a \above{2pt} b+1}`|`{a \above{2pt} b+1}`|| -|\abovewithdelims|(Not supported)||| -|\abs|$`\abs{x}`|`\abs{x}`| physics extension | -|\absolutevalue|$`\absolutevalue{x}`|`\absolutevalue{x}`| physics extension | -|\acomm|$`\acomm{A}{B}`|`\acomm{A}{B}`| physics extension | -|\acute|$`\acute e`|`\acute e`|| -|\AE|$`\text{\AE}`|`\text{\AE}`|| -|\ae|$`\text{\ae}`|`\text{\ae}`|| -|\alef|$`\alef`|| texvc extension | -|\alefsym|$`\alefsym`|| texvc extension | -|\aleph|$`\aleph`||| -|{align}|$$\begin{align}a&=b+c\\d+e&=f\end{align}$$|`\begin{align}`
   `a&=b+c \\`
   `d+e&=f`
`\end{align}` | ams | -|{align\*}|$$\begin{align*}a&=b+c\\d+e&=f\end{align*}$$|`\begin{align*}`
   `a&=b+c \\`
   `d+e&=f`
`\end{align*}` | ams | -|{aligned}|$$\begin{aligned}a&=b+c\\d+e&=f\end{aligned}$$|`\begin{aligned}`
   `a&=b+c \\`
   `d+e&=f`
`\end{aligned}`| ams | -|{alignat}|$$\begin{alignat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat}$$|`\begin{alignat}{2}`
   `10&x+ &3&y = 2 \\`
   ` 3&x+&13&y = 4`
`\end{alignat}` | ams | -|{alignat\*}|$$\begin{alignat*}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat*}$$|`\begin{alignat*}{2}`
   `10&x+ &3&y = 2 \\`
   ` 3&x+&13&y = 4`
`\end{alignat*}` | ams | -|{alignedat}|$$\begin{alignedat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignedat}$$|`\begin{alignedat}{2}`
   `10&x+ &3&y = 2 \\`
   ` 3&x+&13&y = 4`
`\end{alignedat}` | ams | -|\allowbreak|||| -|\Alpha|$`\Alpha`||| -|\alpha|$`\alpha`||| -|\amalg|$`\amalg`||| -|\And|$`\And`||| -|\and|(Not supported)|[Deprecated](https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax)| texvc | -|\ang|(Not supported)|[Deprecated](https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax)| texvc | -|\angl|$`a_{\angl n}`|`a_{\angl n}` | actuarialangle | -|\angln|$`a_\angln`|`a_\angln` | actuarialangle | -|\angle|$`\angle`||| -|\anticommutator|$`\anticommutator{A}{B}`|`\anticommutator{A}{B}`| physics extension | -|\approx|$`\approx`||| -|\approxeq|$`\approxeq`||| -|\arccos|$`\arccos`||| -|\arcctg|$`\arcctg`||| -|\arceq|$`\arceq`|| stix | -|\arcsin|$`\arcsin`||| -|\arctan|$`\arctan`||| -|\arctg|$`\arctg`||| -|\arg|$`\arg`||| -|\argmax|$`\argmax`|| statmath | -|\argmin|$`\argmin`|| statmath | -|{array}|$`\begin{array}{cc}a&b\\c&d\end{array}` | `\begin{array}{cc}`
   `a & b \\`
   `c & d`
`\end{array}`| LaTeX2ε | -|\array|(Not supported)|See `{array}`|| -|\arraystretch|$`\def\arraystretch{1.5}\begin{array}{cc}a&b\\c&d\end{array}`|`\def\arraystretch{1.5}`
`\begin{array}{cc}`
   `a & b \\`
   `c & d`
`\end{array}`|| -|\Arrowvert|(Not supported)|see `\Vert`|| -|\arrowvert|(Not supported)|see `\vert`|| -|\ast|$`\ast`||| -|\asymp|$`\asymp`||| -|\atop|$`{a \atop b}`|`{a \atop b}`|| -|\atopwithdelims|(Not supported)||| - -## B - -| Function | Rendered | Source or Comment| Package -|----------------|-------------|------------------|-----------| -|\backcong|$`\backcong`|| MnSymbol | -|\backepsilon|$`\backepsilon`|| ams | -|\backprime|$`\backprime`|| ams | -|\backsim|$`\backsim`|| ams | -|\backsimeq|$`\backsimeq`|| ams | -|\backslash|$`\backslash`||| -|\bar|$`\bar{y}`|`\bar{y}`|| -|\barwedge|$`\barwedge`|| ams | -|\ballotx|$`\ballotx`|| arev | -|\Bbb|$`\Bbb{ABC}`|`\Bbb{ABC}`|| -|\Bbbk|$`\Bbbk`||| -|\bbox|(Not supported)||| -|\bcancel|$`\bcancel{5}`|`\bcancel{5}`| cancel | -|\because|$`\because`|| ams | -|\begin|$`\begin{matrix} a & b\\ c & d\end{matrix}`|`\begin{matrix}`
   `a & b \\`
   `c & d`
`\end{matrix}`| ams | -|\begingroup|$`\begingroup a\endgroup`|`\begingroup a\endgroup`|| -|\Beta|$`\Beta`||| -|\beta|$`\beta`||| -|\beth|$`\beth`|| ams | -|\between|$`\between`|| ams | -|\bf|$`{\bf AaBb12}`|`{\bf AaBb12}`|| -|\bfseries|(Not supported)||| -|\big|$`\big(\big)`|`\big(\big)`|| -|\Big|$`\Big(\Big)`|`\Big(\Big)`|| -|\bigcap|$`\bigcap`||| -|\bigcirc|$`\bigcirc`||| -|\bigcup|$`\bigcup`||| -|\bigg|$`\bigg(\bigg)`|`\bigg(\bigg)`|| -|\Bigg|$`\Bigg(\Bigg)`|`\Bigg(\Bigg)`|| -|\biggl|$`\biggl(`|`\biggl(`|| -|\Biggl|$`\Biggl(`|`\Biggl(`|| -|\biggm|$`\biggm\vert`|`\biggm\vert`|| -|\Biggm|$`\Biggm\vert`|`\Biggm\vert`|| -|\biggr|$`\biggr)`|`\biggr)`|| -|\Biggr|$`\Biggr)`|`\Biggr)`|| -|\bigl|$`\bigl(`|`\bigl(`|| -|\Bigl|$`\Bigl(`|`\Bigl(`|| -|\bigm|$`\bigm\vert`|`\bigm\vert`|| -|\Bigm|$`\Bigm\vert`|`\Bigm\vert`|| -|\bigodot|$`\bigodot`||| -|\bigominus|(Not supported)||| -|\bigoplus|$`\bigoplus`||| -|\bigoslash|(Not supported)||| -|\bigotimes|$`\bigotimes`||| -|\bigr|$`\bigr)`|`\bigr)`|| -|\Bigr|$`\Bigr)`|`\Bigr)`|| -|\bigsqcap|$`\bigsqcap`||| -|\bigsqcup|$`\bigsqcup`||| -|\bigstar|$`\bigstar`|| ams | -|\bigtriangledown|$`\bigtriangledown`||| -|\bigtriangleup|$`\bigtriangleup`||| -|\biguplus|$`\biguplus`||| -|\bigvee|$`\bigvee`||| -|\bigwedge|$`\bigwedge`||| -|\binom|$`\binom n k`|`\binom n k`| ams | -|\blacklozenge|$`\blacklozenge`|| ams | -|\blacksquare|$`\blacksquare`|| ams | -|\blacktriangle|$`\blacktriangle`|| ams | -|\blacktriangledown|$`\blacktriangledown`|| ams | -|\blacktriangleleft|$`\blacktriangleleft`|| ams | -|\blacktriangleright|$`\blacktriangleright`|| ams | -|\bm|$`\bm{AaBb}`|`\bm{AaBb}`| bm | -|{Bmatrix}|$`\begin{Bmatrix}a&b\\c&d\end{Bmatrix}`|`\begin{Bmatrix}`
   `a & b \\`
   `c & d`
`\end{Bmatrix}`| ams | -|{Bmatrix*}|$`\begin{Bmatrix*}[r] -1 & 3\\ 2 & -4 \end{Bmatrix*}`|`\begin{Bmatrix*}[r]`
   `-1 & 3 \\`
   `2 & -4`
`\end{Bmatrix*}`| mathtools | -|{bmatrix}|$`\begin{bmatrix}a&b\\c&d\end{bmatrix}`|`\begin{bmatrix}`
   `a & b \\`
   `c & d`
`\end{bmatrix}`| ams | -|{bmatrix*}|$`\begin{bmatrix*}[r] -1 & 3\\ 2 & -4 \end{bmatrix*}`|`\begin{bmatrix*}[r]`
   `-1 & 3 \\`
   `2 & -4`
`\end{bmatrix*}`| mathtools | -|\bmod|$`a \bmod b`|`a \bmod b`|| -|\bold|$`\bold{AaBb123}`|`\bold{AaBb123}`|| -|\boldsymbol|$`\boldsymbol{AaBb}`|`\boldsymbol{AaBb}`| ams | -|\bot|$`\bot`||| -|\Bot|$`\Bot`|| cmll | -|\bowtie|$`\bowtie`||| -|\Box|$`\Box`|| ams | -|\boxdot|$`\boxdot`|| ams | -|\boxed|$`\boxed{ab}`|`\boxed{ab}`| ams | -|\boxminus|$`\boxminus`|| ams | -|\boxplus|$`\boxplus`|| ams | -|\boxtimes|$`\boxtimes`|| ams | -|\Bqty|$`\Bqty{5 \text{mm}}`|`\Bqty{5 \text{mm}}`| physics extension | -|\bqty|$`\bqty{5 \text{mm}}`|`\bqty{5 \text{mm}}`| physics extension | -|\Bra|$`\left\langle\psi\right|`|`\Bra{\psi}`| braket | -|\bra|$`\mathinner{\langle{\psi}|}`|`\bra{\psi}`| braket | -|\braket|$`\mathinner{\langle{\phi | \psi}\rangle}`|`\braket{\phi\|\psi}`| braket | -|\Braket|$`\Braket{ \phi \| \frac{\partial^2}{\partial t^2} \| \psi }`|`\Braket{ϕ\|\frac{∂^2}{∂ t^2}\|ψ}`| braket -|\brace|$`{n\brace k}`|`{n\brace k}`|| -|\bracevert|(Not supported)||| -|\brack|$`{n\brack k}`|`{n\brack k}`|| -|\breve|$`\breve{eu}`|`\breve{eu}`|| -|\buildrel|(Not supported)||| -|\bull|$`\bull`|| texvc extension | -|\bullet|$`\bullet`||| -|\Bumpeq|$`\Bumpeq`|| ams | -|\bumpeq|$`\bumpeq`|| ams | - -## C - -| Function | Rendered | Source or Comment| Package -|----------------|-------------|------------------|-----------| -|\C|(Not supported)|[Deprecated](https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax)| texvc | -|\c|$`\text{\c{c}}`|`\text{\c{c}}`|| -|\cal|$`{\cal AaBb}`|`{\cal AaBb}`|| -|\cancel|$`\cancel{5}`|`\cancel{5}`| cancel | -|\cancelto|$`\cancelto{0}{x+1}`|`\cancelto{0}{x+1}`| cancel | -|\Cap|$`\Cap`|| ams | -|\cap|$`\cap`||| -|{cases}|$$\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}$$|`\begin{cases}`
   `a &\text{if } b \\`
   `c &\text{if } d`
`\end{cases}`| ams | -|\cases|(Not supported)|see `{cases}`|| -|{CD}|$$\begin{CD}A @>a>> B \\@VbVV @AAcA\\C @= D\end{CD}$$|`\begin{CD}`
   `A @>a>> B \\`
`@VbVV @AAcA \\`
   `C @= D`
`\end{CD}`| ams | -|\cdot|$`\cdot`||| -|\cdotp|$`\cdotp`||| -|\cdots|$`\cdots`||| -|\ce |$`{\mathrm{C}{\vphantom{X}}_{\smash[t]{6}}\mathrm{H}{\vphantom{X}}_{\smash[t]{5}}{-}\mathrm{CHO}}`|`\ce{C6H5-CHO}` | mhchem extension | -|\cee|(Not supported)|Deprecated
Use `\ce` instead. | mhchem | -|\centerdot|$`\centerdot`|| ams | -|\cf|(Not supported)|Deprecated
Use `\ce` instead.| mhchem | -|\cfrac|$`\cfrac{2}{1+\cfrac{2}{1}}`|`\cfrac{2}{1+\cfrac{2}{1}}`| ams | -|\check|$`\check{oe}`|`\check{oe}`|| -|\ch|$`\ch`||| -|\checkmark|$`\checkmark`|| ams | -|\Chi|$`\Chi`||| -|\chi|$`\chi`||| -|\choose|$`{n+1 \choose k+2}`|`{n+1 \choose k+2}`|| -|\circ|$`\circ`||| -|\circeq|$`\circeq`|| ams | -|\circlearrowleft|$`\circlearrowleft`|| ams | -|\circlearrowright|$`\circlearrowright`|| ams | -|\circledast|$`\circledast`|| ams | -|\circledcirc|$`\circledcirc`|| ams | -|\circleddash|$`\circleddash`|| ams | -|\circledR|$`\circledR`|| ams | -|\circledS|$`\circledS`|| ams | -|\class|(Not supported)||| -|\cline|(Not supported)||| -|\clubs|$`\clubs`|| texvc extension | -|\clubsuit|$`\clubsuit`||| -|\cnums|$`\cnums`|| texvc extension | -|\coh|$`\coh`|| cmll | -|\colon|$`\colon`||| -|\Colonapprox|$`\Colonapprox`|| mathtools | -|\colonapprox|$`\colonapprox`|| mathtools | -|\coloncolon|$`\coloncolon`|| colonequals | -|\coloncolonapprox|$`\coloncolonapprox`|| colonequals | -|\coloncolonequals|$`\coloncolonequals`|| colonequals | -|\coloncolonminus|$`\coloncolonminus`|| colonequals | -|\coloncolonsim|$`\coloncolonsim`|| colonequals | -|\colonminus|$`\colonminus`|| colonequals | -|\Coloneq|$`\Coloneq`|| mathtools | -|\coloneq|$`\coloneq`|| mathtools | -|\Coloneqq|$`\Coloneqq`|| mathtools | -|\coloneqq|$`\coloneqq`|| mathtools | -|\Colonsim|$`\Colonsim`|| mathtools | -|\colonsim|$`\colonsim`|| mathtools | -|\color|$`\color{#0000FF} AaBb123`|`\color{#0000FF} AaBb123`| color | -|\colorbox|$`\colorbox{red}{Black on red}`|`\colorbox{red}{Black on red}`| color | -|\comm|$`\comm{A}{B}`|`\comm{A}{B}`| physics extension | -|\commutator|$`\commutator{A}{B}`|`\commutator{A}{B}`| physics extension | -|\complement|$`\complement`|| ams | -|\Complex|$`\Complex`|| texvc extension | -|\cong|$`\cong`||| -|\Coppa|$`\Coppa`||| -|\coppa|$`\coppa`||| -|\coprod|$`\coprod`||| -|\copyright|$`\copyright`||| -|\cos|$`\cos`||| -|\cosec|$`\cosec`||| -|\cosh|$`\cosh`||| -|\cot|$`\cot`||| -|\cotg|$`\cotg`||| -|\coth|$`\coth`||| -|\cp|$`\cp`|| physics extension | -|\cr|$`\begin{matrix} a & b\cr c & d \end{matrix}`|`\begin{matrix}`
   `a & b \cr`
   `c & d`
`\end{matrix}`|| -|\cross|$`\cross`|| physics extension | -|\crossproduct|$`\crossproduct`|| physics extension | -|\csc|$`\csc`||| -|\cssId|(Not supported)|See `\id`.| -|\ctg|$`\ctg`||| -|\cth|$`\cth`||| -|\Cup|$`\Cup`|| ams | -|\cup|$`\cup`||| -|\curl|$`\curl`|| physics extension | -|\curlyeqprec|$`\curlyeqprec`|| ams | -|\curlyeqsucc|$`\curlyeqsucc`|| ams | -|\curlyvee|$`\curlyvee`|| ams | -|\curlywedge|$`\curlywedge`|| ams | -|\curvearrowleft|$`\curvearrowleft`|| ams | -|\curvearrowright|$`\curvearrowright`|| ams | - -## D - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\dag|$`\dag`||| -|\Dagger|$`\Dagger`|| texvc extension | -|\dagger|$`\dagger`||| -|\daleth|$`\daleth`|| ams | -|\Darr|$`\Darr`|| texvc extension | -|\dArr|$`\dArr`|| texvc extension | -|\darr|$`\darr`|| texvc extension | -|{darray}|$$\begin{darray}{cc}a&b\\c&d\end{darray}$$ | `\begin{darray}{cc}`
   `a & b \\`
   `c & d`
`\end{darray}`|| -|\dashleftarrow|$`\dashleftarrow`|| ams | -|\dashrightarrow|$`\dashrightarrow`|| ams | -|\dashv|$`\dashv`||| -|\dbinom|$`\dbinom n k`|`\dbinom n k`| ams | -|\dblcolon|$`\dblcolon`|| mathtools | -|{dcases}|$$\begin{dcases}a&\text{if }b\\c&\text{if }d\end{dcases}$$ | `\begin{dcases}`
   `a &\text{if } b \\`
   `c &\text{if } d`
`\end{dcases}`| mathtools | -|\dd|$`\dd`|`\dd`| physics extension | -|\ddag|$`\ddag`||| -|\ddagger|$`\ddagger`||| -|\ddddot|$`\ddddot x`|`\ddddot x`| ams | -|\dddot|$`\dddot x`|`\dddot x`| ams | -|\ddot|$`\ddot x`|`\ddot x`|| -|\ddots|$`\ddots`||| -|\DeclareMathOperator|(Not supported)||| -|\def|$`\def\foo{x^2} \foo + \foo`|`\def\foo{x^2} \foo + \foo`|| -|\definecolor|$`\definecolor{sortaGreen}{RGB}{128,128,0} \color{sortaGreen} F=ma`| `\definecolor{sortaGreen}{RGB}{128,128,0}`
`\color{sortaGreen} F=ma` | xcolor | -|\deg|$`\deg`||| -|\degree|$`\degree`||| -|\delta|$`\delta`||| -|\Delta|$`\Delta`||| -|\derivative|$`\derivative{x}{y}`|`\derivative{x}{y}`| physics extension | -|\det|$`\det`||| -|\dfrac|$`\dfrac{a-1}{b-1}`|`\dfrac{a-1}{b-1}`| ams | -|\differential|$`\differential`|`\differential`| physics extension | -|\diagdown|$`\diagdown`|| ams | -|\diagonalmatrix|(Not supported)|| physics | -|\diagup|$`\diagup`|| ams | -|\Diamond|$`\Diamond`||| -|\diamond|$`\diamond`||| -|\diamonds|$`\diamonds`|| texvc extension | -|\diamondsuit|$`\diamondsuit`||| -|\Digamma|(Not supported)||| -|\digamma|$`\digamma`|| ams | -|\dim|$`\dim`||| -|\displaylines|(Not supported)||| -|\displaystyle|$`\displaystyle\sum_0^n`|`\displaystyle\sum_0^n`|| -|\div|$`\div`||| -|\divergence|$`\divergence`|`\divergence`| physics extension | -|\divideontimes|$`\divideontimes`|| ams | -|\dot|$`\dot x`|`\dot x`|| -|\Doteq|$`\Doteq`|| ams | -|\doteq|$`\doteq`||| -|\doteqdot|$`\doteqdot`|| ams | -|\dotplus|$`\dotplus`|| ams | -|\dotproduct|$`\dotproduct`|`\dotproduct`| physics extension | -|\dots|$`x_1 + \dots + x_n` | `x_1 + \dots + x_n` || -|\dotsb|$`x_1 +\dotsb + x_n` | `x_1 +\dotsb + x_n` | ams | -|\dotsc|$`x,\dotsc,y`|`x,\dotsc,y`| ams | -|\dotsi|$$\int_{A_1}\int_{A_2}\dotsi$$|`\int_{A_1}\int_{A_2}\dotsi`| ams | -|\dotsm|$`x_1 x_2 \dotsm x_n`|`$x_1 x_2 \dotsm x_n`| ams | -|\dotso|$`\dotso`|| ams | -|\doublebarwedge|$`\doublebarwedge`|| ams | -|\doublecap|$`\doublecap`|| ams | -|\doublecup|$`\doublecup`|| ams | -|\Downarrow|$`\Downarrow`||| -|\downarrow|$`\downarrow`||| -|\downdownarrows|$`\downdownarrows`|| ams | -|\downharpoonleft|$`\downharpoonleft`|| ams | -|\downharpoonright|$`\downharpoonright`|| ams | -|{drcases}|$`\begin{drcases}a&\text{if }b\\c&\text{if }d\end{drcases}`|`\begin{drcases}`
   `a &\text{if } b \\`
   `c &\text{if } d`
`\end{drcases}`| mathtools | -|\dv|$`\dv{x}{y}`|`\dv{x}{y}`| physics extension | -|\dyad|$`\dyad{a}{b}`|`\dyad{a}{b}`| physics extension | - - -## E - -
- -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\edef|$`\def\foo{a}\edef\bar{\foo}\def\foo{}\bar`|`\def\foo{a}\edef\bar{\foo}\def\foo{}\bar`|| -|\ell|$`\ell`||| -|\else|(Not supported)||| -|\em|(Not supported)||| -|\emph|(Not supported)||| -|\empty|$`\empty`|| texvc extension | -|\emptyset|$`\emptyset`||| -|\enclose|(Not supported)|Non standard.
See `\boxed`, `\cancel`, `\bcancel`,
`\xcancel`, `\sout`, `\longdiv`, `\angl`|| -|\end|$`\begin{matrix} a & b\\ c & d\end{matrix}`|`\begin{matrix}`
   `a & b \\`
   `c & d`
`\end{matrix}`|| -|\endgroup|$`\begingroup a\endgroup`|`\begingroup a\endgroup`|| -|\enspace|$`a\enspace b`|`a\enspace b`|| -|\Epsilon|$`\Epsilon`||| -|\epsilon|$`\epsilon`||| -|\eqalign|(Not supported)|See {align*}|| -|\eqalignno|(Not supported)|See {align}|| -|\eqcirc|$`\eqcirc`|| ams | -|\Eqcolon|$`\Eqcolon`|| mathtools | -|\eqcolon|$`\eqcolon`|| mathtools | -|\equalscolon|$`\equalscolon`|| colonequals | -|\equalscoloncolon|$`\equalscoloncolon`|| colonequals | -|{equation}|$$\begin{equation}a = b + c\end{equation}$$|`\begin{equation}`
   `a = b + c`
`\end{equation}`| ams | -|{equation*}|$$\begin{equation*}a = b + c\end{equation*}$$|`\begin{equation*}`
   `a = b + c`
`\end{equation*}`| ams | -|{eqnarray}|(Not supported)||| -|\Eqqcolon|$`\Eqqcolon`|| mathtools | -|\eqqcolon|$`\eqqcolon`|| mathtools | -|\eqdef|$`\eqdef`|| stix | -|\eqref|$`\eqref{tag1}`|`\eqref{tag1}`
Some sites do not support `\eqref`.| ams | -|\eqsim|$`\eqsim`|| ams | -|\eqslantgtr|$`\eqslantgtr`|| ams | -|\eqslantless|$`\eqslantless`|| ams | -|\equiv|$`\equiv`||| -|\erf|$`\erf(x)`|`\erf(x)`| physics extension || -|\Eta|$`\Eta`||| -|\eta|$`\eta`||| -|\eth|$`\eth`|| ams | -|\euro|$`\euro`||| -|\ev|$`\ev{x}`|`\ev{x}`| physics extension | -|\eval|$`\eval{\tfrac 1 2 x}_0^n`|`\eval{\tfrac 1 2 x}_0^n`| physics extension | -|\evaluated|$`\evaluated{\tfrac 1 2 x}_0^n`|`\evaluated{\tfrac 1 2 x}_0^n`| physics extension | -|\exist|$`\exist`|| texvc extension | -|\exists|$`\exists`||| -|\exp|$`\exp`||| -|\expandafter|||| -|\expectationvalue|$`\expectationvalue{x}`|`\expectationvalue{x}`| physics extension | -|\expval|$`\expval{x}`|`\expval{x}`| physics extension | - -## F - -| Function | Rendered | Source or Comment | Package | -|-----------------------|--------------------------------|------------------------------|-------------------| -| \fallingdotseq | $`\fallingdotseq` | | ams | -| \fbox | $`\fbox{Hi there!}` | `\fbox{Hi there!}` | | -| \fcolorbox | $`\fcolorbox{red}{aqua}{A}` | `\fcolorbox{red}{aqua}{A}` | xcolor | -| \fdv | $`\fdv{x}{y}` | `\fdv{x}{y}` | physics extension | -| \female | $`\female` | | stix | -| \fi | (Not supported) | | | -| \Finv | $`\Finv` | | ams | -| \flat | $`\flat` | | | -| \footnotesize | $`\footnotesize footnotesize` | `\footnotesize footnotesize` | | -| \forall | $`\forall` | | | -| \frac | $`\frac a b` | `\frac a b` | ams | -| \frak | $`\frak{AaBb}` | `\frak{AaBb}` | | -| \frown | $`\frown` | | | -| \functionalderivative | $`\functionalderivative{x}{y}` | `\functionalderivative{x}{y}`| physics extension | -| \futurelet | | | | - -## G - -
- -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -| \Game | $`\Game`| | ams | -| \Gamma | $`\Gamma`| | | -| \gamma | $`\gamma`| | | -| {gather} | $$\begin{gather}a=b\\e=b+c\end{gather}$$| `\begin{gather}`
   `a=b \\ `
   `e=b+c`
`\end{gather}`| ams | -| {gather*} | $$\begin{gather*}a=b\\e=b+c\end{gather*}$$| `\begin{gather*}`
   `a=b \\ `
   `e=b+c`
`\end{gather*}`| ams | -| {gathered} | $`\begin{gathered}a=b\\e=b+c\end{gathered}`| `\begin{gathered}`
   `a=b \\ `
   `e=b+c`
`\end{gathered}`| ams | -| \gcd | $`\gcd`| | | -| \gdef | (Not supported)| | | -| \ge | $`\ge`| | | -| \geneuro | (Not supported) | See `\euro`| | -| \geneuronarrow | (Not supported) | See `\euro`| | -| \geneurowide | (Not supported) | See `\euro`| | -| \genfrac | $`\genfrac ( ] {2pt}{0}a{a+1}` | `\genfrac ( ] {2pt}{0}a{a+1}`| ams | -| \geq | $`\geq`| | | -| \geqq | $`\geqq`| | ams | -| \geqslant | $`\geqslant`| | ams | -| \gets | $`\gets`| | | -| \gg | $`\gg`| | | -| \ggg | $`\ggg`| | ams | -| \gggtr | $`\gggtr`| | ams | -| \gimel | $`\gimel`| | ams | -| \global | (Not supported)| | | -| \gnapprox | $`\gnapprox`| | ams | -| \gneq | $`\gneq`| | ams | -| \gneqq | $`\gneqq`| | ams | -| \gnsim | $`\gnsim`| | ams | -| \grad | $`\grad`| | physics extension | -| \gradient | $`\gradient`| | physics extension | -| \grave | $`\grave{eu}`| `\grave{eu}`| | -| \gt | $`a \gt b`| `a \gt b`| MathJax | -| \gtrapprox | $`\gtrapprox`| | ams | -| \gtrdot | $`\gtrdot`| | ams | -| \gtreqless | $`\gtreqless`| | ams | -| \gtreqqless | $`\gtreqqless`| | ams | -| \gtrless | $`\gtrless`| | ams | -| \gtrsim | $`\gtrsim`| | ams | -| \gvertneqq | $`\gvertneqq`| | ams | - -## H - -| Function | Rendered | Source or Comment | Package | -|-----------------|---------------------------|-------------------|-----------| -| \H | $`\text{\H{a}}` | `\text{\H{a}}`| | -| \Harr | $`\Harr` | | texvc extension | -| \hArr | $`\hArr` | | texvc extension | -| \harr | $`\harr` | | texvc extension | -| \hat | $`\hat{\theta}` | `\hat{\theta}`| | -| \hbar | $`\hbar` | | | -| \hbox | $`\hbox{$x^2$}` | `\hbox{$x^2$}`| | -| \hbox to | (Not supported) | | | -| \hdashline | $`\begin{matrix}a&b\\ \hdashline c &d\end{matrix}`| `\begin{matrix}`
   `a & b \\`
   `\hdashline`
   `c & d`
`\end{matrix}`| arydshln | -| \hearts | $`\hearts` | | texvc extension | -| \heartsuit | $`\heartsuit` | | | -| \hfil | (Not supported) | | | -| \hfill | (Not supported) | | | -| \hline | $`\begin{matrix}a&b\\ \hline c &d\end{matrix}`| `\begin{matrix}`
   `a & b \\ \hline`
   `c & d`
`\end{matrix}`| | -| \hom | $`\hom` | | | -| \hookleftarrow | $`\hookleftarrow` | | | -| \hookrightarrow | $`\hookrightarrow` | | | -| \hphantom | $`a\hphantom{bc}d` | `a\hphantom{bc}d`| | -| \href | $`\href{https://temml.org/}{\Temml}`| `\href{https://temml.org/}{\Temml}`
Requires `trust` [option](options.md)| href | -| \hskip | $`w\hskip1em i\hskip2em d` | `w\hskip1em i\hskip2em d`| | -| \hslash | $`\hslash` | | ams | -| \hspace | $`s\hspace{7ex} k` | `s\hspace{7ex} k`| | -| \class | $`\class{foo}{x}` | `\class{foo}{x}`
Must enable `trust` and disable `strict` [option](options.md)| | -| \data | $`\data{foo=a, bar=b}{x}` | `\data{foo=a, bar=b}{x}`
Must enable `trust` and disable `strict` [option](options.md)| | -| \id | $`\id{bar}{x}`| `\id{bar}{x}`
Must enable `trust` and disable `strict` [option](options.md)| | -| \style | $`\style{color: red;}{x}`| `\style{color: red;}{x}`
Must enable `trust` and disable `strict` [option](options.md)| | -| \huge | $`\huge huge` | `\huge huge`| | -| \Huge | $`\Huge Huge` | `\Huge Huge`| | - -## I - -| Function | Rendered | Source or Comment | Package | -|------------------|------------------------|-----------------------|-------------------| -| \i | $`\text{\i}` | `\text{\i}` | | -| \idotsint | $`\int\idotsint\int` | `\int\idotsint\int` | ams | -| \iddots | $`\iddots` | | | -| \if | (Not supported) | | | -| \iff | $`A\iff B` | `A\iff B` | | -| \ifmode | (Not supported) | | | -| \ifx | (Not supported) | | | -| \iiiint | $`\iiiint` | | ams | -| \iiint | $`\iiint` | | ams | -| \iint | $`\iint` | | ams | -| \Im | $`\Im` | | | -| \image | $`\image` | | texvc extension | -| \imageof | $`\imageof` | | stix | -| \imath | $`\imath` | | | -| \impliedby | $`P\impliedby Q` | `P\impliedby Q` | ams | -| \implies | $`P\implies Q` | `P\implies Q` | ams | -| \in | $`\in` | | | -| \includegraphics | $`\includegraphics[height=1em, totalheight=1.2em, width=1.2em, alt=sphere]{../sphere.jpg}` | `\includegraphics[height=1em,`
`totalheight=1.2em, width=1.2em,`
`alt=sphere]{../sphere.jpg}` | graphicx | -|\incoh | $`\incoh` | | cmll | -| \inf | $`\inf` | | | -| \infin | $`\infin` | | texvc extension | -| \infty | $`\infty` | | | -| \injlim | $`\injlim` | `\injlim` | ams | -| \innerproduct | $`\innerproduct{a}{b}` | `\innerproduct{a}{b}` | physics extension | -| \int | $`\int` | | | -| \intbar | $`\intbar` | | | -| \intBar | $`\intBar` | | | -| \intcap | $`\intcap` | | | -| \intclockwise | $`\intclockwise` | | | -| \intcup | $`\intcup` | | | -| \intercal | $`\intercal` | | ams | -| \intlarhk | $`\intlarhk` | | | -| \intop | $`\intop` | | | -| \intx | $`\intx` | | | -| \invamp | $`\invamp` | | cmll | -| \Iota | $`\Iota` | | | -| \iota | $`\iota` | | | -| \isin | $`\isin` | | texvc extension | -| \it | $`{\it AaBb}` | `{\it AaBb}` | | -| \itshape | (Not supported) | | | - -## JK - -| Function | Rendered | Source or Comment | Package | -|----------|---------------------------------|-------------------|-------------------| -| \j | $`\text{\j}` | `\text{\j}` | | -| \jmath | $`\jmath` | | | -| \Join | $`\Join` | | ams | -| \Kappa | $`\Kappa` | | | -| \kappa | $`\kappa` | | | -| \ker | $`\ker` | | | -| \kern | $`I\kern-2.5pt R` | `I\kern-2.5pt R` | | -| \Ket | $`\left| \psi\right\rangle` | `\Ket{\psi}` | braket | -| \ket | $`\mathinner{| {\psi}\rangle}` | `\ket{\psi}` | braket | -| \ketbra | $`\ketbra{a}{b}` | `\ketbra{a}{b}` | physics extension | -| \Koppa | $`\Koppa` | | | -| \koppa | $`\koppa` | | | - -## L - -| Function | Rendered | Source or Comment | Package | -|----------------------|----------------------------|-------------------|-----------| -| \L | (Not supported) | | | -| \l | (Not supported) | | | -| \Lambda | $`\Lambda` | | | -| \lambda | $`\lambda` | | | -| \label | | `\label{idName}`
Creates an HTML id.
Characters limited to: `A-Za-z0-9_-`| | -| \land | $`\land` | | | -| \lang | $`\lang A\rangle` | `\lang A\rangle` | texvc extension | -| \langle | $`\langle A\rangle` | `\langle A\rangle` | | -| \laplacian | $`\laplacian` | | physics extension | -| \Larr | $`\Larr` | | texvc extension | -| \lArr | $`\lArr` | | texvc extension | -| \larr | $`\larr` | | texvc extension | -| \large | $`\large large` | `\large large`| | -| \Large | $`\Large Large` | `\Large Large`| | -| \LARGE | $`\LARGE LARGE` | `\LARGE LARGE`| | -| \LaTeX | $`\LaTeX` | | | -| \lBrace | $`\lBrace` | | stix | -| \lbrace | $`\lbrace` | | | -| \lbrack | $`\lbrack` | | | -| \lceil | $`\lceil` | | | -| \ldotp | $`\ldotp` | | | -| \ldots | $`\ldots` | | | -| \le | $`\le` | | | -| \leadsto | $`\leadsto` | | ams | -| \left | $`\left\lbrace \dfrac ab \right.` | `\left\lbrace \dfrac ab \right.`| | -| \leftarrow | $`\leftarrow` | | | -| \Leftarrow | $`\Leftarrow` | | | -| \LeftArrow | (Not supported) | Non standard | | -| \leftarrowtail | $`\leftarrowtail` | | ams | -| \leftharpoondown | $`\leftharpoondown` | | | -| \leftharpoonup | $`\leftharpoonup` | | | -| \leftleftarrows | $`\leftleftarrows` | | ams | -| \Leftrightarrow | $`\Leftrightarrow` | | | -| \leftrightarrow | $`\leftrightarrow` | | | -| \leftrightarrows | $`\leftrightarrows` | | ams | -| \leftrightharpoons | $`\leftrightharpoons` | | ams | -| \leftrightsquigarrow | $`\leftrightsquigarrow` | | ams | -| \leftroot | (Not supported) | | | -| \leftthreetimes | $`\leftthreetimes` | | ams | -| \leq | $`\leq` | | | -| \leqalignno | (Not supported) | | | -| \leqq | $`\leqq` | | ams | -| \leqslant | $`\leqslant` | | ams | -| \lessapprox | $`\lessapprox` | | ams | -| \lessdot | $`\lessdot` | | ams | -| \lesseqgtr | $`\lesseqgtr` | | ams | -| \lesseqqgtr | $`\lesseqqgtr` | | ams | -| \lessgtr | $`\lessgtr` | | ams | -| \lesssim | $`\lesssim` | | ams | -| \let | | | | -| \lfloor | $`\lfloor` | | | -| \lg | $`\lg` | | | -| \lgroup | $`\lgroup` | | | -| \lhd | $`\lhd` | | ams | -| \lightning | $`\lightning` | | -| \lim | $`\lim` | | -| \liminf | $`\liminf` | | | -| \limits | $`\lim\limits_x` | `\lim\limits_x`| | -| \limsup | $`\limsup` | | | -| \ll | $`\ll` | | | -| \llap | $`{=}\llap{/\,}` | `{=}\llap{/\,}`| | -| \llbracket | $`\llbracket` | | stmaryrd | -| \llcorner | $`\llcorner` | | ams | -| \Lleftarrow | $`\Lleftarrow` | | ams | -| \lll | $`\lll` | | ams | -| \llless | $`\llless` | | ams | -| \lmoustache | $`\lmoustache` | | | -| \ln | $`\ln` | | | -| \lnapprox | $`\lnapprox` | | ams | -| \lneq | $`\lneq` | | ams | -| \lneqq | $`\lneqq` | | ams | -| \lnot | $`\lnot` | | | -| \lnsim | $`\lnsim` | | ams | -| \log | $`\log` | | | -| \long | | | | -| \longdiv | $`\longdiv{3x^2 + 2x + 5}` | `\longdiv{3x^2 + 2x + 5}` | Temml | -| \Longleftarrow | $`\Longleftarrow` | | | -| \longleftarrow | $`\longleftarrow` | | | -| \Longleftrightarrow | $`\Longleftrightarrow` | | | -| \longleftrightarrow | $`\longleftrightarrow` | | | -| \longmapsto | $`\longmapsto` | | | -| \Longrightarrow | $`\Longrightarrow` | | | -| \longrightarrow | $`\longrightarrow` | | | -| \looparrowleft | $`\looparrowleft` | | ams | -| \looparrowright | $`\looparrowright` | | ams | -| \lor | $`\lor` | | | -| \lower | $`M\lower5pt{M^2}M` | `M\lower5pt{M^2}M`  or
`M\lower5pt\hbox{$`M^2`}M`| | -| \lozenge | $`\lozenge` | | ams | -| \lparen | $`\lparen` | | mathtools | -| \Lrarr | $`\Lrarr` | | texvc extension | -| \lrArr | $`\lrArr` | | texvc extension | -| \lrarr | $`\lrarr` | | texvc extension | -| \lrcorner | $`\lrcorner` | | ams | -| \lq | $`\lq` | | | -| \Lsh | $`\Lsh` | | ams | -| \lt | $`\lt` | | MathJax | -| \ltimes | $`\ltimes` | | ams | -| \lVert | $`\lVert` | | ams | -| \lvert | $`\lvert` | | ams | -| \lvertneqq | $`\lvertneqq` | | ams | - -## M - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\male|$`\male`|| stix | -|\maltese|$`\maltese`|| ams | -|\mapsto|$`\mapsto`||| -|\mathbb|$`\mathbb{AB}`|`\mathbb{AB}`| ams | -|\mathbf|$`\mathbf{AaBb123}`|`\mathbf{AaBb123}`|| -|\mathbin|$`a\mathbin{!}b`|`a\mathbin{!}b`|| -|\mathcal|$`\mathcal{AaBb}`|`\mathcal{AaBb}`|| -|\mathchoice|$`a\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b`|`a\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b`|| -|\mathclap|$`\displaystyle\sum_{\mathclap{1\le i\le n}} x_{i}`|`\sum_{\mathclap{1\le i\le n}} x_{i}`| mathtools | -|\mathclose|$`a + (b\mathclose\gt + c`|`a + (b\mathclose\gt + c`|| -|\mathellipsis|$`\mathellipsis`||| -|\mathfrak|$`\mathfrak{AaBb}`|`\mathfrak{AaBb}`| ams | -|\mathinner|$`ab\mathinner{\text{inside}}cd`|`ab\mathinner{\text{inside}}cd`|| -|\mathit|$`\mathit{AaBb}`|`\mathit{AaBb}`|| -|\mathllap|$`{=}\mathllap{/\,}`|`{=}\mathllap{/\,}`| mathtools | -|\mathnormal|$`\mathnormal{AaBb}`|`\mathnormal{AaBb}`|| -|\mathop|$`\mathop{\star}_a^b`|`\mathop{\star}_a^b`|| -|\mathopen|$`a + \mathopen\lt b) + c`|`a + \mathopen\lt b) + c`|| -|\mathord|$`1\mathord{,}234{,}567`|`1\mathord{,}234{,}567`|| -|\mathpunct|$`A\mathpunct{-}B`|`A\mathpunct{-}B`|| -|\mathrel|$`a \mathrel{\#} b`|`a \mathrel{\#} b`|| -|\mathrlap|$`\mathrlap{\,/}{=}`|`\mathrlap{\,/}{=}`| mathtools | -|\mathring|$`\mathring{a}`|`\mathring{a}`| ams | -|\mathrm|$`\mathrm{AaBb12}`|`\mathrm{AaBb12}`|| -|\mathscr|$`\mathscr{AB}`|`\mathscr{AB}`|| -|\mathsf|$`\mathsf{AaBb123}`|`\mathsf{AaBb123}`|| -|\mathsterling|$`\mathsterling`||| -|\mathstrut|$`\sqrt{\mathstrut a}`|`\sqrt{\mathstrut a}`|| -|\mathtip|(Not supported)|See `\texttip`|| -|\mathtt|$`\mathtt{AaBb123}`|`\mathtt{AaBb123}`|| -|\matrix|(Not supported)|See `{matrix}`|| -|{matrix}|$`\begin{matrix}a&b\\c&d\end{matrix}`|`\begin{matrix}`
   `a & b \\`
   `c & d`
`\end{matrix}`| ams | -|{matrix*}|$`\begin{matrix*}[r] -1 & 3\\ 2 & -4 \end{matrix*}`|`\begin{matrix*}[r]`
   `-1 & 3 \\`
   `2 & -4`
`\end{matrix*}`| mathtools | -|\matrixel|$`\matrixel{n}{A}{m}`|`\matrixel{n}{A}{m}`| physics extension | -|\matrixelement|$`\matrixelement{n}{A}{m}`|`\matrixelement{n}{A}{m}`| physics extension | -|\mel|$`\mel{n}{A}{m}`|`\mel{n}{A}{m}`| physics extension | -|\max|$`\max`||| -|\mbox|(Not supported)||| -|\md|(Not supported)||| -|\mdseries|(Not supported)||| -|\measeq|$`\measeq`|| stix | -|\measuredangle|$`\measuredangle`|| ams | -|\medspace|$`a\medspace b`|`a\medspace b`| ams | -|\mho|$`\mho`||| -|\mid|$`\{x∈ℝ\mid x>0\}`|`\{x∈ℝ\mid x>0\}`|| -|\middle|$`P\left(A\middle\vert B\right)`|`P\left(A\middle\vert B\right)`|| -|\min|$`\min`||| -|\minuscolon|$`\minuscolon`|| colonequals | -|\minuscoloncolon|$`\minuscoloncolon`|| colonequals | -|\minuso|(Not supported)| See `\standardstate`|| -|\mit|(Not supported)|See `\mathit`|| -|\mkern|$`a\mkern18mu b`|`a\mkern18mu b`|| -|\mmlToken|(Not supported)||| -|\mod|$`3\equiv 5 \mod 2`|`3\equiv 5 \mod 2`| ams | -|\models|$`\models`||| -|\moveleft|(Not supported)||| -|\moveright|(Not supported)||| -|\mp|$`\mp`||| -|\mskip|$`a\mskip{10mu}b`|`a\mskip{10mu}b`|| -|\mspace|(Not supported)||| -|\Mu|$`\Mu`||| -|\mu|$`\mu`||| -|\multicolumn|(Not supported)||| -|\multimap|$`\multimap`|| ams | -|\multimapboth|$`\multimapboth`|| cmll | -|\multimapinv|$`\multimapinv`|| cmll | -|{multline}|$$\begin{multline}\rm uno \\ \rm dos \\ \rm tres\end{multline}$$|`\begin{multline}`
  `\rm uno \\`
  `\rm dos \\`
  `\rm tres`
`\end{multline}`| ams | -|{multline*}|$$\begin{multline*}\rm uno \\ \rm dos \\ \rm tres\end{multline*}$$|`\begin{multline*}`
  `\rm uno \\`
  `\rm dos \\`
  `\rm tres`
`\end{multline*}`| ams | - -## N - -
- -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\N|$`\N`|| texvc extension | -|\nabla|$`\nabla`||| -|\natnums|$`\natnums`|| texvc extension | -|\natural|$`\natural`||| -|\negmedspace|$`a\negmedspace b`|`a\negmedspace b`| ams | -|\ncong|$`\ncong`|| ams | -|\ne|$`\ne`||| -|\nearrow|$`\nearrow`||| -|\neg|$`\neg`||| -|\negthickspace|$`a\negthickspace b`|`a\negthickspace b`| ams | -|\negthinspace|$`a\negthinspace b`|`a\negthinspace b`| ams | -|\neq|$`\neq`||| -|\newcommand|$`\newcommand\chk{\checkmark} \chk`|`\newcommand\chk{\checkmark} \chk`| newcommand | -|\newenvironment|(Not supported)||| -|\newextarrow|(Not supported)|| extpfeil | -|\newline|$`a\newline b`|`a\newline b`|| -|\nexists|$`\nexists`|| ams | -|\ngeq|$`\ngeq`|| ams | -|\ngeqq|$`\ngeqq`|| ams | -|\ngeqslant|$`\ngeqslant`|| ams | -|\ngtr|$`\ngtr`|| ams | -|\ni|$`\ni`||| -|\nleftarrow|$`\nleftarrow`|| ams | -|\nLeftarrow|$`\nLeftarrow`|| ams | -|\nLeftrightarrow|$`\nLeftrightarrow`|| ams | -|\nleftrightarrow|$`\nleftrightarrow`|| ams | -|\nleq|$`\nleq`|| ams | -|\nleqq|$`\nleqq`|| ams | -|\nleqslant|$`\nleqslant`|| ams | -|\nless|$`\nless`|| ams | -|\nmid|$`\nmid`|| ams | -|\nobreak|||| -|\nobreakspace|$`a\nobreakspace b`|`a\nobreakspace b`| ams | -|\noexpand|||| -|\nolimits|$`\lim\nolimits_x`|`\lim\nolimits_x`|| -|\norm|$`\norm{x}`|\norm{x}| physics extension | -|\normalfont|(Not supported)||| -|\normalsize|$`\normalsize normalsize`|`\normalsize normalsize`|| -|\not|$`\not =`|`\not =`|| -|\notag|$$\begin{align} a&=b \\ \notag d+e&=f \end{align}$$|`\begin{align}`
  `a&=b \\`
  `\notag d+e&=f`
`\end{align}`| ams | -|\notin|$`\notin`||| -|\notni|$`\notni`|| txfonts/pxfonts | -|\nparallel|$`\nparallel`|| ams | -|\nprec|$`\nprec`|| ams | -|\npreceq|$`\npreceq`|| ams | -|\nRightarrow|$`\nRightarrow`|| ams | -|\nrightarrow|$`\nrightarrow`|| ams | -|\nshortmid|$`\nshortmid`|| ams | -|\nshortparallel|$`\nshortparallel`|| ams | -|\nsim|$`\nsim`|| ams | -|\nsubset|$`\nsubset`|| mathabx | -|\nsubseteq|$`\nsubseteq`|| ams | -|\nsubseteqq|$`\nsubseteqq`|| ams | -|\nsucc|$`\nsucc`|| ams | -|\nsucceq|$`\nsucceq`|| ams | -|\nsupset|$`\nsupset`|| mathabx | -|\nsupseteq|$`\nsupseteq`|| ams | -|\nsupseteqq|$`\nsupseteqq`|| ams | -|\ntriangleleft|$`\ntriangleleft`|| ams | -|\ntrianglelefteq|$`\ntrianglelefteq`|| ams | -|\ntriangleright|$`\ntriangleright`|| ams | -|\ntrianglerighteq|$`\ntrianglerighteq`|| ams | -|\Nu|$`\Nu`||| -|\nu|$`\nu`||| -|\nVDash|$`\nVDash`|| ams | -|\nVdash|$`\nVdash`|| ams | -|\nvDash|$`\nvDash`|| ams | -|\nvdash|$`\nvdash`|| ams | -|\nwarrow|$`\nwarrow`||| - -## O - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\O|$`\text{\O}`|`\text{\O}`|| -|\o|$`\text{\o}`|`\text{\o}`|| -|\oc|$`\oc`|| cmll | -|\odot|$`\odot`||| -|\odv|$`\odv{f}{x}`|`\odv{f}{x}`| derivative | -|\odv*|$`\odv*{f}{x}`|`\odv*{f}{x}`| derivative | -|\OE|$`\text{\OE}`|`\text{\OE}`|| -|\oe|$`\text{\oe}`|`\text{\oe}`|| -|\officialeuro|(Not supported)|See `\euro`|| -|\oiiint|$`\oiiint`||| -|\oiint|$`\oiint`||| -|\oint|$`\oint`||| -|\oldstyle|(Not supported)| See `\oldstylenums`|| -|\oldstylenums|$`\oldstylenums{123}`|`\oldstylenums{123}`| LaTeX2ε | -|\omega|$`\omega`||| -|\Omega|$`\Omega`||| -|\Omicron|$`\Omicron`||| -|\omicron|$`\omicron`||| -|\ominus|$`\ominus`||| -|\op|$`\op{a}{b}`|`\op{a}{b}`| physics extension | -|\operatorname|$`\operatorname{asin} x`|\operatorname{asin} x| ams | -|\operatorname\*|$`\operatorname*{asin}\limits_y x`|`\operatorname*{asin}\limits_y x`| ams | -|\operatornamewithlimits|$`\operatornamewithlimits{asin}\limits_y x`|`\operatornamewithlimits{asin}\limits_y x`| | -|\oplus|$`\oplus`||| -|\or|(Not supported)||| -|\order|$`\order{x^2}`|`\order{x^2}`| physics extension | -|\origof|$`\origof`|| stix | -|\oslash|$`\oslash`||| -|\otimes|$`\otimes`||| -|\outerproduct|$`\outerproduct{a}{b}`|`\outerproduct{a}{b}`| physics extension | -|\over|$`{a+1 \over b+2}+c`|`{a+1 \over b+2}+c`|| -|\overbrace|$`\overbrace{x+⋯+x}^{n\text{ times}}`|`\overbrace{x+⋯+x}^{n\text{ times}}`|| -|\overbracket|(Not supported)||| -|\overgroup|$`\overgroup{AB}`|`\overgroup{AB}`| MnSymbol | -|\overleftarrow|$`\overleftarrow{AB}`|`\overleftarrow{AB}`| ams | -|\overleftharpoon|$`\overleftharpoon{AB}`|`\overleftharpoon{AB}`| MnSymbol | -|\overleftrightarrow|$`\overleftrightarrow{AB}`|`\overleftrightarrow{AB}`| ams | -|\overline|$`\overline{\text{a long argument}}`|`\overline{\text{a long argument}}`|| -|\overlinesegment|(Not supported)||| -|\overparen|$`\overparen{abc}`|`\overparen{abc}`|| -|\Overrightarrow|$`\Overrightarrow{AB}`|`\Overrightarrow{AB}`| overrightarrow | -|\overrightarrow|$`\overrightarrow{AB}`|`\overrightarrow{AB}`| ams | -|\overrightharpoon|$`\overrightharpoon{ac}`|`\overrightharpoon{ac}`|| -|\overset|$`\overset{!}{=}`|`\overset{!}{=}`| ams | -|\overwithdelims|(Not supported)||| -|\owns|$`\owns`||| - -## P - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\P|$`\text{\P}`|`\text{\P}` or `\P`|| -|\pagecolor|(Not supported)|[Deprecated](https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax)| texvc | -|\parallel|$`\parallel`||| -|\parr|$`\parr`|| cmll | -|\part|(Not supported)|[Deprecated](https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax)| texvc | -|\partial|$`\partial`||| -|\partialderivative|$`\partialderivative{x}{y}`|`\partialderivative{x}{y}`| physics extension | -|\pb|$`\pb{x}{y}`|`\pb{x}{y}`| physics extension | -|\pdv|$`\pdv{f}{x,y}`|`\pdv{f}{x,y}`| derivative | -|\pdv*|$`\pdv*{f}{x,y}`|`\pdv*{f}{x,y}`| derivative | -|\permil|$`\permil`|| wasysym | -|\perp|$`\perp`||| -|\Perp|$`\Perp`|| cmll | -|\phantom|$`\Gamma^{\phantom{i}j}_{i\phantom{j}k}`|`\Gamma^{\phantom{i}j}_{i\phantom{j}k}`|| -|\phase|$`\phase{-78^\circ}`|`\phase{-78^\circ}`| steinmetz | -|\Phi|$`\Phi`||| -|\phi|$`\phi`||| -|\Pi|$`\Pi`||| -|\pi|$`\pi`||| -|{picture}|(Not supported)||| -|\pitchfork|$`\pitchfork`|| ams | -|\plim|$`\plim`|| statmath | -|\plusmn|$`\plusmn`|| texvc extension | -|\pm|$`\pm`||| -|\pmatrix|(Not supported)| See `{pmatrix}` || -|{pmatrix}|$`\begin{pmatrix}a&b\\c&d\end{pmatrix}`|`\begin{pmatrix}`
   `a & b \\`
   `c & d`
`\end{pmatrix}`| ams | -|{pmatrix*}|$`\begin{pmatrix*}[r] -1 & 3\\ 2 & -4 \end{pmatrix*}`|`\begin{pmatrix*}[r]`
   `-1 & 3 \\`
   `2 & -4`
`\end{pmatrix*}`| mathtools | -|\pmb|$`\pmb{\mu}`|`\pmb{\mu}`| ams | -|\pmod|$`x\pmod a`|`x\pmod a`|| -|\pod|$`x \pod a`|`x \pod a`| ams | -|\pointint|$`\pointint`||| -|\poissonbracket|$`\poissonbracket{A}{B}`|`\poissonbracket{A}{B}`| physics extension | -|\pounds|$`\pounds`||| -|\pqty|$`\pqty{5}`|`\pqty{5}`| physics extension | -|\Pr|$`\Pr`||| -|\prec|$`\prec`||| -|\precapprox|$`\precapprox`|| ams | -|\preccurlyeq|$`\preccurlyeq`|| ams | -|\preceq|$`\preceq`|| ams | -|\precnapprox|$`\precnapprox`|| ams | -|\precneqq|$`\precneqq`|| ams | -|\precnsim|$`\precnsim`|| ams | -|\precsim|$`\precsim`|| ams | -|\prescript|$`\prescript{a}{2}{\mathbf{C}}^{5+}_{2}`|`\prescript{a}{2}{\mathbf{C}}^{5+}_{2}`| mathtools | -|\prime|$`\prime`||| -|\principalvalue|$`\principalvalue`|| physics extension | -|\pv|$`\pv`|| physics extension | -|\PV|$`\PV(x)`|`\PV(x)`| physics extension | -|\prod|$`\prod`||| -|\projlim|$`\projlim`|`\projlim`| ams | -|\propto|$`\propto`||| -|\providecommand|$`\providecommand\greet{\text{Hello}} \greet`|`\providecommand\greet{\text{Hello}}`
`\greet`|| -|\psi|$`\psi`||| -|\Psi|$`\Psi`||| -|\pu |$`{123~\mathchoice{\textstyle\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}}`|`\pu{123 kJ//mol}`| mhchem extension | - -## Q - -| Function | Rendered | Source or Comment | Package | -|-------------|--------------------------|-------------------------|-------------------| -| \Q | (Not supported) | See `\Bbb{Q}` | | -| \qall | $`\qall` | | physics extension | -| \qand | $`\qand` | | physics extension | -| \qas | $`\qas` | | physics extension | -| \qassume | $`\qassume` | | physics extension | -| \qc | $`\qc` | | physics extension | -| \qcc | $`\qcc` | | physics extension | -| \qcomma | $`\qcomma` | | physics extension | -| \qelse | $`\qelse` | | physics extension | -| \qeven | $`\qeven` | | physics extension | -| \qfor | $`\qfor` | | physics extension | -| \qgiven | $`\qgiven` | | physics extension | -| \qif | $`\qif` | | physics extension | -| \qin | $`\qin` | | physics extension | -| \qinteger | $`\qinteger` | | physics extension | -| \qlet | $`\qlet` | | physics extension | -| \qodd | $`\qodd` | | physics extension | -| \qor | $`\qor` | | physics extension | -| \qotherwise | $`\qotherwise` | | physics extension | -| \qq | $`\qq{text}` | `\qq{text}` | physics extension | -| \qqtext | $`\qqtext{text}` | `\qqtext{text}` | physics extension | -| \qquad | $`a\qquad\qquad{b}` | `a\qquad\qquad{b}` | | -| \qsince | $`\qsince` | | physics extension | -| \qthen | $`\qthen` | | physics extension | -| \qty | $`\qty{5 \text{m}}` | `\qty{5 \text{m}}` | physics extension | -| \quad | $`a\quad\quad{b}` | `a\quad\quad{b}` | | -| \quantity | $`\quantity{5 \text{m}}` | `\quantity{5 \text{m}}` | physics extension | -| \qunless | $`\qunless` | | physics extension | -| \qusing | $`\qusing` | | physics extension | -| \questeq | $`\questeq` | | stix | - -## R - -| Function | Rendered | Source or Comment | Package | -|--------------------|-------------|-------------------|-----------| -| \R | $`\R`| | texvc extension | -| \r | $`\text{\r{a}}`| `\text{\r{a}}`| | -| \raise | $`M\raise3pt{M^2}M`| `M\raise3pt{M^2}M`  or
`M\raise3pt\hbox{$`M^2`}M`| | -| \raisebox | $`h\raisebox{2pt}{ighe}r`| `h\raisebox{2pt}{ighe}r`| | -| \rang | $`\langle A\rang`| `\langle A\rang` | texvc extension | -| \rangle | $`\langle A\rangle`| `\langle A\rangle`| | -| \rank | $`\rank M`| `\rank M`| physics extension | -| \Rarr | $`\Rarr`| | texvc extension | -| \rArr | $`\rArr`| | texvc extension | -| \rarr | $`\rarr`| | texvc extension | -| \ratio | $`\ratio`| | colonequals | -| \rBrace | $`\rBrace`| | stix | -| \rbrace | $`\rbrace`| | | -| \rbrack | $`\rbrack`| | | -| {rcases} | $`\begin{rcases}a&\text{if }b\\c&\text{if }d\end{rcases}`| `\begin{rcases}`
   `a &\text{if } b \\`
   `c &\text{if } d`
`\end{rcases}`| mathtools | -| \rceil | $`\rceil`| | | -| \Re | $`\Re`| | | -| \real | $`\real`| | texvc extension | -| \Reals | $`\Reals`| | texvc extension | -| \reals | $`\reals`| | texvc extension | -| \ref | $`\ref{tag1}`| `\ref{tag1}`
Some sites do not support `\ref`.| | -| \relax | | | | -| \renewcommand | $`\def\hail{Hi!}\renewcommand\hail{\text{Ahoy!}} \hail`| `\def\hail{Hi!}`
`\renewcommand\hail{\text{Ahoy!}}`
`\hail`| newcommand | -| \renewenvironment | (Not supported)| | newcommand | -| \require | (Not supported)| | | -| \Res | $`\Res[f(z)]`| `\Res[f(z)]`| physics extension | -| \restriction | $`\restriction`| | ams | -| \rfloor | $`\rfloor`| | | -| \rgroup | $`\rgroup`| | | -| \rhd | $`\rhd`| | ams | -| \Rho | $`\Rho`| | | -| \rho | $`\rho`| | | -| \right | $`\left.\dfrac a b\right)`| `\left.\dfrac a b\right)`| | -| \Rightarrow | $`\Rightarrow`| | | -| \rightarrow | $`\rightarrow`| | | -| \rightarrowtail | $`\rightarrowtail`| | ams | -| \rightharpoondown | $`\rightharpoondown`| | | -| \rightharpoonup | $`\rightharpoonup`| | | -| \rightleftarrows | $`\rightleftarrows`| | ams | -| \rightleftharpoons | $`\rightleftharpoons`| | ams | -| \rightrightarrows | $`\rightrightarrows`| | ams | -| \rightsquigarrow | $`\rightsquigarrow`| | ams | -| \rightthreetimes | $`\rightthreetimes`| | ams | -| \risingdotseq | $`\risingdotseq`| | ams | -| \rlap | $`\rlap{\,/}{=}`| `\rlap{\,/}{=}`| | -| \rm | $`{\rm AaBb12}`| `{\rm AaBb12}`| | -| \rmoustache | $`\rmoustache`| | | -| \root | (Not supported)| | | -| \rotatebox | (Not supported)| | | -| \rparen | $`\rparen`| | mathtools | -| \rppolint | $`\rppolint`| | | -| \rq | $`\rq`| | | -| \rrbracket | $`\rrbracket`| | stmaryrd | -| \Rrightarrow | $`\Rrightarrow`| | ams | -| \Rsh | $`\Rsh`| | ams | -| \rtimes | $`\rtimes`| | ams | -| \Rule | (Not supported)| see `\rule`| | -| \rule | $`x\rule[6pt]{2ex}{1ex}x`| `x\rule[6pt]{2ex}{1ex}x`| | -| \rVert | $`\rVert`| | ams | -| \rvert | $`\rvert`| | ams | - -## S - -
- -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\S|$`\text{\S}`|`\text{\S}` or `\S`|| -|\Sampi|$`\Sampi`||| -|\sampi|$`\sampi`||| -|\sc|(Not supported)|See `\textsc`|| -|\scoh|$`\scoh`|| cmll | -|\scalebox|(Not supported)||| -|\scpolint|$`\scpolint`||| -|\scr|(Not supported)|See `\mathscr`|| -|\scriptscriptstyle|$`\scriptscriptstyle \frac cd`|`\scriptscriptstyle \frac cd`|| -|\scriptsize|$`\scriptsize scriptsize`|`\scriptsize scriptsize`|| -|\scriptstyle|$`A{\scriptstyle B}`|`A{\scriptstyle B}`|| -|\sdot|$`\sdot`|| texvc extension | -|\searrow|$`\searrow`||| -|\sec|$`\sec`||| -|\sect|$`\text{\sect}`|`\text{\sect}`| texvc extension | -|\set| $`\Set{ x | x<5 }` |`\set{x | x<5}`| braket -|\Set| $`\Set{ x | x<\tfrac 1 2 }` |`\Set{ x | x<\tfrac 1 2 }`| braket -|\setlength|(Not supported)||| -|\setminus|$`\setminus`||| -|\sf|$`{\sf AaBb123}`|`{\sf AaBb123}`|| -|\sgn|$`\sgn`|| mismath | -|\sharp|$`\sharp`||| -|\shift|$`\shift`|| cmll | -|\shneg|$`\shneg`|| cmll | -|\shortmid|$`\shortmid`|| ams | -|\shortparallel|$`\shortparallel`|| ams | -|\shoveleft|(Not supported)|| ams | -|\shoveright|(Not supported)|| ams | -|\shpos|$`\shpos`|| cmll | -|\sideset|$`\sideset{_a^b}{_c^d}\sum`|`\sideset{_a^b}{_c^d}\sum`| ams | -|\Sigma|$`\Sigma`||| -|\sigma|$`\sigma`||| -|\sim|$`\sim`||| -|\simeq|$`\simeq`||| -|\sin|$`\sin`||| -|\sincoh|$`\sincoh`|| cmll | -|\sinh|$`\sinh`||| -|\sixptsize|$`\sixptsize sixptsize`|`\sixptsize sixptsize`|| -|\sh|$`\sh`||| -|\skew|(Not supported)||| -|\skip|(Not supported)||| -|\sl|(Not supported)||| -|\small|$`\small small`|`\small small`|| -|\smallfrown|$`\smallfrown`|| ams | -|\smallint|$`\smallint`||| -|{smallmatrix}|$`\begin{smallmatrix} a & b \\ c & d \end{smallmatrix}`|`\begin{smallmatrix}`
   `a & b \\`
   `c & d`
`\end{smallmatrix}`|| -|\smallsetminus|$`\smallsetminus`|| ams | -|\smallsmile|$`\smallsmile`|| ams | -|\smash|$`\left(x^{\smash{2}}\right)`|`\left(x^{\smash{2}}\right)`|| -|\smile|$`\smile`||| -|\smiley|$`\smiley`|| wasysym | -|\sout|$`\sout{abc}`|`\sout{abc}`| ulem | -|\Space|(Not supported)|see `\space`|| -|\space|$`a\space b`|`a\space b`|| -|\spades|$`\spades`|| texvc extension | -|\spadesuit|$`\spadesuit`||| -|\sphericalangle|$`\sphericalangle`|| ams | -|{split}|$$\begin{equation}\begin{split}a &=b+c\\&=e+f\end{split}\end{equation}$$|`\begin{equation}`
`\begin{split}`
   `a &=b+c\\`
      `&=e+f`
`\end{split}`
`\end{equation}`| ams | -|\sqcap|$`\sqcap`||| -|\sqcup|$`\sqcup`||| -|\sqint|$`\sqint`||| -|\square|$`\square`||| -|\sqrt|$`\sqrt[3]{x}`|`\sqrt[3]{x}`|| -|\sqsubset|$`\sqsubset`|| ams | -|\sqsubseteq|$`\sqsubseteq`||| -|\sqsupset|$`\sqsupset`|| ams | -|\sqsupseteq|$`\sqsupseteq`|| ams | -|\ss|$`\text{\ss}`|`\text{\ss}`|| -|\stackrel|$`\stackrel{!}{=}`|`\stackrel{!}{=}`|| -|\standardstate|$`\standardstate`|| chemstyle | -|\star|$`\star`||| -|\stareq|$`\stareq`|| stix | -|\Stigma|$`\Stigma`||| -|\stigma|$`\stigma`||| -|\strictif|$`\strictif`|| txfonts/pxfonts | -|\strictfi|$`\strictfi`|| txfonts/pxfonts | -|\strut|(Not supported)||| -|\style|(Not supported)|Non standard|| -|\sub|$`\sub`|| texvc extension | -|{subarray}|$$\sum_{\begin{subarray}{l} i\in\Lambda\\ 0 `i\in\Lambda\\`
  `0`\end{subarray}}P(i,j)`| ams | -|\sube|$`\sube`|| texvc extension | -|\Subset|$`\Subset`|| ams | -|\subset|$`\subset`||| -|\subseteq|$`\subseteq`||| -|\subseteqq|$`\subseteqq`|| ams | -|\subsetneq|$`\subsetneq`|| ams | -|\subsetneqq|$`\subsetneqq`|| ams | -|\substack|$$\sum_{\substack{0 - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\tag|$$\tag{hi} e=mc^2 \label{tag1}$$|`\tag{hi} e=mc^2 \label{tag1}`| ams | -|\tag*|$$\tag*{hey} e=mc^2$$|`\tag*{hey} e=mc^2`| ams | -|\tan|$`\tan`||| -|\tanh|$`\tanh`||| -|\Tau|$`\Tau`||| -|\tau|$`\tau`||| -|\tbinom|$`\tbinom n k`|`\tbinom n k`| ams | -|\TeX|$`\TeX`||| -|\text|$`\text{ yes }\&\text{ no }`|`\text{ yes }\&\text{ no }`|| -|\textasciitilde|$`\text{\textasciitilde}`|`\text{\textasciitilde}`|| -|\textasciicircum|$`\text{\textasciicircum}`|`\text{\textasciicircum}`|| -|\textbackslash|$`\text{\textbackslash}`|`\text{\textbackslash}`|| -|\textbar|$`\text{\textbar}`|`\text{\textbar}`|| -|\textbardbl|$`\text{\textbardbl}`|`\text{\textbardbl}`|| -|\textbf|$`\textbf{AaBb123}`|`\textbf{AaBb123}`|| -|\textbraceleft|$`\text{\textbraceleft}`|`\text{\textbraceleft}`|| -|\textbraceright|$`\text{\textbraceright}`|`\text{\textbraceright}`|| -|\textbullet|$`\text{\textbullet}`|`\text{\textbullet}`|| -|\textcircled|(Not supported)||| -|\textcolor|$`\textcolor{blue}{F=ma}`|`\textcolor{blue}{F=ma}`| color | -|\textdagger|$`\text{\textdagger}`|`\text{\textdagger}`|| -|\textdaggerdbl|$`\text{\textdaggerdbl}`|`\text{\textdaggerdbl}`|| -|\textdegree|$`\text{\textdegree}`|`\text{\textdegree}`|| -|\textdollar|$`\text{\textdollar}`|`\text{\textdollar}`|| -|\textellipsis|$`\text{\textellipsis}`|`\text{\textellipsis}`|| -|\textemdash|$`\text{\textemdash}`|`\text{\textemdash}`|| -|\textendash|$`\text{\textendash}`|`\text{\textendash}`|| -|\\texteuro|$`\text{\texteuro}`|`\text{\texteuro}`|| -|\textgreater|$`\text{\textgreater}`|`\text{\textgreater}`|| -|\textit|$`\textit{AaBb}`|`\textit{AaBb}`|| -|\textless|$`\text{\textless}`|`\text{\textless}`|| -|\textmd|$`\textmd{AaBb123}`|`\textmd{AaBb123}`|| -|\textnormal|$`\textnormal{AB}`|`\textnormal{AB}`|| -|\textquotedblleft|$`\text{\textquotedblleft}`|`\text{\textquotedblleft}`|| -|\textquotedblright|$`\text{\textquotedblright}`|`\text{\textquotedblright}`|| -|\textquoteleft|$`\text{\textquoteleft}`|`\text{\textquoteleft}`|| -|\textquoteright|$`\text{\textquoteright}`|`\text{\textquoteright}`|| -|\textregistered|$`\text{\textregistered}`|`\text{\textregistered}`|| -|\textrm|$`\textrm{AaBb123}`|`\textrm{AaBb123}`|| -|\textsc|$`\textsc{hey}`|`\textsc{hey}`|| -|\textsf|$`\textsf{AaBb123}`|`\textsf{AaBb123}`|| -|\textsl|(Not supported)||| -|\textsterling|$`\text{\textsterling}`|`\text{\textsterling}`|| -|\textstyle|$`\textstyle\sum_0^n`|`\textstyle\sum_0^n`|| -|\texttip|$`\texttip{\text{hover here}}{This is a tooltip.}`|`\texttip{\text{hover here}}`
`{This is a tooltip.}`|MathJax| -|\texttt|$`\texttt{AaBb123}`|`\texttt{AaBb123}`|| -|\textunderscore|$`\text{\textunderscore}`|`\text{\textunderscore}`|| -|\textup|$`\textup{AaBb123}`|`\textup{AaBb123}`|| -|\textvisiblespace|$`\text{\textvisiblespace}`|`\text{\textvisiblespace}`|| -|\tfrac|$`\tfrac ab`|`\tfrac ab`| ams | -|\tg|$`\tg`||| -|\th|$`\th`||| -|\therefore|$`\therefore`|| ams | -|\Theta|$`\Theta`||| -|\theta|$`\theta`||| -|\thetasym|$`\thetasym`|| texvc extension | -|\thickapprox|$`\thickapprox`|| ams | -|\thicksim|$`\thicksim`|| ams | -|\thickspace|$`a\thickspace b`|`a\thickspace b`| ams | -|\thinspace|$`a\thinspace b`|`a\thinspace b`| ams | -|\tilde|$`\tilde M`|`\tilde M`|| -|\times|$`\times`||| -|\Tiny|$`\Tiny Tiny`|`\Tiny Tiny`|| -|\tiny|$`\tiny tiny`|`\tiny tiny`|| -|\to|$`\to`||| -|\toggle|$`\toggle{\text{Click me}}{Hey!}{Ow!}\endtoggle`|`\toggle{\text{Click me}}`
`{Hey!}{Ow!}\endtoggle`| MathJax | -|\top|$`\top`||| -|\Tr|$`\Tr\rho`|`\Tr\rho`| physics extension | -|\tr|$`\tr\rho`|`\tr\rho`| physics extension | -|\triangle|$`\triangle`||| -|\triangledown|$`\triangledown`|| ams | -|\triangleleft|$`\triangleleft`||| -|\trianglelefteq|$`\trianglelefteq`|| ams | -|\triangleq|$`\triangleq`|| ams | -|\triangleright|$`\triangleright`||| -|\trianglerighteq|$`\trianglerighteq`|| ams | -|\tt|$`{\tt AaBb123}`|`{\tt AaBb123}`|| -|\twoheadleftarrow|$`\twoheadleftarrow`|| ams | -|\twoheadrightarrow|$`\twoheadrightarrow`|| ams | - -## U - -| Function | Rendered | Source or Comment | Package | -|----------------------|-----------------------------|----------------------------|-----------------| -| \u | $`\text{\u{a}}` | `\text{\u{a}}` | | -| \Uarr | $`\Uarr` | | texvc extension | -| \uArr | $`\uArr` | | texvc extension | -| \uarr | $`\uarr` | | texvc extension | -| \ulcorner | $`\ulcorner` | | ams | -| \underbar | $`\underbar{X}` | `\underbar{X}` | | -| \underbrace | $`\underbrace{x+⋯+x}_{n\text{ times}}`| `\underbrace{x+⋯+x}_{n\text{ times}}`| | -| \underbracket | (Not supported) | | | -| \undergroup | $`\undergroup{AB}` | `\undergroup{AB}` | MnSymbol | -| \underleftarrow | $`\underleftarrow{AB}` | `\underleftarrow{AB}` | ams | -| \underleftrightarrow | $`\underleftrightarrow{AB}` | `\underleftrightarrow{AB}` | ams | -| \underrightarrow | $`\underrightarrow{AB}` | `\underrightarrow{AB}` | ams | -| \underline | $`\underline{\text{a long argument}}`| `\underline{\text{a long argument}}`| | -| \underlinesegment | (Not supported) | | | -| \underparen | $`\underparen{abc}` | `\underparen{abc}` | | -| \underrightarrow | $`\underrightarrow{AB}` | `\underrightarrow{AB}` | | -| \underset | $`\underset{!}{=}` | `\underset{!}{=}` | AMS | -| \unicode | (Not supported) | See `\char` | | -| \unlhd | $`\unlhd` | | ams | -| \unrhd | $`\unrhd` | | ams | -| \up | (Not supported) | | | -| \upalpha | $`\upalpha` | | upgreek | -| \Uparrow | $`\Uparrow` | | | -| \uparrow | $`\uparrow` | | | -| \upbeta | $`\upbeta` | | upgreek | -| \updelta | $`\updelta` | | upgreek | -| \upchi | $`\upchi` | | upgreek | -| \Updownarrow | $`\Updownarrow` | | | -| \updownarrow | $`\updownarrow` | | | -| \upeta | $`\upeta` | | upgreek | -| \upepsilon | $`\upepsilon` | | upgreek | -| \upgamma | $`\upgamma` | | upgreek | -| \upharpoonleft | $`\upharpoonleft` | | ams | -| \upharpoonright | $`\upharpoonright` | | ams | -| \upiota | $`\upiota` | | upgreek | -| \upkappa | $`\upkappa` | | upgreek | -| \uplambda | $`\uplambda` | | upgreek | -| \upmu | $`\upmu` | | upgreek | -| \upnu | $`\upnu` | | upgreek | -| \upomega | $`\upomega` | | upgreek | -| \upomicron | $`\upomicron` | | upgreek | -| \uplus | $`\uplus` | | upgreek | -| \upphi | $`\upphi` | | upgreek | -| \uppi | $`\uppi` | | upgreek | -| \uppsi | $`\uppsi` | | upgreek | -| \uprho | $`\uprho` | | upgreek | -| \uproot | (Not supported) | | | -| \upshape | (Not supported) | | | -| \upsigma | $`\upsigma` | | upgreek | -| \Upsilon | $`\Upsilon` | | | -| \upsilon | $`\upsilon` | | | -| \uptau | $`\uptau` | | upgreek | -| \uptheta | $`\uptheta` | | upgreek | -| \upuparrows | $`\upuparrows` | | ams | -| \upupsilon | $`\upupsilon` | | upgreek | -| \upxi | $`\upxi` | | upgreek | -| \upzeta | $`\upzeta` | | upgreek | -| \urcorner | $`\urcorner` | | ams | -| \url | $`\footnotesize\url{https://temml.org/}`| `\url{https://temml.org/}`
Requires `trust` [option](options.md)| | -| \utilde | $`\utilde{AB}` | `\utilde{AB}` | undertilde | - -## V - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------| -|\v|$`\text{\v{a}}`|`\text{\v{a}}`|| -|\va|$`\va{a}`|`\va{a}`| physics extension | -|\var|$`\var`|| physics extension | -|\varcoppa|$`\varcoppa`||| -|\varclubsuit|$`\varclubsuit`|| txfonts | -|\varDelta|$`\varDelta`|| ams | -|\vardiamondsuit|$`\vardiamondsuit`|| txfonts | -|\varepsilon|$`\varepsilon`||| -|\varGamma|$`\varGamma`|| ams | -|\varheartsuit|$`\varheartsuit`|| txfonts | -|\variation|$`\variation`|| physics extension | -|\varinjlim|$`\varinjlim`|`\varinjlim`| ams | -|\varkappa|$`\varkappa`|| ams | -|\varLambda|$`\varLambda`|| ams | -|\varliminf|$`\varliminf`|`\varliminf`| ams | -|\varlimsup|$`\varlimsup`|`\varlimsup`| ams | -|\varnothing|$`\varnothing`|| ams | -|\varointclockwise|$`\varointclockwise`||| -|\varOmega|$`\varOmega`|| ams | -|\varPhi|$`\varPhi`|| ams | -|\varphi|$`\varphi`||| -|\varPi|$`\varPi`|| ams | -|\varpi|$`\varpi`||| -|\varprojlim|$`\varprojlim`|`\varprojlim`| ams | -|\varpropto|$`\varpropto`|| ams | -|\varPsi|$`\varPsi`|| ams | -|\varrho|$`\varrho`||| -|\varSigma|$`\varSigma`|| ams | -|\varsigma|$`\varsigma`||| -|\varspadesuit|$`\varspadesuit`|| txfonts | -|\varstigma|(Not supported)||| -|\varsubsetneq|$`\varsubsetneq`|| ams | -|\varsubsetneqq|$`\varsubsetneqq`|| ams | -|\varsupsetneq|$`\varsupsetneq`|| ams | -|\varsupsetneqq|$`\varsupsetneqq`|| ams | -|\varTheta|$`\varTheta`|| ams | -|\vartheta|$`\vartheta`||| -|\vartriangle|$`\vartriangle`|| ams | -|\vartriangleleft|$`\vartriangleleft`|| ams | -|\vartriangleright|$`\vartriangleright`|| ams | -|\varUpsilon|$`\varUpsilon`|| ams | -|\varXi|$`\varXi`|| ams | -|\vb|$`\vb{a}`|`\vb{a}`| physics extension | -|\vcentcolon|$`\vcentcolon`||| -|\vcenter|(Not supported)||| -|\Vdash|$`\Vdash`|| ams | -|\vDash|$`\vDash`|| ams | -|\vdash|$`\vdash`||| -|\vdot|$`\vdot`|| physics extension | -|\vdots|$`\vdots`||| -|\vec|$`\vec{F}`|`\vec{F}`|| -|\vectorarrow|$`\vectorarrow{a}`|`\vectorarrow{a}`| physics extension | -|\vectorbold|$`\vectorbold{a}`|`\vectorbold{a}`| physics extension | -|\vectorunit|$`\vectorunit{a}`|`\vectorunit{a}`| physics extension | -|\vee|$`\vee`||| -|\veebar|$`\veebar`|| ams | -|\veeeq|$`\veeeq`|| stix | -|\verb|$`\verb!\frac a b!`|`\verb!\frac a b!`|| -|\Vert|$`\Vert`||| -|\vert|$`\vert`||| -|\vfil|(Not supported)||| -|\vfill|(Not supported)||| -|\vline|(Not supported)||| -|{Vmatrix}|$`\begin{Vmatrix}a&b\\c&d\end{Vmatrix}`|`\begin{Vmatrix}`
   `a & b \\`
   `c & d`
`\end{Vmatrix}`| ams | -|{Vmatrix*}|$`\begin{Vmatrix*}[r] -1 & 3\\ 2 & -4 \end{Vmatrix*}`|`\begin{Vmatrix*}[r]`
   `-1 & 3 \\`
   `2 & -4`
`\end{Vmatrix*}`| mathtools | -|{vmatrix}|$`\begin{vmatrix}a&b\\c&d\end{vmatrix}`|`\begin{vmatrix}`
   `a & b \\`
   `c & d`
`\end{vmatrix}`| ams | -|{vmatrix*}|$`\begin{vmatrix*}[r] -1 & 3\\ 2 & -4 \end{vmatrix*}`|`\begin{vmatrix*}[r]`
   `-1 & 3 \\`
   `2 & -4`
`\end{vmatrix*}`| mathtools | -|\vphantom|$`\overline{\vphantom{M}a}`|`\overline{\vphantom{M}a}`|| -|\vqty|$`\vqty{x}`|`\vqty{x}`| physics extension | -|\vu|$`\vu{a}`|`\vu{a}`| physics extension | -|\Vvdash|$`\Vvdash`|| ams | - -## W - -| Function | Rendered | Source or Comment | Package | -|------------|--------------------|-------------------|-----------------| -| \wedge | $`\wedge` | | | -| \wedgeq | $`\wedgeq` | | stix | -| \weierp | $`\weierp` | | texvc extension | -| \widecheck | $`\widecheck{AB}` |`\widecheck{AB}` | mathabx | -| \widehat | $`\widehat{AB}` |`\widehat{AB}` | | -| \wideparen | $`\wideparen{abc}` |`\wideparen{abc}` | MnSymbol | -| \widetilde | $`\widetilde{AB}` |`\widetilde{AB}` | | -| \with | $`\with` | | cmll | -| \wn | $`\wn` | | cmll | -| \wp | $`\wp` | | | -| \wr | $`\wr` | | | - -## X - -| Function | Rendered | Source or Comment | Package | -|---------------------|-----------------------------|----------------------------|-----------| -| \xcancel | $`\xcancel{ABC}` | `\xcancel{ABC}` | cancel | -| \xdef | (Not supported) | | | -| \Xi | $`\Xi` | | | -| \xi | $`\xi` | | | -| \xhookleftarrow | $`\xhookleftarrow{abc}` | `\xhookleftarrow{abc}` | mathtools | -| \xhookrightarrow | $`\xhookrightarrow{abc}` | `\xhookrightarrow{abc}` | mathtools | -| \xLeftarrow | $`\xLeftarrow{abc}` | `\xLeftarrow{abc}` | mathtools | -| \xleftarrow | $`\xleftarrow{abc}` | `\xleftarrow{abc}` | ams | -| \xleftharpoondown | $`\xleftharpoondown{abc}` | `\xleftharpoondown{abc}` | mathtools | -| \xleftharpoonup | $`\xleftharpoonup{abc}` | `\xleftharpoonup{abc}` | mathtools | -| \xLeftrightarrow | $`\xLeftrightarrow{abc}` | `\xLeftrightarrow{abc}` | mathtools | -| \xleftrightarrow | $`\xleftrightarrow{abc}` | `\xleftrightarrow{abc}` | mathtools | -| \xleftrightharpoons | $`\xleftrightharpoons{abc}` | `\xleftrightharpoons{abc}` | mathtools | -| \xlongequal | $`\xlongequal{abc}` | `\xlongequal{abc}` | extpfeil | -| \xmapsto | $`\xmapsto{abc}` | `\xmapsto{abc}` | mathtools | -| \xRightarrow | $`\xRightarrow{abc}` | `\xRightarrow{abc}` | mathtools | -| \xrightarrow | $`\xrightarrow{abc}` | `\xrightarrow{abc}` | ams | -| \xrightharpoondown | $`\xrightharpoondown{abc}` | `\xrightharpoondown{abc}` | mathtools | -| \xrightharpoonup | $`\xrightharpoonup{abc}` | `\xrightharpoonup{abc}` | mathtools | -| \xrightleftharpoons | $`\xrightleftharpoons{abc}` | `\xrightleftharpoons{abc}` | mathtools | -| \xtofrom | $`\xtofrom{abc}` | `\xtofrom{abc}` | extpfeil | -| \xtwoheadleftarrow | $`\xtwoheadleftarrow{abc}` | `\xtwoheadleftarrow{abc}` | extpfeil | -| \xtwoheadrightarrow | $`\xtwoheadrightarrow{abc}` | `\xtwoheadrightarrow{abc}` | extpfeil | - -## YZ - -| Function | Rendered | Source or Comment | Package | -|----------------|-------------|-------------------|-----------------| -| \yen | $`\yen` | | ams | -| \Z | $`\Z` | | texvc extension | -| \Zeta | $`\Zeta` | | | -| \zeta |$`\zeta` | | | - - -
- -

Copyright © 2021, 2022 Ron Kok. Released under the MIT License

- -
- -
- - - -
- - - - -
- - - - - \ No newline at end of file diff --git a/docs/supported.md b/docs/supported.md deleted file mode 100644 index 192e5f16..00000000 --- a/docs/supported.md +++ /dev/null @@ -1,1623 +0,0 @@ - - - - - - Temml Functions - - - - - - - -
- -# Supported Functions - -**Temml** is a JavaScript library that converts TeX math-mode functions to MathML. -This page lists the TeX functions it supports, sorted into logical groups. - -To read this page, use a browser that supports MathML, such as Firefox or Safari. -Chrome and Edge will support MathML [soon](https://www.igalia.com/2021/08/09/MathML-Progress.html). - -There is a similar [Support Table](./support_table.html), sorted alphabetically, -that lists both supported and some un-supported functions. - -## Accents - -+:-------------------------+:-------------------------+:-----------------------------------+ -| $`a'` `a'` | $`\tilde{a}` `\tilde{a}` | $`\widetilde{ac}` `\widetilde{ac}` | -+--------------------------+--------------------------+------------------------------------+ -| $`a''` `a''` | $`\vec{F}` `\vec{F}` | $`\utilde{AB}` `\utilde{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`a^{\prime}` | $`\overleftarrow{AB}` | $`\overrightarrow{AB}` | -| `a^{\prime}` | `\overleftarrow{AB}` | `\overrightarrow{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\acute{a}` `\acute{a}` | $`\underleftarrow{AB}` | $`\underrightarrow{AB}` | -| | `\underleftarrow{AB}` | `\underrightarrow{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\bar{y}` `\bar{y}` | $`\overline{AB}` | $`\Overrightarrow{AB}` | -| | `\overline{AB}` | `\Overrightarrow{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\breve{a}` `\breve{a}` | $`\underline{AB}` | $`\overleftrightarrow{AB}` | -| | `\underline{AB}` | `\overleftrightarrow{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\check{a}` `\check{a}` | $`\widecheck{ac}` | $`\underleftrightarrow{AB}` | -| | `\widecheck{ac}` | `\underleftrightarrow{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\dot{a}` `\dot{a}` | $`\overleftharpoon{ac}` | $`\overrightharpoon{ac}` | -| | `\overleftharpoon{ac}` | `\overrightharpoon{ac}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\ddot{a}` `\ddot{a}` | $`\overgroup{AB}` | $`\wideparen{AB}` | -| | `\overgroup{AB}` | `\wideparen{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\dddot{a}` `\dddot{a}` | $`\undergroup{AB}` | $`\overparen{AB}` | -| | `\undergroup{AB}` | `\overparen{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\ddddot{a}` | $`\underbar{X}` | $`\underparen{AB}` | -| `\ddddot{a}` | `\underbar{X}` | `\underparen{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\grave{a}` `\grave{a}` | $`\mathring{g}` | $`\overbrace{AB}` | -| | `\mathring{g}` | `\overbrace{AB}` | -+--------------------------+--------------------------+------------------------------------+ -| $`\hat{\theta}` | $`\widehat{ac}` | $`\underbrace{AB}` | -| `\hat{\theta}` | `\widehat{ac}` | `\underbrace{AB}` | -+--------------------------+--------------------------+------------------------------------+ - - -**Accent functions inside \\text{…}** - -+:------------------+:------------------+:-----------------+:----------------+ -| $`\text{\'{a}}` | $`\text{\~{a}}` | $`\text{\.{a}}` | $`\text{\H{a}}` | -| `\'{a}` | `\~{a}` | `\.{a}` | `\H{a}` | -+-------------------+-------------------+------------------+-----------------+ -| $``\text{\`{a}}`` | $`\text{\={a}}` | $`\text{\"{a}}` | $`\text{\v{a}}` | -| ``\`{a}`` | `\={a}` | `\"{a}` | `\v{a}` | -+-------------------+-------------------+------------------+-----------------+ -| $`\text{\^{a}}` | $`\text{\u{a}}` | $`\text{\r{a}}` | $`\text{\c{c}}` | -| `\^{a}` | `\u{a}` | `\r{a}` | `\c{c}` | -+-------------------+-------------------+------------------+-----------------+ - -See also [letters](#letters) - -## Annotation - -+:---------------------------------+:---------------------------------------------------+ -| $`\cancel{5}` `\cancel{5}` | $`\overbrace{a+b+c}^{\text{note}}` | -| | `\overbrace{a+b+c}^{\text{note}}` | -+----------------------------------+----------------------------------------------------+ -| $`\bcancel{5}` `\bcancel{5}` | $`\underbrace{a+b+c}_{\text{note}}` | -| | `\underbrace{a+b+c}_{\text{note}}` | -+----------------------------------+----------------------------------------------------+ -| $`\xcancel{ABC}` `\xcancel{ABC}` | $`\cancelto{0}{x+1}` | -| | `\cancelto{0}{x+1}` | -+----------------------------------+----------------------------------------------------+ -| $`\sout{abc}` `\sout{abc}` | $`\boxed{\pi=\frac c d}` | -| | `\boxed{\pi=\frac c d}` | -+----------------------------------+----------------------------------------------------+ -| $`\ref{tag1}` `\ref{tag1}` | $`\texttip{\text{hover here}}{This is a tooltip.}` | -| |`\texttip{\text{hover here}}{This is a tooltip.}` | -+----------------------------------+----------------------------------------------------+ -| | $`\toggle{\text{Click me}}{Hey!}{Ow!}\endtoggle` | -| | `\toggle{\text{Click me}}{Hey!}{Ow!}\endtoggle` | -+----------------------------------+----------------------------------------------------+ -| $$ | `\tag{hi} x+y^{2x} \label{tag1}` | -| \tag{hi} x+y^{2x} \label{tag1} | | -| $$ | | -+----------------------------------+----------------------------------------------------+ -| $$ | `\tag*{bye} x+y^{2x}` | -| \tag*{bye} x+y^{2x} | | -| $$ | | -+----------------------------------+----------------------------------------------------+ - -Also some [environments](#environments) have automatic equation numbering. - -A `\label{…}` may be placed anywhere and will create an HTML id matching the -`\label{…}` argument. That argument may contain only the characters `A-Za-z0-9_-`. - -On sites where Temml fields are updated dynamically, `\ref{…}` may not be -supported. Other Temml functions update only the local field. `\ref{…}` must -make two passes through the entire document. Some sites may choose not to do this. - -## Color - -+------------------------------+---------------------------------------------+ -| $`\color{blue} F=ma` | $`\color[RGB]{255,0,255} F=ma` | -| `{\color{blue} F=ma}` | `{\color[RGB]{255,0,255} F=ma}` | -+------------------------------+---------------------------------------------+ -| $`\textcolor{blue}{F=ma}` | $`\color[rgb]{1,0,1} F=ma` | -| `\textcolor{blue}{F=ma}` | `{\color[rgb]{1,0,1} F=ma}` | -+------------------------------+---------------------------------------------+ -| $`\textcolor{#228B22}{F=ma}` | $`\color[HTML]{ff00ff} F=ma` | -| `\textcolor{#228B22}{F=ma}` | `{\color[HTML]{ff00ff} F=ma}` | -+------------------------------+---------------------------------------------+ -| $`\colorbox{aqua}{A}` | `\definecolor{sortaGreen}{RGB}{128,128,0}`\ | -| `\colorbox{aqua}{A}` | $`\definecolor{sortaGreen}{RGB}{128,128,0} | -+------------------------------+ \color{sortaGreen} F=ma` + -| $`\fcolorbox{red}{aqua}{A}` | `{\color{sortaGreen} F=ma}` | -| `\fcolorbox{red}{aqua}{A}` | | -+------------------------------+---------------------------------------------+ - -`\definecolor` functions can be included in a [preamble](administration.html#preamble). -If so, their color definitions will have document-wide scope. - -Color functions can all take an optional argument to set the color model, as -in the `xcolor` package. (Exception: `\definecolor`’s model argument is -required.) Temml supports color models `HTML`, `RGB`, and `rgb`. - -If the color model is omitted, Temml color functions will accept: - -- `#rrggbb`, `#rgb`, or `rrggbb`. -- A color name previously created by `\definecolor`. -- Any color from the following `xcolor` table. -- Any of the standard HTML [predefined color names](https://www.w3schools.com/colors/colors_names.asp). - -
- -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Apricot}\rule{1em}{0.8em}} `  Apricot | $` {\color{ForestGreen}\rule{1em}{0.8em}} `  ForestGreen | $` {\color{olive}\rule{1em}{0.8em}} `  olive | $` {\color{RoyalPurple}\rule{1em}{0.8em}} `  RoyalPurple | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Aquamarine}\rule{1em}{0.8em}} `  Aquamarine | $` {\color{Fuchsia}\rule{1em}{0.8em}} `  Fuchsia | $` {\color{OliveGreen}\rule{1em}{0.8em}} `  OliveGreen | $` {\color{RubineRed}\rule{1em}{0.8em}} `  RubineRed | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Bittersweet}\rule{1em}{0.8em}} `  Bittersweet | $` {\color{Goldenrod}\rule{1em}{0.8em}} `  Goldenrod | $` {\color{orange}\rule{1em}{0.8em}} `  orange | $` {\color{Salmon}\rule{1em}{0.8em}} `  Salmon | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{blue}\rule{1em}{0.8em}} `  blue | $` {\color{gray}\rule{1em}{0.8em}} `  gray | $` {\color{Orange}\rule{1em}{0.8em}} `  Orange | $` {\color{SeaGreen}\rule{1em}{0.8em}} `  SeaGreen | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Blue}\rule{1em}{0.8em}} `  Blue | $` {\color{Gray}\rule{1em}{0.8em}} `  Gray | $` {\color{OrangeRed}\rule{1em}{0.8em}} `  OrangeRed | $` {\color{Sepia}\rule{1em}{0.8em}} `  Sepia | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{BlueGreen}\rule{1em}{0.8em}} `  BlueGreen | $` {\color{green}\rule{1em}{0.8em}} `  green | $` {\color{Orchid}\rule{1em}{0.8em}} `  Orchid | $` {\color{SkyBlue}\rule{1em}{0.8em}} `  SkyBlue | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{BlueViolet}\rule{1em}{0.8em}} `  BlueViolet | $` {\color{Green}\rule{1em}{0.8em}} `  Green | $` {\color{Peach}\rule{1em}{0.8em}} `  Peach | $` {\color{SpringGreen}\rule{1em}{0.8em}} `  SpringGreen | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{BrickRed}\rule{1em}{0.8em}} `  BrickRed | $` {\color{GreenYellow}\rule{1em}{0.8em}} `  GreenYellow | $` {\color{Periwinkle}\rule{1em}{0.8em}} `  Periwinkle | $` {\color{Tan}\rule{1em}{0.8em}} `  Tan | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{brown}\rule{1em}{0.8em}} `  brown | $` {\color{JungleGreen}\rule{1em}{0.8em}} `  JungleGreen | $` {\color{PineGreen}\rule{1em}{0.8em}} `  PineGreen | $` {\color{teal}\rule{1em}{0.8em}} `  teal | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Brown}\rule{1em}{0.8em}} `  Brown | $` {\color{Lavender}\rule{1em}{0.8em}} `  Lavender | $` {\color{pink}\rule{1em}{0.8em}} `  pink | $` {\color{TealBlue}\rule{1em}{0.8em}} `  TealBlue | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{BurntOrange}\rule{1em}{0.8em}} `  BurntOrange | $` {\color{lightgray}\rule{1em}{0.8em}} `  lightgray | $` {\color{Plum}\rule{1em}{0.8em}} `  Plum | $` {\color{Thistle}\rule{1em}{0.8em}} `  Thistle | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{CadetBlue}\rule{1em}{0.8em}} `  CadetBlue | $` {\color{lime}\rule{1em}{0.8em}} `  lime | $` {\color{ProcessBlue}\rule{1em}{0.8em}} `  ProcessBlue | $` {\color{Turquoise}\rule{1em}{0.8em}} `  Turquoise | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{CarnationPink}\rule{1em}{0.8em}} `  CarnationPink | $` {\color{LimeGreen}\rule{1em}{0.8em}} `  LimeGreen | $` {\color{purple}\rule{1em}{0.8em}} `  purple | $` {\color{violet}\rule{1em}{0.8em}} `  violet | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Cerulean}\rule{1em}{0.8em}} `  Cerulean | $` {\color{magenta}\rule{1em}{0.8em}} `  magenta | $` {\color{Purple}\rule{1em}{0.8em}} `  Purple | $` {\color{Violet}\rule{1em}{0.8em}} `  Violet | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{CornflowerBlue}\rule{1em}{0.8em}} `  CornflowerBlue | $` {\color{Magenta}\rule{1em}{0.8em}} `  Magenta | $` {\color{RawSienna}\rule{1em}{0.8em}} `  RawSienna | $` {\color{VioletRed}\rule{1em}{0.8em}} `  VioletRed | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{cyan}\rule{1em}{0.8em}} `  cyan | $` {\color{Mahogany}\rule{1em}{0.8em}} `  Mahogany | $` {\color{red}\rule{1em}{0.8em}} `  red | $` {\color{WildStrawberry}\rule{1em}{0.8em}} `  WildStrawberry | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Cyan}\rule{1em}{0.8em}} `  Cyan | $` {\color{Maroon}\rule{1em}{0.8em}} `  Maroon | $` {\color{Red}\rule{1em}{0.8em}} `  Red | $` {\color{yellow}\rule{1em}{0.8em}} `  yellow | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Dandelion}\rule{1em}{0.8em}} `  Dandelion | $` {\color{Melon}\rule{1em}{0.8em}} `  Melon | $` {\color{RedOrange}\rule{1em}{0.8em}} `  RedOrange | $` {\color{Yellow}\rule{1em}{0.8em}} `  Yellow | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{darkgray}\rule{1em}{0.8em}} `  darkgray | $` {\color{MidnightBlue}\rule{1em}{0.8em}} `  MidnightBlue | $` {\color{RedViolet}\rule{1em}{0.8em}} `  RedViolet | $` {\color{YellowGreen}\rule{1em}{0.8em}} `  YellowGreen | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{DarkOrchid}\rule{1em}{0.8em}} `  DarkOrchid | $` {\color{Mulberry}\rule{1em}{0.8em}} `  Mulberry | $` {\color{Rhodamine}\rule{1em}{0.8em}} `  Rhodamine | $` {\color{YellowOrange}\rule{1em}{0.8em}} `  YellowOrange | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ -| $` {\color{Emerald}\rule{1em}{0.8em}} `  Emerald | $` {\color{NavyBlue}\rule{1em}{0.8em}} `  NavyBlue | $` {\color{RoyalBlue}\rule{1em}{0.8em}} `  RoyalBlue | | -+----------------------------------------------------------------+------------------------------------------------------------+----------------------------------------------------------+----------------------------------------------------------------+ - - -## Delimiters - -+:-----------------+:-------------------+:-------------+:---------------------------+:--------------------+ -| $`(~)` `( )` | $`\lparen~\rparen` | $`⌈~⌉` `⌈ ⌉` | $`\lceil~\rceil` | $`\uparrow` | -| | `\lparen`\ | | `\lceil`\ | `\uparrow` | -| | $`~~~~` `\rparen` | | $`~~~~~` `\rceil` | | -+------------------+--------------------+--------------+----------------------------+---------------------+ -| $`[~]` `[ ]` | $`\lbrack~\rbrack` | $`⌊~⌋` `⌊ ⌋` | $`\lfloor~\rfloor` | $`\downarrow` | -| | `\lbrack`\ | | `\lfloor`\ | `\downarrow` | -| | $`~~~~` `\rbrack` | | $`~~~~~` `\rfloor` | | -+------------------+--------------------+--------------+----------------------------+---------------------+ -| $`\{ \}` | $`\lbrace \rbrace` | $`⎰⎱` `⎰⎱` | $`\lmoustache \rmoustache` | $`\updownarrow` | -| `\{ \}` | `\lbrace`\ | | `\lmoustache`\ | `\updownarrow` | -| | $`~~~~` `\rbrace` | | $`~~~~` `\rmoustache` | | -+------------------+--------------------+--------------+----------------------------+---------------------+ -| $`⟨~⟩` `⟨ ⟩` | $`\langle~\rangle` | $`⟮~⟯` `⟮ ⟯` | $`\lgroup~\rgroup` | $`\Uparrow` | -| | `\langle` \ | | `\lgroup`\ | `\Uparrow` | -| | $`~~~~~` `\rangle` | | $`~~~~~` `\rgroup` | | -+------------------+--------------------+--------------+----------------------------+---------------------+ -| $`\vert` | $`\vert` | $`┌ ┐` `┌ ┐` | $`\ulcorner \urcorner` | $`\Downarrow` | -| `|` | `\vert` | | `\ulcorner`\ | `\Downarrow` | -| | | | $`~~~~` `\urcorner` | | -+------------------+--------------------+--------------+----------------------------+---------------------+ -| $`\Vert` | $`\Vert` `\Vert` | $`└ ┘` `└ ┘` | $`\llcorner \lrcorner` | $`\Updownarrow` | -| `\|` | | | `\llcorner`\ | `\Updownarrow` | -| | | | $`~~~~` `\lrcorner` | | -+------------------+--------------------+--------------+----------------------------+---------------------+ -| $`\lvert~\rvert` | $`\lVert~\rVert` | `\left.` | `\right.` | $`\backslash` | -| `\lvert`\ | `\lVert`\ | | | `\backslash` | -| $`~~~~` `\rvert` | $`~~~~~` `\rVert` | | | | -+------------------+--------------------+--------------+----------------------------+---------------------+ -| | $`\lt\gt` `\lt`\ | $`⟦~⟧` `⟦ ⟧` | $`\llbracket~\rrbracket` | $`\lBrace~\rBrace` | -| | $`~~~~~~~~~~` | | `\llbracket`\ | `\lBrace \rBrace` | -| | `\gt` | | $`~~~~` `\rrbracket` | | -+------------------+--------------------+--------------+----------------------------+---------------------+ - -The _texvc_ extension includes $`\lang` `\lang` and $`\rang` `\rang`. - -#### Delimiter Sizing - -$`\left(\LARGE{AB}\right)` `\left(\LARGE{AB}\right)` - -$`( \big( \Big( \bigg( \Bigg(` `( \big( \Big( \bigg( \Bigg(` - -+:----------+:--------+:---------+:---------+:---------+ -| `\left` | `\big` | `\bigl` | `\bigm` | `\bigr` | -+-----------+---------+----------+----------+----------+ -| `\middle` | `\Big` | `\Bigl` | `\Bigm` | `\Bigr` | -+-----------+---------+----------+----------+----------+ -| `\right` | `\bigg` | `\biggl` | `\biggm` | `\biggr` | -+-----------+---------+----------+----------+----------+ -| | `\Bigg` | `\Biggl` | `\Biggm` | `\Biggr` | -+-----------+---------+----------+----------+----------+ - -## Environments - -+:---------------------:+:---------------------------+:--------------------------:+:-----------------------------+ -| $`\begin{matrix} | `\begin{matrix}`\ | $`\begin{array}{cc} | `\begin{array}{cc}`\ | -| a & b \\ |    `a & b \\`\ |    a & b \\ |    `a & b \\`\ | -| c & d |    `c & d`\ |    c & d |    `c & d`\ | -| \end{matrix}` | `\end{matrix}` | \end{array}` | `\end{array}` | -+-----------------------+---------------------------+----------------------------+------------------------------+ -| $`\begin{pmatrix} | `\begin{pmatrix}`\ | $`\begin{bmatrix} | `\begin{bmatrix}`\ | -| a & b \\ |    `a & b \\`\ | a & b \\ |    `a & b \\`\ | -| c & d |    `c & d`\ | c & d |    `c & d`\ | -| \end{pmatrix}` | `\end{pmatrix}` | \end{bmatrix}` | `\end{matrix}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $`\begin{vmatrix} | `\begin{vmatrix}`\ | $`\begin{Vmatrix} | `\begin{Vmatrix}`\ | -| a & b \\ |    `a & b \\`\ | a & b \\ |    `a & b \\`\ | -| c & d |    `c & d`\ | c & d |    `c & d`\ | -| \end{vmatrix}` | `\end{vmatrix}` | \end{Vmatrix}` | `\end{Vmatrix}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $`\begin{Bmatrix} | `\begin{Bmatrix}`\ | $`\def\arraystretch{1.5} | `\def\arraystretch{1.5}`\ | -| a & b \\ |    `a & b \\`\ | \begin{array}{c|c:c} | `\begin{array}{c|c:c}`\ | -| c & d |    `c & d`\ | a & b & c \\ \hline |    `a & b & c \\ \hline`\ | -| \end{Bmatrix}` | `\end{Bmatrix}` | d & e & f \\ \hdashline |    `d & e & f \\`\ | -| | | g & h & i |    `\hdashline`\ | -| | | \end{array}` |    `g & h & i`\ | -| | | | `\end{array}` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $`x = \begin{cases} | `x = \begin{cases}`\ | $`\begin{rcases} | `\begin{rcases}`\ | -| a &\text{if } b \\ |    `a &\text{if } b \\`\ | a &\text{if } b \\ |    `a &\text{if } b \\`\ | -| c &\text{if } d |    `c &\text{if } d`\ | c &\text{if } d |   `c &\text{if } d`\ | -| \end{cases}` | `\end{cases}` | \end{rcases}⇒` | `\end{rcases}⇒` | -+-----------------------+----------------------------+----------------------------+------------------------------+ -| $`\begin{smallmatrix} | `\begin{smallmatrix}`\ | $$ | `\sum_{\begin{subarray}{l}`\ | -| a & b \\ |    `a & b \\`\ | \sum_{\begin{subarray}{l} |    `i\in\Lambda\\`\ | -| c & d |    `c & d`\ | i\in\Lambda\\ |    `0 - -+:-----------------+:-----------------------+:-------------------+:--------------------------+ -| $$ | `\begin{equation}`\ | $$ | `\begin{align}`\ | -| \begin{equation} | `\begin{split}`\ | \begin{align} |    `a&=b+c \\`\ | -| \begin{split} |    `a &=b+c\\`\ | a&=b+c \\ |    `d+e&=f`\ | -| a &=b+c\\ |    `&=e+f`\ | d+e&=f | `\endalign` | -| &=e+f | `\end{split}`\ | \end{align} | | -| \end{split} | `\end{equation}` | $$ | | -| \end{equation} | | | | -| $$ | | | | -+------------------+------------------------+--------------------+---------------------------+ -| $$ | `\begin{gather}`\ | $$ | `\begin{alignat}{2}`\ | -| \begin{gather} |    `a=b \\`\ | \begin{alignat}{2} |    `10&x+ &3&y = 2 \\`\ | -| a=b \\ |    `e=b+c`\ | 10&x+ &3&y = 2 \\ |    `3&x+&13&y = 4`\ | -| e=b+c | `\end{gather}` | 3&x+&13&y = 4 | `\end{alignat}` | -| \end{gather} | | \end{alignat} | | -| $$ | | $$ | | -+------------------+------------------------+--------------------+---------------------------+ -| $$ | `\begin{CD}`\ | $$ | `\begin{multline}`\ | -| \begin{CD} | `A @>a>> B \\`\ | \begin{multline} |    `\rm uno \\`\ | -| A @>a>> B \\ | `@VbVV @AAcA \\`\ | \rm uno \\ \    `\rm dos \\`\ | -| @VbVV @AAcA\\ | `C @= D`\ | \rm dos \\ |    `\rm tres`\ | -| C @= D | `\end{CD}` | \rm tres | `\end{multline}` | -| \end{CD} | | \end{multline} | | -| $$ | | $$ | | -+------------------+------------------------+--------------------+---------------------------+ - -#### Other Temml Environments - -+:------------------------------------+:----------------------------------------------+ -| Environments | How they differ from those shown above | -+=====================================+===============================================+ -| `darray`, `dcases`, `drcases` | … apply `displaystyle` | -+-------------------------------------+-----------------------------------------------+ -| `matrix*`, `pmatrix*`, `bmatrix*`\ | … take an optional argument that sets column\ | -| `Bmatrix*`, `vmatrix*`, `Vmatrix*` | alignment, as in `\begin{matrix*}[r]` | -+-------------------------------------+-----------------------------------------------+ -| `equation*`, `gather*`\ | … have no automatic numbering. | -| `align*`, `alignat*` | | -+-------------------------------------+-----------------------------------------------+ -| `gathered`, `aligned`, `alignedat` | … do not need to be in display mode.\ | -| | … have no automatic numbering.\ | -| | … must be inside math delimiters in\ | -| | order to be rendered by the auto-render\ | -| | extension. | -+-------------------------------------+-----------------------------------------------+ - -Acceptable horizontal line separators are: `\\` and `\cr`. - -Temml supports `\tag{…}`, `\notag`, and `\nonumber` to modify equation numbering. - -The `{array}` environment does not yet support `\cline` or `\multicolumn`. - -## HTML - -The following "raw HTML" features are potentially dangerous for untrusted -inputs, so they are disabled by default, and attempting to use them produces -the command names in red (which you can configure via the `errorColor` -[option](administration.html#options)). To fully trust your LaTeX input, you need to pass -an option of `trust: true`; you can also enable just some of the commands -or for just some URLs via the `trust` [option](administration.html#options). - -+:-------------------------------------+:-----------------------------------------------+ -| $`\href{https://temml.org/}{\Temml}` | `\href{https://temml.org/}{\Temml}` | -+--------------------------------------+------------------------------------------------+ -| $`\url{https://temml.org/}` | `\url{https://temml.org/}` | -+--------------------------------------+------------------------------------------------+ -| $`\includegraphics[height=1em, | `\includegraphics[height=1em,`\ | -| totalheight=1.2em, width=1.2em, | `totalheight=1.2em,width=1.2em, alt=sphere]`\ | -| alt=sphere]{../sphere.jpg}` | `{../sphere.jpg}` | -+--------------------------------------+------------------------------------------------+ -| $`\id{idName}{x}` | `\id{idName}{x}` | -+--------------------------------------+------------------------------------------------+ -| $`\class{class-name}{x}` | `\class{class-name}{x}` | -+--------------------------------------+------------------------------------------------+ -| $`\style{color: red;}{x}` | `\style{color: red;}{x}` | -+--------------------------------------+------------------------------------------------+ -| $`\data{datum1=a, datum2=b}{x}` | `\data{datum1=a, datum2=b}{x}` | -+--------------------------------------+------------------------------------------------+ - -## Letters - -**Greek Letters** - -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\Alpha` `\Alpha` | $`\Beta` `\Beta` | $`\Gamma` `\Gamma` | $`\Delta` `\Delta` | $`\Epsilon` `\Epsilon` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\Zeta` `\Zeta` | $`\Eta` `\Eta` | $`\Theta` `\Theta` | $`\Iota` `\Iota` | $`\Kappa` `\Kappa` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\Lambda` | $`\Mu` `\Mu` | $`\Nu` `\Nu` | $`\Xi` `\Xi` | $`\Omicron` `\Omicron` | -| `\Lambda` | | | | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\Pi` `\Pi` | $`\Rho` `\Rho` | $`\Sigma` `\Sigma` | $`\Tau` `\Tau` | $`\Upsilon` `\Upsilon` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\Phi` `\Phi` | $`\Chi` `\Chi` | $`\Psi` `\Psi` | $`\Omega` `\Omega` | $`\varGamma` `\varGamma` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\varDelta` | $`\varTheta` | $`\varLambda` | $`\varXi` `\varXi` | $`\varPi` `\varPi` | -| `\varDelta` | `\varTheta` | `\varLambda` | | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\varSigma` | $`\varUpsilon` | $`\varPhi` | $`\varPsi` | $`\varOmega` `\varOmega` | -| `\varSigma` | `\varUpsilon` | `\varPhi` | `\varPsi` | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\alpha` `\alpha` | $`\beta` `\beta` | $`\gamma` `\gamma` | $`\delta` `\delta` | $`\epsilon` `\epsilon` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\zeta` `\zeta` | $`\eta` `\eta` | $`\theta` `\theta` | $`\iota` `\iota` | $`\kappa` `\kappa` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\lambda` | $`\mu` `\mu` | $`\nu` `\nu` | $`\xi` `\xi` | $`\omicron` `\omicron` | -|`\lambda` | | | | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\pi` `\pi` | $`\rho` `\rho` | $`\sigma` `\sigma` | $`\tau` `\tau` | $`\upsilon` `\upsilon` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\phi` `\phi` | $`\chi` `\chi` | $`\psi` `\psi` | $`\omega` `\omega` | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\upalpha` | $`\upbeta` | $`\upgamma` | $`\updelta` | $`\upepsilon` | -| `\upalpha` | `\upbeta` | `\upgamma` | `\updelta` | `\upepsilon` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\upzeta` | $`\upeta` | $`\uptheta` | $`\upiota` | $`\upkappa` `\upkappa` | -| `\upzeta` | `\upeta` | `\uptheta` | `\upiota` | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\uplambda` | $`\upmu` `\upmu` | $`\upnu` `\upnu` | $`\upxi` `\upxi` | $`\upomicron` | -| `\uplambda` | | | | `\upomicron` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\uppi` `\uppi` | $`\uprho` | $`\upsigma` | $`\uptau` `\uptau` | $`\upupsilon` | -| | `\uprho` | `\upsigma` | | `\upupsilon` | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\upphi` `\upphi` | $`\upchi` | $`\uppsi` `\uppsi` | $`\upomega` | | -| | `\upchi` | | `\upomega` | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\varepsilon` | $`\varkappa` | $`\vartheta` | $`\varpi` `\varpi` | $`\varrho` `\varrho` | -| `\varepsilon` | `\varkappa` | `\vartheta` | | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\varsigma` | $`\varphi` | $`\Coppa` `\Coppa` | $`\coppa` `\coppa` | $`\Koppa` `\Koppa` | -| `\varsigma` | `\varphi` | | | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\koppa` `\koppa` | $`\Sampi` | $`\sampi` `\sampi` | $`\Stigma` | $`\stigma` `\stigma` | -| | `\Sampi` | | `\Stigma` | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ -| $`\digamma` | $`\varcoppa` | | | | -| `\digamma` | `\varcoppa` | | | | -+--------------------+------------------+--------------------+--------------------+--------------------------+ - -Direct Input: Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω - α β γ δ ϵ ζ η θ ι κ λ μ ν ξ o π ρ σ τ υ ϕ χ ψ ω ε ϑ ϖ ϱ ς φ ϝ - -#### Other Letters - -+:---------------------+:-------------------+:-------------------+:---------------------------+:---------------------------+ -| $`\aleph` `\aleph` | $`\nabla` `\nabla` | $`\imath` `\imath` | $`\text{\aa}` `\text{\aa}` | $`\text{\OE}` `\text{\OE}` | -+----------------------+--------------------+--------------------+----------------------------+----------------------------+ -| $`\beth` `\beth` | $`\partial` | $`\jmath` `\jmath` | $`\text{\AA}` `\text{\AA}` | $`\text{\o}` `\text{\o}` | -| | `\partial` | | | | -+----------------------+--------------------+--------------------+----------------------------+----------------------------+ -| $`\gimel` `\gimel` | $`\Game` `\Game` | $`\Im` `\Im` | $`\text{\ae}` `\text{\ae}` | $`\text{\O}` `\text{\O}` | -+----------------------+--------------------+--------------------+----------------------------+----------------------------+ -| $`\daleth` `\daleth` | $`\Finv` `\Finv` | $`\Bbbk` `\Bbbk` | $`\text{\AE}` `\text{\AE}` | $`\text{\ss}` `\text{\ss}` | -+----------------------+--------------------+--------------------+----------------------------+----------------------------+ -| $`\eth` `\eth` | $`\hbar` `\hbar` | $`\Re` `\Re` | $`\text{\oe}` `\text{\oe}` | $`\text{\i}` `\text{\i}` | -+----------------------+--------------------+--------------------+----------------------------+----------------------------+ -| $`\ell` `\ell` | $`\hslash` | $`\wp` `\wp` | | $`\text{\j}` `\text{\j}` | -| | `\hslash` | | | | -+----------------------+--------------------+--------------------+----------------------------+----------------------------+ - -Letters in the _texvc_ extension - -+:-----------------------+:-----------------------+:-----------------------+:-------------------+:-------------------------+ -| $`\alef` `\alef` | $`\Complex` `\Complex` | $`\natnums` `\natnums` | $`\real` `\real` | $`\weierp` `\weierp` | -+------------------------+------------------------+------------------------+--------------------+--------------------------+ -| $`\alefsym` `\alefsym` | $`\image` `\image` | $`\R` `\R` | $`\reals` `\reals` | $`\thetasym` `\thetasym` | -+------------------------+------------------------+------------------------+--------------------+--------------------------+ -| $`\cnums` `\cnums` | $`\N` `\N` | $`\Reals` `\Reals` | | $`\Z` `\Z` | -+------------------------+------------------------+------------------------+--------------------+--------------------------+ - -Direct Input: ∂ ∇ ℑ Ⅎ ℵ ℶ ℷ ℸ ⅁ ℏ ð À Á Â Ã Ä Å Æ Ç È É Ê Ë -Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ù Ú Û Ü Ý Þ ß à á â ã ä å ç è é ê ë ì í î ï ð ñ ò ó ô ö ù ú û ü ý þ ÿ - ₊ ₋ ₌ ₍ ₎ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₐ ₑ ₕ ᵢ ⱼ ₖ ₗ ₘ ₙ ₒ ₚ ᵣ ₛ ₜ ᵤ ᵥ ₓ ᵦ ᵧ ᵨ ᵩ ᵪ ⁺ ⁻ ⁼ ⁽ ⁾ ⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ᵃ ᵇ ᶜ ᵈ ᵉ ᵍ ʰ ⁱ ʲ ᵏ ˡ ᵐ ⁿ ᵒ ᵖ ʳ ˢ ᵗ ᵘ ʷ ˣ ʸ ᶻ ᵛ ᵝ ᵞ ᵟ ᵠ ᵡ - -Math-mode Unicode (sub|super)script characters will render as if you had written regular -characters in a subscript or superscript. For instance, `A²⁺³` will render the same -as `A^{2+3}`. - -#### Unicode Mathematical Alphanumeric Symbols - -| Item | Range | Item | Range | -|--------------|-----------------------|-------------------|-------------------------| -| Bold | $`\text{𝐀-𝐙 𝐚-𝐳 𝟎-𝟗}` | Double-struck | $`\text{𝔸-ℤ 𝕒-𝕫 𝟘-𝟡}` | -| Italic | $`\text{𝐴-𝑍 𝑎-𝑧}` | Sans serif | $`\text{𝖠-𝖹 𝖺-𝗓 𝟢-𝟫}` | -| Bold Italic | $`\text{𝑨-𝒁 𝒂-𝒛}` | Sans serif bold | $`\text{𝗔-𝗭 𝗮-𝘇 𝟬-𝟵}` | -| Fractur | $`\text{𝔄-ℨ}\text{𝔞-𝔷}`| Sans serif italic | $`\text{𝘈-𝘡 𝘢-𝘻}` | -| Monospace | $`\text{𝙰-𝚉 𝚊-𝚣 𝟶-𝟿}` | Sans serif bold italic | $`\text{𝘼-𝙕 𝙖-𝙯}` | - -Any character can be written with the `\char` function and the Unicode code in hex. For example `\char"263a` will render as $`\char"263a`. - -
- -
For chancery or roundhand characters, it’s probably best to use \mathcal and \mathscr instead of Unicode input.
Why? -

Unicode has historically accepted either chancery or roundhand glyphs in the range U+1D49C—U+1D4B5. That's confusing, -because Cambria Math has chancery in those code points and some other math fonts have roundhand in the same code points. -Unicode 14 has recently added code points that resolve the ambiguity. Both chancery and roundhand still occupy the same range, but each unambigous chancery character has a \ufe00 appended to the code point and each unambigous roundhand character has a \ufe01 appended to the code point.

-

Published fonts have not yet caught up to the new code point assignments. If you want your documents to not break in the future, it’s probably best to avoid Unicode input and stick with \mathcal and \mathscr.

-
-
- -## Layout - -### Line Breaks - -Hard line breaks are `\\` and `\newline`. - -If the rendering options do not include annotations, Hurmet will write MathML -with soft line breaks after relations and binary operators. These soft line -breaks will appear only in Firefox. Chromium and Safari do not support soft -line breaks. - -### Vertical Layout - -+:---------------+:-------------------------------------+:---------------------------------------------------+ -| $`x_n` `x_n` | $`\stackrel{!}{=}` `\stackrel{!}{=}` | $`a\raisebox{0.25em}{b}c` `a\raisebox{0.25em}{b}c` | -+----------------+--------------------------------------+----------------------------------------------------+ -| $`e^x` `e^x` | $`\overset{!}{=}` `\overset{!}{=}` | $`M\raise3pt{M^2}M` `M\raise3pt{M^2}M` | -+----------------+--------------------------------------+----------------------------------------------------+ -| $`_u^o` `_u^o` | $`\underset{!}{=}` `\underset{!}{=}` | $`M\lower3pt{M^2}M` `M\lower3pt{M^2}M` | -+----------------+--------------------------------------+----------------------------------------------------+ -| | $`a \atop b` `a \atop b` | | -+----------------+--------------------------------------+----------------------------------------------------+ - -+:-------------------------------+:---------------------------------+ -| $$ | `\sum_{\substack{0` | ⁴∕₁₈ em space | `\mskip{distance}` | space, width = _distance_ | -| `\:` | ⁴∕₁₈ em space | `\hskip{distance}` | space, width = _distance_ | -| `\medspace` | ⁴∕₁₈ em space | `\hspace{distance}` | space, width = _distance_ | -| `\;` | ⁵∕₁₈ em space | `\hspace*{distance}` | space, width = _distance_ | -| `\thickspace` | ⁵∕₁₈ em space | `\phantom{content}` | space the width and height of content | -| `\enspace` | ½ em space | `\hphantom{content}` | space the width of content | -| `\quad` | 1 em space | `\vphantom{content}` | a strut the height of content | -| `\qquad` | 2 em space | `\!` | – ³∕₁₈ em space | -| `~` | non-breaking space | `\negthinspace` | – ³∕₁₈ em space | -| `\` | space | `\negmedspace` | – ⁴∕₁₈ em space | -| `\nobreakspace` | non-breaking space | `\negthickspace` | – ⁵∕₁₈ em space | -| `\space` | space | | | - -**Notes:** - -`distance` will accept any of the [Temml units](#units). - -`\kern`, `\mkern`, `\mskip`, and `\hskip` accept unbraced distances, as in: `\kern1em`. - -`\mkern` and `\mskip` will not work in text mode and both will write a console warning for any unit except `mu`. - -`\rule{}{distance}` is valuable as a vertical strut. - -## Logic and Set Theory - -+:-----------------------+:---------------------+:----------------------------+:-----------------------------+ -| $`\forall` `\forall` | $`\complement` | $`\therefore` | $`\emptyset` `\emptyset` | -| | `\complement` | `\therefore` | | -+------------------------+----------------------+-----------------------------+------------------------------+ -| $`\exists` `\exists` | $`\subset` `\subset` | $`\because` `\because` | $`\varnothing` `\varnothing` | -+------------------------+----------------------+-----------------------------+------------------------------+ -| $`\nexists` `\nexists` | $`\supset` `\supset` | $`\mapsto` `\mapsto` | $`\implies` `\implies` | -+------------------------+----------------------+-----------------------------+------------------------------+ -| $`\in` `\in` | $`\mid` `\mid` | $`\to` `\to` | $`\impliedby` `\impliedby` | -+------------------------+----------------------+-----------------------------+------------------------------+ -| $`\ni` `\ni` | $`\land` `\land` | $`\gets` `\gets` | $`\iff` `\iff` | -+------------------------+----------------------+-----------------------------+------------------------------+ -| $`\notin` `\notin` | $`\lor` `\lor` | $`\leftrightarrow` | $`\lightning` `\lightning` | -| | | `\leftrightarrow` | | -+------------------------+----------------------+-----------------------------+------------------------------+ -| $`\notni` `\notni` | $`\neg` `\neg` | $`\Set{ x | x<\frac 1 2 }`\ | $`\set{x|x<5 }`\ | -| | or `\lnot` | `\Set{ x | x<\frac 1 2 }` | `\set{x|x<5}` | -+------------------------+----------------------+ | | -| $`\strictif` | $`\strictfi` | | | -| `\strictif` | `\strictfi` | | | -+------------------------+----------------------+-----------------------------+------------------------------+ - -Linear Logic (from the `cmll` package): - -+-----------+----------------------+------------------------+----------------------+------------------------+ -| Operators | $` \oc ` `\oc` | $` \wn ` `\wn` | $` \with ` `\with` | $` \parr ` `\parr` | -* +----------------------+------------------------+----------------------+------------------------+ -| | $` \shpos ` `\shpos` | $` \shneg ` `\shneg` | $` \shift ` `\shift` | $` \invamp ` `\invamp` | -+-----------+----------------------+------------------------+----------------------+------------------------+ -| Relations | $` \coh ` `\coh` | $` \scoh ` `\scoh` | $` \Perp ` `\Perp` | $` \multimapboth ` | -| | | | | `\multimapboth` | -* +----------------------+------------------------+----------------------+------------------------+ -| | $` \incoh ` `\incoh` | $` \sincoh ` `\sincoh` | | $` \multimapinv ` | -| | | | | `\multimapinv` | -+-----------+----------------------+------------------------+----------------------+------------------------+ - -Equivalents in the _texvc_ extension - -+:-------------------+:-----------------+:-------------------+:---------------+ -| $`\exist` `\exist` | $`\isin` `\isin` | $`\empty` `\empty` | $`\sub` `\sub` | -+--------------------+------------------+--------------------+----------------+ - -Direct Input: ∀ ∴ ∁ ∵ ∃ ∣ ∈ ∉ ∋ ⊂ ⊃ ∧ ∨ ↦ → ← ↔ ∅ ⟹ ⟺ ¬ ↯ ⥼ ⥽\ -ℂ ℍ ℕ ℙ ℚ ℝ - -## Macros - -+:---------------------------------+:--------------------------------------------------------+ -| $`\def\foo#1#2{#1^2 #2^3} | `\def\macroname{definition to be expanded}` \ | -| \foo a b + \foo c d` | `\def\foo#1#2{#1^2 #2^3}` \ | -| | `\foo a b + \foo c d` | -+----------------------------------+---------------------------------------------------------+ -| | `\edef\macroname#1#2…{definition}` | -+----------------------------------+---------------------------------------------------------+ -| | `\let\foo=\bar` | -+----------------------------------+---------------------------------------------------------+ -| | `\futurelet\foo\bar x` | -+----------------------------------+---------------------------------------------------------+ -| $`\newcommand\foo[2]{#1^2 #2^3} | `\newcommand\macroname[numargs]{definition}` \ | -| \foo a b + \foo c d` | `\newcommand\foo[2]{#1^2 #2^3}` \ | -| | `\foo a b + \foo c d` | -+----------------------------------+---------------------------------------------------------+ -| | `\renewcommand\macroname[numargs]{definition}` | -+----------------------------------+---------------------------------------------------------+ -| | `\providecommand\macroname[numargs]{definition}` | -+----------------------------------+---------------------------------------------------------+ - -To create macros with document-wide scope, a [preamble](./administration.html#preamble) can be defined -as one of the Temml [rendering options](./administration.html#options) - -Macros accept up to nine arguments: #1, #2, etc. - -Available functions include: - -`\char` `\mathchoice` `\TextOrMath` `\@ifstar` `\@ifnextchar` `\@firstoftwo` `\@secondoftwo` `\relax` `\expandafter` `\noexpand` - -@ is a valid character for commands, as if `\makeatletter` were in effect. - -Temml macros do not escape their group, so `\gdef`, `\xdef`, and`\global` are not supported. -Temml has no `\par`, so `\long` is ignored. - -## Numbers - -Temml’s default mode will consolidate a string of numerals into a single MathML -`` element. This applies to any string that begins and ends with a digit -(0-9) and includes digits, commas, or dots. Example: `2,000.00`. - -In strict mode, Temml acts like LaTeX and treats each digit individually. This -is not as nice semantically, but it does maintain backwards compatibility for -LaTeX macros. - -## Operators - -### Big Operators - -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\sum` `\sum` | $`\prod` `\prod` | $`\bigotimes` `\bigotimes` | $`\bigvee` `\bigvee` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\int` `\int` | $`\coprod` `\coprod` | $`\bigoplus` `\bigoplus` | $`\bigwedge` `\bigwedge` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\iint` `\iint` | $`\intop` `\intop` | $`\bigodot` `\bigodot` | $`\bigcap` `\bigcap` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\iiint` `\iiint` | $`\smallint` `\smallint` | $`\biguplus` `\biguplus` | $`\bigcup` `\bigcup` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\iiiint` `\iiiint` | $`\intcap` `\intcap` | $`\intcup` `\intcup` | $`\bigsqcup` `\bigsqcup` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\oint` `\oint` | $`\varointclockwise` | $`\intclockwise` | $`\bigsqcap` | -| | `\varointclockwise` | `\intclockwise` | `\bigsqcap` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\oiint` `\oiint` | $`\pointint` `\pointint` | $`\rppolint` `\rppolint` | $`\scpolint` `\scpolint` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\oiiint` `\oiiint` | $`\intlarhk` `\intlarhk` | $`\sqint` `\sqint` | $`\intx` `\intx` | -+----------------------+--------------------------+----------------------------+-------------------------------+ -| $`\intbar` `\intbar` | $`\intBar` `\intBar` | $`\fint` `\fint` | $`\sideset{_a^b}{_c^d}\sum` | -| | | | `\sideset{_a^b}{_c^d}\sum` | -+----------------------+--------------------------+----------------------------+-------------------------------+ - -Direct Input: ∫ ∬ ∭ ⨌ ∮ ∯ ∰ ⨖ ∲ ∏ ∐ ∑ ⋀ ⋁ ⋂ ⋃ ⨀ ⨁ ⨂ ⨄ ⨆ ⨅ - -### Binary Operators - -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` + ` `+` | $` \cdot ` `\cdot` | $` \gtrdot ` `\gtrdot` | $` x \pmod a ` `x \pmod | -| | | | a` | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` - ` `-` | $` \cdotp ` `\cdotp` | $` \intercal ` | $` x \pod a ` `x \pod a` | -| | | `\intercal` | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` / ` `/` | $`\centerdot` | $` \land ` `\land` | $` \rhd ` `\rhd` | -| | `\centerdot` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` * ` `*` | $` \circ ` `\circ` | $` \leftthreetimes ` | $` \rightthreetimes ` | -| | | `\leftthreetimes` | `\rightthreetimes` | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \amalg ` `\amalg` | $` \circledast ` | $` \ldotp ` `\ldotp` | $` \rtimes ` `\rtimes` | -| | `\circledast` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \And ` `\And` | $` \circledcirc ` | $` \lor ` `\lor` | $` \setminus ` | -| | `\circledcirc` | | `\setminus` | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \ast ` `\ast` | $` \circleddash ` | $` \lessdot ` `\lessdot` | $` \smallsetminus ` | -| | `\circleddash` | | `\smallsetminus` | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \barwedge ` | $` \Cup ` `\Cup` | $` \lhd ` `\lhd` | $` \sqcap ` `\sqcap` | -| `\barwedge` | | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \bigcirc ` `\bigcirc` | $` \cup ` `\cup` | $` \ltimes ` `\ltimes` | $` \sqcup ` `\sqcup` | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \bmod ` `\bmod` | $` \curlyvee ` | $` x \mod a ` `x\mod a` | $` \times ` `\times` | -| | `\curlyvee` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \boxdot ` `\boxdot` | $` \curlywedge ` | $` \mp ` `\mp` | $` \unlhd ` `\unlhd` | -| | `\curlywedge` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \boxminus ` | $` \div ` `\div` | $` \odot ` `\odot` | $` \unrhd ` `\unrhd` | -| `\boxminus` | | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \boxplus ` `\boxplus` | $` \divideontimes ` | $` \ominus ` `\ominus` | $` \uplus ` `\uplus` | -| | `\divideontimes` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \boxtimes ` | $` \dotplus ` `\dotplus` | $` \oplus ` `\oplus` | $` \vee ` `\vee` | -| `\boxtimes` | | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \bullet ` `\bullet` | $` \doublebarwedge ` | $` \otimes ` `\otimes` | $` \veebar ` `\veebar` | -| | `\doublebarwedge` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \Cap ` `\Cap` | $` \doublecap ` | $` \oslash ` `\oslash` | $` \wedge ` `\wedge` | -| | `\doublecap` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| $` \cap ` `\cap` | $` \doublecup ` | $` \parr ` ` \parr ` | $` \with ` ` \with ` | -| | `\doublecup` | | | -+--------------------------+--------------------------+--------------------------+--------------------------+ -| | | $` \pm ` `\pm` | $` \wr ` `\wr` | -+--------------------------+--------------------------+--------------------------+--------------------------+ - -The _texvc_ extension provides $`\plusmn` `\plusmn`. - -Direct Input: + - / ∖ * ⋅ ∘ ± × ÷ ∓ ∔ ∧ ∨ ∩ ∪ ≀ ⊎ ⊓ ⊔ ⊕ ⊖ ⊗ ⊘ ⊙ ⊚ ⊛ ⊝ ◯ - -### Fractions and Binomials - -+:----------------+:-----------------+:-------------------------------+ -| $`\frac{a}{b}` | $`\tfrac{a}{b}` | $`\genfrac ( ] {2pt}{1}a{a+1}` | -| `\frac{a}{b}` | `\tfrac{a}{b}` | `\genfrac ( ] {2pt}{1}a{a+1}` | -+-----------------+------------------+--------------------------------+ -| $`{a \over b}` | $`\dfrac{a}{b}` | $`{a \above{2pt} b+1}` | -| `{a \over b}` | `\dfrac{a}{b}` | `{a \above{2pt} b+1}` | -+-----------------+------------------+--------------------------------+ -| $`a/b` `a/b` | | $`\cfrac{a}{1 + \cfrac{1}{b}}` | -| | | `\cfrac{a}{1 + \cfrac{1}{b}}` | -+-----------------+------------------+--------------------------------+ - -+:---------------------------------+:---------------------------------+:-----------------------------+ -| $`\binom{n}{k}` `\binom{n}{k}` | $`\dbinom{n}{k}` `\dbinom{n}{k}` | $`{n\brace k}` `{n\brace k}` | -+----------------------------------+----------------------------------+------------------------------+ -| $`{n \choose k}` `{n \choose k}` | $`\tbinom{n}{k}` `\tbinom{n}{k}` | $`{n\brack k}` `{n\brack k}` | -+----------------------------------+----------------------------------+------------------------------+ - -### Math Operators - -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \operatorname{f} ` | $` \cosec ` `\cosec` | $` \dim ` `\dim` | $`\pdv*{f}{x,y}` | -| `\operatorname{f}` | | | `\pdv*{f}{x,y}` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \arcsin ` `\arcsin` | $` \cosh ` `\cosh` | $` \exp ` `\exp` | $` \sec ` `\sec` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \arccos ` `\arccos` | $` \cot ` `\cot` | $` \hom ` `\hom` | $` \sgn ` `\sgn` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \arctan ` `\arctan` | $` \cotg ` `\cotg` | $` \ker ` `\ker` | $` \sin ` `\sin` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \arctg ` `\arctg` | $` \coth ` `\coth` | $` \lg ` `\lg` | $` \sinh ` `\sinh` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \arcctg ` `\arcctg` | $` \csc ` `\csc` | $` \ln ` `\ln` | $` \sh ` `\sh` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \arg ` `\arg` | $` \ctg ` `\ctg` | $` \log ` `\log` | $` \tan ` `\tan` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \ch ` `\ch` | $` \cth ` `\cth` | $`\odv{f}{x}` `\odv{f}{x}` | $` \tanh ` `\tanh` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \cos ` `\cos` | $` \nabla ` `\nabla` | $`\odv*{f}{x}` `\odv*{f}{x}` | $` \tg ` `\tg` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \partial ` `\partial` | $` \deg ` `\deg` | $`\pdv{f}{x,y}` `\pdv{f}{x,y}` | $` \th ` `\th` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \operatorname*{f} ` | $` \inf ` `\inf` | $` \max ` `\max` | $` \sup ` `\sup` | -| `\operatorname*{f}` or\ | | | | -| `\operatornamewithlimits` | | | | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \argmax ` `\argmax` | $` \injlim ` `\injlim` | $` \min ` `\min` | $` \varinjlim ` | -| | | | `\varinjlim` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \argmin ` `\argmin` | $` \lim ` `\lim` | $` \plim ` `\plim` | $` \varliminf ` | -| | | | `\varliminf` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \det ` `\det` | $` \liminf ` `\liminf` | $` \Pr ` `\Pr` | $` \varlimsup ` | -| | | | `\varlimsup` | -+---------------------------+------------------------+--------------------------------+--------------------+ -| $` \gcd ` `\gcd` | $` \limsup ` `\limsup` | $` \projlim ` `\projlim` | $` \varprojlim ` | -| | | | `\varprojlim` | -+---------------------------+------------------------+--------------------------------+--------------------+ - -Functions in the bottom five rows of this table can take `\limits`. - -### Enclosing Operators - -+:-------------------------------+:-----------------------------------------------------+ -| $`\sqrt{x}` `\sqrt{x}` | $`\longdiv{3x^2 + 2x + 5}` `\longdiv{3x^2 + 2x + 5}` | -+--------------------------------+------------------------------------------------------+ -| $`\sqrt[3]{x}` `\sqrt[3]{x}` | $`\phase{-78^\circ}` `\phase{-78^\circ}` | -+--------------------------------+------------------------------------------------------+ -| $`a_{\angl n}`   `a_{\angl n}` | $`a_\angln`   `a_\angln` | -+--------------------------------+------------------------------------------------------+ - -## Physics and Chemistry - -+:---------------------------+:-------------------------------------------------------------+ -| $`\bra{\phi}` `\bra{\phi}` | $`\prescript{a}{2}{\mathbf{C}}^{5+}_{2}` | -| | `\prescript{a}{2}{\mathbf{C}}^{5+}_{2}` | -+----------------------------+--------------------------------------------------------------+ -| $`\ket{\psi}` `\ket{\psi}` | $`\braket{\phi\vert\psi}` | -| | `\braket{\phi\vert\psi}` | -+----------------------------+--------------------------------------------------------------+ -| $`\Bra{\phi}` `\Bra{\phi}` | $`\Braket{ \phi | \frac{\partial^2}{\partial t^2} | \psi }`\ | -| | `\Braket{ \phi | \frac{\partial^2}{\partial t^2} | \psi }` | -+----------------------------+ + -| $`\Ket{\psi}` `\Ket{\psi}` | | -+----------------------------+--------------------------------------------------------------+ - -From the _mhchem_ extension: - -+:----------------------------------+:---------------------------------+ -| $`\ce{SO4^2- + Ba^2+ -> BaSO4 v}` | `\ce{SO4^2- + Ba^2+ -> BaSO4 v}` | -+-----------------------------------+----------------------------------+ -| $`\pu{75.3 J // mol K}` | `\pu{75.3 J // mol K}` | -+-----------------------------------+----------------------------------+ - -

There is much more mhchem information in the -mhchem docs.

- -
- -
Click to see the physics extension. - -+:--------------------------------+:----------------------------+:-------------------------+ -| $`\abs{x}` `\abs{x}` | $`\innerproduct{a}{b}` | $`\qif` `\qif` | -| | `\innerproduct{a}{b}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\absolutevalue{x}` | $`\ketbra{a}{b}` | $`\qin` `\qin` | -| `\absolutevalue{x}` | `\ketbra{a}{b}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\acomm{A}{B}` `\acomm{A}{B}` | $`\laplacian` | $`\qinteger` `\qinteger` | -| | `\laplacian` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\anticommutator{A}{B}` | $`\matrixel{n}{A}{m}` | $`\qlet` `\qlet` | -| `\anticommutator{A}{B}` | `\matrixel{n}{A}{m}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\Bqty{5 \text{mm}}` | $`\matrixelement{n}{A}{m}` | $`\qodd` `\qodd` | -| `\Bqty{5 \text{mm}}` | `\matrixelement{n}{A}{m}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\bqty{5 \text{mm}}` | $`\mel{n}{A}{m}` | $`\qor` `\qor` | -| `\bqty{5 \text{mm}}` | `\mel{n}{A}{m}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\comm{A}{B}` `\comm{A}{B}` | $`\norm{x}` `\norm{x}` | $`\qotherwise` | -| | | `\qotherwise` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\commutator{A}{B}` | $`\op{a}{b}` `\op{a}{b}` | $`\qq{text}` `\qq{text}` | -| `\commutator{A}{B}` | | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\cp` `\cp` | $`\order{x^2}` | $`\qqtext{text}` | -| | `\order{x^2}` | `\qqtext{text}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\cross` `\cross` | $`\outerproduct{a}{b}` | $`\qsince` `\qsince` | -| | `\outerproduct{a}{b}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\crossproduct` | $`\partialderivative{x}{y}` | $`\qthen` `\qthen` | -| `\crossproduct` | `\partialderivative{x}{y}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\curl` `\curl` | $`\pb{x}{y}` `\pb{x}{y}` | $`\qty{5 \text{m}}` | -| | | `\qty{5 \text{m}}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\dd` `\dd` | | $`\quantity{5 \text{m}}` | -| | | `\quantity{5 \text{m}}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\derivative{x}{y}` | $`\poissonbracket{A}{B}` | $`\qunless` `\qunless` | -| `\derivative{x}{y}` | `\poissonbracket{A}{B}` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\differential` | $`\pqty{5}` `\pqty{5}` | $`\qusing` `\qusing` | -| `\differential` | | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\divergence` `\divergence` | $`\principalvalue` | $`\rank M` `\rank M` | -| | `\principalvalue` | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\dotproduct` `\dotproduct` | $`\pv` `\pv` | $`\Res[f(z)]` | -| | | `\Res\[f(z)\]` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\dv{x}{y}` `\dv{x}{y}` | $`\PV(x)` `\PV(x)` | $`\Tr\rho` `\Tr\rho` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\dyad{a}{b}` `\dyad{a}{b}` | $`\qall` `\qall` | $`\tr\rho` `\tr\rho` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\erf(x)` `\erf(x)` | $`\qand` `\qand` | $`\va{a}` `\va{a}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\ev{x}` `\ev{x}` | $`\qas` `\qas` | $`\var` `\var` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\eval{\tfrac 1 2 x}_0^n` | $`\qassume` `\qassume` | $`\variation` | -| `\eval{\tfrac 1 2 x}_0^n` | | `\variation` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\evaluated{\tfrac 1 2 x}_0^n` | $`\qc` `\qc` | $`\vb{a}` `\vb{a}` | -| `\evaluated{\tfrac 1 2 x}_0^n` | | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\expectationvalue{x}` | $`\qcc` `\qcc` | $`\vdot` `\vdot` | -| `\expectationvalue{x}` | | | -+---------------------------------+-----------------------------+--------------------------+ -| $`\expval{x}` `\expval{x}` | $`\qcomma` `\qcomma` | $`\vectorarrow{a}` | -| | | `\vectorarrow{a}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\fdv{x}{y}` `\fdv{x}{y}` | $`\qelse` `\qelse` | $`\vectorbold{a}` | -| | | `\vectorbold{a}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\functionalderivative{x}{y}` | $`\qeven` `\qeven` | $`\vectorunit{a}` | -| `\functionalderivative{x}{y}` | | `\vectorunit{a}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\grad` `\grad` | $`\qfor` `\qfor` | $`\vqty{x}` `\vqty{x}` | -+---------------------------------+-----------------------------+--------------------------+ -| $`\gradient` `\gradient` | $`\qgiven` `\qgiven` | $`\vu{a}` `\vu{a}` | -+---------------------------------+-----------------------------+--------------------------+ - -
- -## Relations - -$`\stackrel{!}{=}\vphantom{\frac a b}` `\stackrel{!}{=}` - -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` = ` `=` | $` \eqcirc ` `\eqcirc` | $` \lesseqqgtr ` | $` \smallsmile ` | -| | | `\lesseqqgtr` | `\smallsmile` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` < ` `<` | $` \eqcolon ` `\eqcolon` | $` \lessgtr ` `\lessgtr` | $` \smile ` `\smile` | -| | or\ | | | -| |   `\minuscolon` | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` > ` `>` | $` \Eqcolon ` `\Eqcolon` | $` \lesssim ` `\lesssim` | $` \sqsubset ` | -| | or\ | | `\sqsubset` | -| |    `\minuscoloncolon` | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` : ` `:` | $` \eqqcolon ` | $` \ll ` `\ll` | $` \sqsubseteq ` | -| | `\eqqcolon` | | `\sqsubseteq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` := ` `:=` | $` \Eqqcolon ` | $` \lll ` `\lll` | $` \sqsupset ` | -| | `\Eqqcolon` | | `\sqsupset` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \approx ` `\approx` | $` \eqdef ` `\eqdef` | $` \llless ` `\llless` | $` \sqsupseteq ` | -| | | | `\sqsupseteq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \approxeq ` | $` \eqsim ` `\eqsim` | $` \lt ` `\lt` | $` \stareq ` `\stareq` | -| `\approxeq` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \arceq ` `\arceq` | $` \eqslantgtr ` | $` \measeq ` `\measeq` | $` \Subset ` `\Subset` | -| | `\eqslantgtr` | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \asymp ` `\asymp` | $` \eqslantless ` | $` \mid ` `\mid` | $` \subset ` `\subset` | -| | `\eqslantless` | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \backcong ` | $` \equiv ` `\equiv` | $` \models ` `\models` | $` \subseteq ` | -| `\backcong` | | | `\subseteq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \backepsilon ` | $` \fallingdotseq ` | $` \multimap ` | $` \subseteqq ` | -| `\backepsilon` | `\fallingdotseq` | `\multimap` | `\subseteqq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \backsim ` `\backsim` | $` \frown ` `\frown` | $`\multimapboth ` `\multimapboth` | $` \succ ` `\succ` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \backsimeq ` | $` \ge ` `\ge` | $`\multimapinv ` `\multimapinv` | $` \succapprox ` | -| `\backsimeq` | | | `\succapprox` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \between ` `\between` | $` \geq ` `\geq` | $` \origof ` `\origof` | $` \succcurlyeq ` | -| | | | `\succcurlyeq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \bowtie ` `\bowtie` | $` \geqq ` `\geqq` | $` \owns ` `\owns` | $` \succeq ` `\succeq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \bumpeq ` `\bumpeq` | $` \geqslant ` | $` \parallel ` | $` \succsim ` `\succsim` | -| | `\geqslant` | `\parallel` | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \Bumpeq ` `\Bumpeq` | $` \gg ` `\gg` | $` \perp ` `\perp` | $` \Supset ` `\Supset` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \circeq ` `\circeq` | $` \ggg ` `\ggg` | $` \Perp ` `\Perp` | $` \supset ` `\supset` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \coh ` `\coh` | $` \gggtr ` `\gggtr` | $` \pitchfork ` | $` \supseteq ` | -| | | `\pitchfork` | `\supseteq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \colonapprox ` | $` \gt ` `\gt` | $` \prec ` `\prec` | $` \supseteqq ` | -| `\colonapprox` | | | `\supseteqq` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \Colonapprox ` | $` \gtrapprox ` | $` \precapprox ` | $` \thickapprox ` | -| `\Colonapprox` or\ | `\gtrapprox` | `\precapprox` | `\thickapprox` | -|    `\coloncolonapprox` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \coloneq ` `\coloneq` | $` \gtreqless ` | $` \preccurlyeq ` | $` \thicksim ` | -| or\ | `\gtreqless` | `\preccurlyeq` | `\thicksim` | -|    `\colonminus` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \Coloneq ` `\Coloneq` | $` \gtreqqless ` | $` \preceq ` `\preceq` | $` \trianglelefteq ` | -| or\ | `\gtreqqless` | | `\trianglelefteq` | -|    `\coloncolonminus` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \coloneqq ` | $` \gtrless ` `\gtrless` | $` \precsim ` `\precsim` | $` \triangleq ` | -| `\coloneqq` or\ | | | `\triangleq` | -|    `\colonequals` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \Coloneqq ` | $` \gtrsim ` `\gtrsim` | $` \propto ` `\propto` | $` \trianglerighteq ` | -| `\Coloneqq` or \ | | | `\trianglerighteq` | -|     `\coloncolonequals` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \colonsim ` | $` \imageof ` `\imageof` | $` \questeq ` `\questeq` | $` \varpropto ` | -| `\colonsim` | | | `\varpropto` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \Colonsim ` | $` \in ` `\in` or `\isin` | :`\ratio` or\ | $` \vartriangle ` | -| `\Colonsim` or\ | |   `\vcentcolon` | `\vartriangle` | -|    `\coloncolonsim` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \cong ` `\cong` | $` \incoh ` `\incoh` | $` \risingdotseq ` | $` \vartriangleleft ` | -| | | `\risingdotseq` | `\vartriangleleft` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \curlyeqprec ` | $` \Join ` `\Join` | $` \scoh ` `\scoh` | $` \vartriangleright ` | -| `\curlyeqprec` | | | `\vartriangleright` | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \curlyeqsucc ` | $` \le ` `\le` | $` \shortmid ` | $` \vdash ` `\vdash` | -| `\curlyeqsucc` | | `\shortmid` | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \dashv ` `\dashv` | $` \leq ` `\leq` | $` \shortparallel ` | $` \vDash ` `\vDash` | -| | | `\shortparallel` | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \dblcolon ` | $` \leqq ` `\leqq` | $` \sim ` `\sim` | $` \Vdash ` `\Vdash` | -| `\dblcolon` or\ | | | | -|    `\coloncolon` | | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \doteq ` `\doteq` | $` \leqslant ` | $` \simeq ` `\simeq` | $` \Vvdash ` `\Vvdash` | -| | `\leqslant` | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \Doteq ` `\Doteq` | $` \lessapprox ` | $` \sincoh ` `\sincoh` | $` \veeeq ` `\veeeq` | -| | `\lessapprox` | | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ -| $` \doteqdot ` | $` \lesseqgtr ` | $` \smallfrown ` | $` \wedgeq ` `\wedgeq` | -| `\doteqdot` | `\lesseqgtr` | `\smallfrown` | | -+---------------------------+---------------------------+-----------------------------------+--------------------------+ - -The _texvc_ extension provides $`\sub` `\sub`, $`\sube` `\sube`, and $`\supe` `\supe`. - -Direct Input: = < > : ∈ ∋ ∝ ∼ ∽ ≂ ≃ ≅ ≈ ≊ ≍ ≎ ≏ ≐ ≑ ≒ ≓ ≖ -≗ ≜ ≡ ≤ ≥ ≦ ≧ ≫ ≬ ≳ ≷ ≺ ≻ ≼ ≽ ≾ ≿ ⊂ ⊃ ⊆ ⊇ ⊏ ⊐ ⊑ ⊒ ⊢ ⊣ ⊩ ⊪ ⊸ ⋈ ⋍ ⋐ ⋑ ⋔ ⋙ -⋛ ⋞ ⋟ ⌢ ⌣ ⩾ ⪆ ⪌ ⪕ ⪖ ⪯ ⪰ ⪷ ⪸ ⫅ ⫆ ≲ ⩽ ⪅ ≶ ⋚ ⪋ ⟂ ⊨ ≔ ≕ ⩴ ⊷ ⊶ - -### Negated Relations - -$`\not =` `\not =` - -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \gnapprox ` | $` \ngeqslant ` | $` \nsubset ` | $` \nVdash ` `\nVdash` | -| `\gnapprox` | `\ngeqslant` | ` \nsubset ` | | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \gneq ` `\gneq` | $` \ngtr ` `\ngtr` | $` \nsubseteq ` | $` \precnapprox ` | -| | | `\nsubseteq` | `\precnapprox` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \gneqq ` `\gneqq` | $` \nleq ` `\nleq` | $` \nsubseteqq ` | $` \precneqq ` | -| | | `\nsubseteqq` | `\precneqq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \gnsim ` `\gnsim` | $` \nleqq ` `\nleqq` | $` \nsucc ` `\nsucc` | $` \precnsim ` | -| | | | `\precnsim` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \gvertneqq ` | $` \nleqslant ` | $` \nsucceq ` `\nsucceq` | $` \subsetneq ` | -| `\gvertneqq` | `\nleqslant` | | `\subsetneq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \lnapprox ` | $` \nless ` `\nless` | $` \nsupset ` | $` \subsetneqq ` | -| `\lnapprox` | | ` \nsupset ` | `\subsetneqq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \lneq ` `\lneq` | $` \nmid ` `\nmid` | $` \nsupseteq ` | $` \succnapprox ` | -| | | `\nsupseteq` | `\succnapprox` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \lneqq ` `\lneqq` | $` \notin ` `\notin` | $` \nsupseteqq ` | $` \succneqq ` | -| | | `\nsupseteqq` | `\succneqq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \lnsim ` `\lnsim` | $` \notni ` `\notni` | $` \ntriangleleft ` | $` \succnsim ` | -| | | `\ntriangleleft` | `\succnsim` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \lvertneqq ` | $` \nparallel ` | $` \ntrianglelefteq ` | $` \supsetneq ` | -| `\lvertneqq` | `\nparallel` | `\ntrianglelefteq` | `\supsetneq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \ncong ` `\ncong` | $` \nprec ` `\nprec` | $` \ntriangleright ` | $` \supsetneqq ` | -| | | `\ntriangleright` | `\supsetneqq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \ne ` `\ne` | $` \npreceq ` `\npreceq` | $` \ntrianglerighteq ` | $` \varsubsetneq ` | -| | | `\ntrianglerighteq` | `\varsubsetneq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \neq ` `\neq` | $` \nshortmid ` | $` \nvdash ` `\nvdash` | $` \varsubsetneqq ` | -| | `\nshortmid` | | `\varsubsetneqq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \ngeq ` `\ngeq` | $` \nshortparallel ` | $` \nvDash ` `\nvDash` | $` \varsupsetneq ` | -| | `\nshortparallel` | | `\varsupsetneq` | -+----------------------+---------------------------+--------------------------+------------------------+ -| $` \ngeqq ` `\ngeqq` | $` \nsim ` `\nsim` | $` \nVDash ` `\nVDash` | $` \varsupsetneqq ` | -| | | | `\varsupsetneqq` | -+----------------------+---------------------------+--------------------------+------------------------+ - -Direct Input: ∉ ∌ ∤ ∦ ≁ ≆ ≠ ≨ ≩ ≮ ≯ ≰ ≱ ⊀ ⊁ ⊄ ⊅ ⊈ ⊉ ⊊ ⊋ ⊬ ⊭ -⊮ ⊯ ⋠ ⋡ ⋦ ⋧ ⋨ ⋩ ⋬ ⋭ ⪇ ⪈ ⪉ ⪊ ⪵ ⪶ ⪹ ⪺ ⫋ ⫌ - -### Arrows - -+------------------------+-------------------------+------------------------+ -| $`\circlearrowleft` | $`\Leftrightarrow` | $`\rightarrow` | -| `\circlearrowleft` | `\Leftrightarrow` | `\rightarrow` | -+------------------------+-------------------------+------------------------+ -| $`\circlearrowright` | $`\leftrightarrows` | $`\Rightarrow` | -| `\circlearrowright` | `\leftrightarrows` | `\Rightarrow` | -+------------------------+-------------------------+------------------------+ -| $`\curvearrowleft` | $`\leftrightharpoons` | $`\rightarrowtail` | -| `\curvearrowleft` | `\leftrightharpoons` | `\rightarrowtail` | -+------------------------+-------------------------+------------------------+ -| $`\curvearrowright` | $`\leftrightsquigarrow` | $`\rightharpoondown` | -| `\curvearrowright` | `\leftrightsquigarrow` | `\rightharpoondown` | -+------------------------+-------------------------+------------------------+ -| $`\dashleftarrow` | $`\Lleftarrow` | $`\rightharpoonup` | -| `\dashleftarrow` | `\Lleftarrow` | `\rightharpoonup` | -+------------------------+-------------------------+------------------------+ -| $`\dashrightarrow` | $`\longleftarrow` | $`\rightleftarrows` | -| `\dashrightarrow` | `\longleftarrow` | `\rightleftarrows` | -+------------------------+-------------------------+------------------------+ -| $`\downarrow` | $`\Longleftarrow` | $`\rightleftharpoons` | -| `\downarrow` | `\Longleftarrow` | `\rightleftharpoons` | -+------------------------+-------------------------+------------------------+ -| $`\Downarrow` | $`\longleftrightarrow` | $`\rightrightarrows` | -| `\Downarrow` | `\longleftrightarrow` | `\rightrightarrows` | -+------------------------+-------------------------+------------------------+ -| $`\downdownarrows` | $`\Longleftrightarrow` | $`\rightsquigarrow` | -| `\downdownarrows` | `\Longleftrightarrow` | `\rightsquigarrow` | -+------------------------+-------------------------+------------------------+ -| $`\downharpoonleft` | $`\longmapsto` | $`\Rrightarrow` | -| `\downharpoonleft` | `\longmapsto` | `\Rrightarrow` | -+------------------------+-------------------------+------------------------+ -| $`\downharpoonright` | $`\longrightarrow` | $`\Rsh` `\Rsh` | -| `\downharpoonright` | `\longrightarrow` | | -+------------------------+-------------------------+------------------------+ -| $`\gets` `\gets` | $`\Longrightarrow` | $`\searrow` `\searrow` | -| | `\Longrightarrow` | | -+------------------------+-------------------------+------------------------+ -| $`\hookleftarrow` | $`\looparrowleft` | $`\swarrow` `\swarrow` | -| `\hookleftarrow` | `\looparrowleft` | | -+------------------------+-------------------------+------------------------+ -| $`\hookrightarrow` | $`\looparrowright` | $`\to` `\to` | -| `\hookrightarrow` | `\looparrowright` | | -+------------------------+-------------------------+------------------------+ -| $`\iff` `\iff` | $`\Lsh` `\Lsh` | $`\twoheadleftarrow` | -| | | `\twoheadleftarrow` | -+------------------------+-------------------------+------------------------+ -| $`\impliedby` | $`\mapsto` `\mapsto` | $`\twoheadrightarrow` | -| `\impliedby` | | `\twoheadrightarrow` | -+------------------------+-------------------------+------------------------+ -| $`\implies` `\implies` | $`\nearrow` `\nearrow` | $`\uparrow` `\uparrow` | -+------------------------+-------------------------+------------------------+ -| $`\leadsto` `\leadsto` | $`\nleftarrow` | $`\Uparrow` `\Uparrow` | -| | `\nleftarrow` | | -+------------------------+-------------------------+------------------------+ -| $`\leftarrow` | $`\nLeftarrow` | $`\updownarrow` | -| `\leftarrow` | `\nLeftarrow` | `\updownarrow` | -+------------------------+-------------------------+------------------------+ -| $`\Leftarrow` | $`\nleftrightarrow` | $`\Updownarrow` | -| `\Leftarrow` | `\nleftrightarrow` | `\Updownarrow` | -+------------------------+-------------------------+------------------------+ -| $`\leftarrowtail` | $`\nLeftrightarrow` | $`\upharpoonleft` | -| `\leftarrowtail` | `\nLeftrightarrow` | `\upharpoonleft` | -+------------------------+-------------------------+------------------------+ -| $`\leftharpoondown` | $`\nrightarrow` | $`\upharpoonright` | -| `\leftharpoondown` | `\nrightarrow` | `\upharpoonright` | -+------------------------+-------------------------+------------------------+ -| $`\leftharpoonup` | $`\nRightarrow` | $`\upuparrows` | -| `\leftharpoonup` | `\nRightarrow` | `\upuparrows` | -+------------------------+-------------------------+------------------------+ -| $`\leftleftarrows` | $`\nwarrow` `\nwarrow` | | -| `\leftleftarrows` | | | -+------------------------+-------------------------+------------------------+ -| $`\leftrightarrow` | $`\restriction` | | -| `\leftrightarrow` | `\restriction` | | -+------------------------+-------------------------+------------------------+ - -Arrows in the _texvc_ extension - -+:-----------------+:-----------------+:-----------------+:-------------------+:-----------------+:-----------------+ -| $`\Darr` `\Darr` | $`\Harr` `\Harr` | $`\Larr` `\Larr` | $`\Lrarr` `\Lrarr` | $`\Rarr` `\Rarr` | $`\Uarr` `\Uarr` | -+------------------+------------------+------------------+--------------------+------------------+------------------+ -| $`\dArr` `\dArr` | $`\hArr` `\hArr` | $`\lArr` `\lArr` | $`\lrArr` `\lrArr` | $`\rArr` `\rArr` | $`\uArr` `\uArr` | -+------------------+------------------+------------------+--------------------+------------------+------------------+ -| $`\darr` `\darr` | $`\harr` `\harr` | $`\larr` `\larr` | $`\lrarr` `\lrarr` | $`\rarr` `\rarr` | $`\uarr` `\uarr` | -+------------------+------------------+------------------+--------------------+------------------+------------------+ - -Direct Input: ← ↑ → ↓ ↔ ↕ ↖ ↗ ↘ ↙ ↚ ↛ ↞ ↠ ↢ ↣ ↦ ↩ ↪ ↫ ↬ ↭ ↮ ↰ ↱↶ ↷ ↺ ↻ ↼ ↽ ↾ ↾ ↿ ⇀ ⇁ ⇂ ⇃ ⇄ ⇆ ⇇ ⇈ ⇉ ⇊ ⇋ ⇌⇍ ⇎ ⇏ ⇐ ⇑ ⇒ ⇓ ⇔ ⇕ ⇚ ⇛ ⇝ ⇠ ⇢ ⟵ ⟶ ⟷ ⟸ ⟹ ⟺ ⟼ ↽ - -### Extensible Arrows - -+:-------------------------------------------------------+:---------------------------------------------------------+ -| $`\xleftarrow{abc}` `\xleftarrow{abc}` | $`\xrightarrow[under]{over}` `\xrightarrow[under]{over}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xLeftarrow{abc}` `\xLeftarrow{abc}` | $`\xRightarrow{abc}` `\xRightarrow{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xleftrightarrow{abc}` `\xleftrightarrow{abc}` | $`\xLeftrightarrow{abc}` `\xLeftrightarrow{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xhookleftarrow{abc}` `\xhookleftarrow{abc}` | $`\xhookrightarrow{abc}` `\xhookrightarrow{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xtwoheadleftarrow{abc}` `\xtwoheadleftarrow{abc}` | $`\xtwoheadrightarrow{abc}` `\xtwoheadrightarrow{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xleftharpoonup{abc}` `\xleftharpoonup{abc}` | $`\xrightharpoonup{abc}` `\xrightharpoonup{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xleftharpoondown{abc}` `\xleftharpoondown{abc}` | $`\xrightharpoondown{abc}` `\xrightharpoondown{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xleftrightharpoons{abc}` `\xleftrightharpoons{abc}` | $`\xrightleftharpoons{abc}` `\xrightleftharpoons{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xtofrom{abc}` `\xtofrom{abc}` | $`\xmapsto{abc}` `\xmapsto{abc}` | -+--------------------------------------------------------+----------------------------------------------------------+ -| $`\xlongequal{abc}` `\xlongequal{abc}` | | -+--------------------------------------------------------+----------------------------------------------------------+ - -All extensible arrows can take an optional argument in the same manner as `\xrightarrow[under]{over}`. - -## Style, Size, and Font - -#### Class Assignment - -Override the usual spacing and semantic meaning of a character or fragment. - -+-----------------------------------------------+-----------------------------------------------+ -| $`a = b`  `a = b` \ | $`a | b\;\,`  `a | b` \ | -| $`a \mathord = b\;\,`  `a \mathord{=} b` \ | $`a \mathpunct | b\;`  `a \mathpunct{|} b` \ | -| $`a \mathopen = b\;\,`  `a \mathopen{=} b` \ | $`a \mathop | b\;`  `a \mathop{|} b` \ | -| $`a \mathclose = b\;\,`  `a \mathclose{=} b` | $`a \mathbin | b\,`  `a \mathbin{|} b` \ | -| | $`a \mathrel | b`  `a \mathrel{|} b` | -+-----------------------------------------------+-----------------------------------------------+ - -See also [\operatorname](#math-operators). - -#### Font - -+:-------------------------------+:---------------------------------+:---------------------------------+ -| $`\mathrm{Ab0}` `\mathrm{Ab0}` | $`\mathbf{Ab0θ}` `\mathbf{Ab0θ}` | $`\mathit{Ab0θ}` `\mathit{Ab0θ}` | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\mathnormal{Ab0}` | $`\textbf{Ab0θ}` `\textbf{Ab0θ}` | $`\textit{Ab0θ}` `\textit{Ab0θ}` | -| `\mathnormal{Ab0}` | | | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\textrm{Ab0θ}` | $`{\bf Ab0θ}` `{\bf Ab0θ}` | $`{\it Ab0θ}` `{\it Ab0θ}` | -| `\textrm{Ab0θ}` | | | -+--------------------------------+----------------------------------+----------------------------------+ -| $`{\rm Ab0}` `{\rm Ab0}` | $`\bold{Ab0θ}` `\bold{Ab0θ}` | $`\textup{Ab0θ}` `\textup{Ab0θ}` | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\textnormal{Ab0θ}` | $`\boldsymbol{Ab0θ}` | $`\Bbb{Ab0}` `\Bbb{Ab0}` | -| `\textnormal{Ab0θ}` | `\boldsymbol{Ab0θ}` | | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\text{Ab0θ}` `\text{Ab0θ}` | $`\bm{Ab0θ}` `\bm{Ab0θ}` | $`\mathbb{Ab0}` `\mathbb{Ab0}` | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\mathsf{Ab0}` `\mathsf{Ab0}` | $`\textmd{Ab0θ}` `\textmd{Ab0θ}` | $`\frak{Ab}` `\frak{Ab}` | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\textsf{Ab0}` `\textsf{Ab0}` | $`\mathtt{Ab0}` `\mathtt{Ab0}` | $`\mathfrak{Ab}` `\mathfrak{Ab}` | -+--------------------------------+----------------------------------+----------------------------------+ -| $`{\sf Ab0}` `{\sf Ab0}` | $`\texttt{Ab0}` `\texttt{Ab0}` | $`\mathcal{AB}` `\mathcal{AB}` | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\textsc{hey}` `\textsc{hey}` | $`{\tt Ab0}` `{\tt Ab0 }` | $`{\cal AB}` `{\cal AB}` | -+--------------------------------+----------------------------------+----------------------------------+ -| $`\oldstylenums{123}` | | $`\mathscr{AB}` `\mathscr{AB}` | -| `\oldstylenums{123}` | | | -+--------------------------------+----------------------------------+----------------------------------+ - -The `\textXX` versions can stack font family, font weight, and font shape. So `\textsf{\textbf{H}}` will produce $`\textsf{\textbf{H}}`. The other versions do not stack, e.g., `\mathsf{\mathbf{H}}` will produce $`\mathsf{\mathbf{H}}`. - -In cases where math fonts do not have a bold glyph, `\pmb` can simulate one. For example, `\pmb{\vartheta}` renders as : $`\pmb{\vartheta}` - -#### Font Size - -+:-------------------------+:---------------------------------------+ -| $`\Huge AB` `\Huge AB` | $`\normalsize AB` `\normalsize AB` | -+--------------------------+----------------------------------------+ -| $`\huge AB` `\huge AB` | $`\small AB` `\small AB` | -+--------------------------+----------------------------------------+ -| $`\LARGE AB` `\LARGE AB` | $`\footnotesize AB` `\footnotesize AB` | -+--------------------------+----------------------------------------+ -| $`\Large AB` `\Large AB` | $`\scriptsize AB` `\scriptsize AB` | -+--------------------------+----------------------------------------+ -| $`\large AB` `\large AB` | $`\Tiny AB` `\Tiny AB` | -+--------------------------+----------------------------------------+ -| | $`\tiny AB` `\tiny AB` | -+--------------------------+----------------------------------------+ - -#### Style - -+:-----------------------------+:-----------------------------------------------------------------+ -| $`\displaystyle\sum_{i=1}^n` | `\displaystyle\sum_{i=1}^n` | -+------------------------------+------------------------------------------------------------------+ -| $`\textstyle\sum_{i=1}^n` | `\textstyle\sum_{i=1}^n` | -+------------------------------+------------------------------------------------------------------+ -| $`\scriptstyle x` | `\scriptstyle x`     (The size of a first sub/superscript) | -+------------------------------+------------------------------------------------------------------+ -| $`\scriptscriptstyle x` | `\scriptscriptstyle x` (The size of subsequent sub/superscripts) | -+------------------------------+------------------------------------------------------------------+ -| $`\lim\limits_y x` | `\lim\limits_y x` | -+------------------------------+------------------------------------------------------------------+ -| $`\lim\nolimits_y x` | `\lim\nolimits_y x` | -+------------------------------+------------------------------------------------------------------+ -| $`\verb!x^2!` | `\verb!x^2!` | -+------------------------------+------------------------------------------------------------------+ -| $`\text{ABcd }ABcd` | `\text{ABcd $ABcd$}` | -+------------------------------+------------------------------------------------------------------+ - -`\text{…}` shifts its contents into text mode, but you can shift back into math mode by nesting `$…$`. - -## Symbols and Punctuation - -+:-----------------------------+:------------------------+:-----------------------------------+ -| `% comment` | $`\dots` `\dots` | $`\TeX` `\TeX` | -+------------------------------+-------------------------+------------------------------------+ -| $`\%` `\%` | $`\cdots` `\cdots` | $`\LaTeX` `\LaTeX` | -+------------------------------+-------------------------+------------------------------------+ -| $`\#` `\#` | $`\ddots` `\ddots` | $`\Temml` `\Temml` | -+------------------------------+-------------------------+------------------------------------+ -| $`\&` `\&` | $`\ldots` `\ldots` | $`\rule[6pt]{2ex}{1ex}` | -| | | `\rule[6pt]{2ex}{1ex}` | -+------------------------------+-------------------------+------------------------------------+ -| $`\_` `\_` | $`\vdots` `\vdots` | $`\surd` `\surd` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textunderscore}` | $`\iddots` `\iddots` | $`\infty` `\infty` | -| `\text{\textunderscore}` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{--}` `\text{--}` | $`\dotsb` `\dotsb` | $`\checkmark` `\checkmark` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textendash}` | $`\dotsc` `\dotsc` | $`\ballotx` `\ballotx` | -| `\text{\textendash}` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{---}` `\text{---}` | $`\dotsi` `\dotsi` | $`\dag` `\dagger` or `\dag` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textemdash}` | $`\dotsm` `\dotsm` | $`\text{\textdagger}` | -| `\text{\textemdash}` | | `\text{\textdagger}` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textasciitilde}` | $`\dotso` `\dotso` | $`\ddagger` `\ddagger` or `\ddag` | -| `\text{\textasciitilde}` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textasciicircum}` | $`\dotsi` `\idotsin` | $`\text{\textdaggerdbl}` | -| `\text{\textasciicircum}` | | `\text{\textdaggerdbl}` | -+------------------------------+-------------------------+------------------------------------+ -| $`` ` `` `` ` `` | $`\mathellipsis` | $`\angle` `\angle` | -| | `\mathellipsis` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textquoteleft}` | $`\text{\textellipsis}` | $`\measuredangle` `\measuredangle` | -| `text{\textquoteleft}` | `\text{\textellipsis}` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\lq` `\lq` | $`\Box` `\Box` | $`\sphericalangle` | -| | | `\sphericalangle` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textquoteright}` | $`\square` `\square` | $`\top` `\top` | -| `\text{\textquoteright}` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\rq` `\rq` | $`\blacksquare` | $`\bot` `\bot` | -| | `\blacksquare` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textquotedblleft}` | $`\triangle` | $`\Bot` `\Bot` | -| `\text{\textquotedblleft}` | `\triangle` | | -+------------------------------+-------------------------+------------------------------------+ -| $`"` `"` | $`\triangledown` | $`\$` `\$` | -| | `\triangledown` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textquotedblright}` | $`\triangleleft` | $`\text{\textdollar}` | -| `\text{\textquotedblright}` | `\triangleleft` | `\text{\textdollar}` | -+------------------------------+-------------------------+------------------------------------+ -| $`\colon` `\colon` | $`\triangleright` | $`\pounds` `\pounds` | -| | `\triangleright` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\backprime` `\backprime` | $`\bigtriangledown` | $`\mathsterling` `\mathsterling` | -| | `\bigtriangledown` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\prime` `\prime` | $`\bigtriangleup` | $`\text{\textsterling}` | -| | `\bigtriangleup` | `\text{\textsterling}` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textless}` | $`\blacktriangle` | $`\yen` `\yen` | -| `\text{\textless}` | `\blacktriangle` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textgreater}` | $`\blacktriangledown` | $`\euro` `\euro` | -| `\text{\textgreater}` | `\blacktriangledown` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textbar}` | $`\blacktriangleleft` | $`\text{\texteuro}` | -| `\text{\textbar}` | `\blacktriangleleft` | `\text{\texteuro}` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textbardbl}` | $`\blacktriangleright` | $`\degree` `\degree` | -| `\text{\textbardbl}` | `\blacktriangleright` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textbraceleft}` | $`\diamond` `\diamond` | $`\text{\textdegree}` | -| `\text{\textbraceleft}` | | `\text{\textdegree}` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textbraceright}` | $`\Diamond` `\Diamond` | $`\mho` `\mho` | -| `\text{\textbraceright}` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textbackslash}` | $`\lozenge` `\lozenge` | $`\diagdown` `\diagdown` | -| `\text{\textbackslash}` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textvisiblespace}` | $`\blacklozenge` | $`\diagup` `\diagup` | -| `\text{\textvisiblespace}` | `\blacklozenge` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\P}` `\text{\P}` | $`\star` `\star` | $`\flat` `\flat` | -| or `\P` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\S}` `\text{\S}` | $`\bigstar` `\bigstar` | $`\natural` `\natural` | -| or `\S` | | | -+------------------------------+-------------------------+------------------------------------+ -| $`\copyright` `\copyright` | $`\maltese` `\maltese` | $`\sharp` `\sharp` | -+------------------------------+-------------------------+------------------------------------+ -| $`\circledR` `\circledR` | $`\clubsuit` | $`\varclubsuit` `\varclubsuit` | -| | `\clubsuit` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\circledS` `\circledS` | $`\diamondsuit` | $`\vardiamondsuit` | -| | `\diamondsuit` | `\vardiamondsuit` | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textregistered}` | $`\heartsuit` | $`\varheartsuit` `\varheartsuit` | -| `\text{\textregistered}` | `\heartsuit` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\text{\textbullet}` | $`\spadesuit` | $`\varspadesuit` `\varspadesuit` | -| `\text{\textbullet}` | `\spadesuit` | | -+------------------------------+-------------------------+------------------------------------+ -| $`\smiley` `\smiley` | $`\female` `\female` | $`\male` `\male` | -+------------------------------+-------------------------+------------------------------------+ -| $`\standardstate` | $`\lightning` | $`\permil` `\permil` | -| `\standardstate` | `\lightning` | | -+------------------------------+-------------------------+------------------------------------+ - -Symbols in the _texvc_ extension - -+:-------------------------+:-------------------------------+:---------------------+ -| $`\clubs` `\clubs` | $`\hearts` `\hearts` | $`\sdot` `\sdot` | -+--------------------------+--------------------------------+----------------------+ -| $`\diamonds` `\diamonds` | $`\spades` `\spades` | $`\infin` `\infin` | -+--------------------------+--------------------------------+----------------------+ -| $`\bull` `\bull` | $`\text{\sect}` `\text{\sect}` | $`\Dagger` `\Dagger` | -+--------------------------+--------------------------------+----------------------+ - -Direct Input: § ¶ £ ¥ € ∇ ∞ · ∠ ∡ ∢ ♠ ♡ ♢ ♣ ♭ ♮ ♯ © ® ☺ ✓ ↯ … ⋮ ⋯ ⋱ ! ‼ - -## Units - -| Unit | Value | Unit | Value | -|:-----|:-------------|:-----|:--------------| -| em | CSS em | bp | 1/72​ inch | -| ex | CSS ex | pc | 12 pt | -| mu | 1/18 em | dd | 1238/1157​ pt | -| pt | 1/72.27 inch | cc | 14856/1157 pt | -| mm | 1 mm | nd | 685/642 pt | -| cm | 1 cm | nc | 1370/107​ pt | -| in | 1 inch | sp | 1/65536 pt | - -The effect of script level and font size: - -| Unit | textstyle
normal size | scriptscript | huge | -|:------:|:-----------------:|:-----------------------------------:|:--------------------------:| -|em or ex|$`\rule{1em}{1em}` |$`\scriptscriptstyle\rule{1em}{1em}` |$`\huge\rule{1em}{1em}` | -| mu |$`\rule{18mu}{18mu}`|$`\scriptscriptstyle\rule{18mu}{18mu}`|$`\huge\rule{18mu}{18mu}` | -| others |$`\rule{16pt}{16pt}`|$`\scriptscriptstyle\rule{16pt}{16pt}`|$`\huge\rule{16pt}{16pt}` | - -`em` and `ex` are affected by font size changes such as `\Large`, but they are not affected -by script level, so they will not change size in a fraction numerator or an -exponent. - -`mu` is affected by both script level and font size. - -The other units are absolute and are not affected by either script level or font size. - -
- -

Copyright © 2021, 2022 Ron Kok. -Released under the MIT License

- -
- -
- - - - - - - - - \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index cb95070d..00000000 --- a/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "temml", - "version": "0.6.9", - "description": "TeX to MathML conversion in JavaScript.", - "main": "dist/temml.js", - "homepage": "https://temml.org", - "repository": { - "type": "git", - "url": "git://github.com/ronkok/Temml" - }, - "files": [ - "temml.js", - "src/", - "contrib/", - "dist/" - ], - "license": "MIT", - "devDependencies": { - "eslint": "^8.7.0", - "esm": "^3.2.25", - "rollup": "^2.66.1", - "terser": "^5.10.0" - }, - "scripts": { - "lint": "eslint temml.js src", - "unit-test": "node -r esm ./test/unit-test.js", - "visual-test": "node utils/buildTests.js", - "test": "yarn lint && node utils/buildTests.js && yarn unit-test", - "minify": "terser test/temml.js -o site/assets/temml.min.js -c -m && terser contrib/mhchem/mhchem.js -o site/assets/mhchem.min.js -c -m", - "build": "rollup --config ./utils/rollupConfig.js && yarn minify && node utils/insertPlugins.js", - "docs": "node utils/buildDocs.js", - "dist": "yarn build && node ./utils/copyfiles.js && terser contrib/auto-render/test/auto-render.js -o contrib/auto-render/dist/auto-render.min.js -c -m" - }, - "dependencies": { - "xml-formatter": "^2.4.0" - } -} diff --git a/site/assets/Asana-Math.woff2 b/site/assets/Asana-Math.woff2 deleted file mode 100644 index 9ca8cda8..00000000 Binary files a/site/assets/Asana-Math.woff2 and /dev/null differ diff --git a/site/assets/GUST-FONT-LICENSE.txt b/site/assets/GUST-FONT-LICENSE.txt deleted file mode 100644 index 60b55002..00000000 --- a/site/assets/GUST-FONT-LICENSE.txt +++ /dev/null @@ -1,30 +0,0 @@ -% This is a preliminary version (2006-09-30), barring acceptance from -% the LaTeX Project Team and other feedback, of the GUST Font License. -% (GUST is the Polish TeX Users Group, http://www.gust.org.pl) -% -% For the most recent version of this license see -% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt -% or -% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt -% -% This work may be distributed and/or modified under the conditions -% of the LaTeX Project Public License, either version 1.3c of this -% license or (at your option) any later version. -% -% Please also observe the following clause: -% 1) it is requested, but not legally required, that derived works be -% distributed only after changing the names of the fonts comprising this -% work and given in an accompanying "manifest", and that the -% files comprising the Work, as listed in the manifest, also be given -% new names. Any exceptions to this request are also given in the -% manifest. -% -% We recommend the manifest be given in a separate file named -% MANIFEST-.txt, where is some unique identification -% of the font family. If a separate "readme" file accompanies the Work, -% we recommend a name of the form README-.txt. -% -% The latest version of the LaTeX Project Public License is in -% http://www.latex-project.org/lppl.txt and version 1.3c or later -% is part of all distributions of LaTeX version 2006/05/20 or later. - diff --git a/site/assets/MANIFEST-Latin-Modern-Math.txt b/site/assets/MANIFEST-Latin-Modern-Math.txt deleted file mode 100644 index c84e1e5a..00000000 --- a/site/assets/MANIFEST-Latin-Modern-Math.txt +++ /dev/null @@ -1,60 +0,0 @@ -########################################################################### -############ The TeX Gyre Collection of Fonts ############ -########################################################################### - -Font: Latin Modern Math -Authors: Bogus\l{}aw Jackowski, Piotr Strzelczyk and Piotr Pianowski -Version: 1.959 -Date: 5 IX 2014 - -Copyright 2012--2014 for TeX Gyre math extensions by B. Jackowski, -P. Strzelczyk and P. Pianowski (on behalf of TeX Users Groups). - -This work can be freely used and distributed under -the GUST Font License (GFL -- see GUST-FONT-LICENSE.txt) -which is actually an instance of the LaTeX Project Public License -(LPPL -- see http://www.latex-project.org/lppl.txt). - -This work has the maintenance status "maintained". The Current Maintainer -of this work is Bogus\l{}aw Jackowski, Piotr Strzelczyk and Piotr Pianowski. - -This work consists of the files listed in this file. - -Below, in three sections required by the GUST Font License, -font names and file names specific for the Latin Modern Math -font are listed. - -NOTE: the names of the directories are not subject to the renaming -restrictions. - -1. Fonts whose names should be changed in derived works as requested - by clause 1 of GUST-FONT-LICENSE.txt - - 1.1 OTF menu names - Latin Modern Math - LatinModernMath-Regular - -2. Files whose names should be changed in derived works as requested - by clause 1 of GUST-FONT-LICENSE.txt - - 2.1 otf/latinmodern-math.otf - - 2.2 doc/MANIFEST-Latin-Modern-Math.txt - doc/README-Latin-Modern-Math.txt - doc/presentation-lmodern_math.pdf - doc/math-test.tex - doc/math-test-context.tex - doc/test-context-latinmodern_math.pdf - doc/test-context-latinmodern_math.tex - doc/test-lualatex-latinmodern_math.pdf - doc/test-lualatex-latinmodern_math.tex - doc/test-xelatex-latinmodern_math.pdf - doc/test-xelatex-latinmodern_math.tex - doc/test-word-tg_latinmodern_math.docx - doc/test-word-tg_latinmodern_math.pdf - -3. Files whose names need not be changed in derived works as requested - by clause 1 of GUST-FONT-LICENSE.txt - - doc/GUST-FONT-LICENSE.txt - doc/INSTALL.txt diff --git a/site/assets/README-Latin-Modern-Math.txt b/site/assets/README-Latin-Modern-Math.txt deleted file mode 100644 index 30c8e602..00000000 --- a/site/assets/README-Latin-Modern-Math.txt +++ /dev/null @@ -1,92 +0,0 @@ -########################################################################### -############ Latin Modern Collection of Fonts ############ -########################################################################### - -Font: Latin Modern Math -Authors: Bogus\l{}aw Jackowski, Piotr Strzelczyk and Piotr Pianowski -Version: 1.959 -Date: 5 IX 2014 - -License: - % Copyright 2012--2014 for the Latin Modern math extensions by B. Jackowski, - % P. Strzelczyk and P. Pianowski (on behalf of TeX Users Groups). - % - % This work can be freely used and distributed under - % the GUST Font License (GFL -- see GUST-FONT-LICENSE.txt) - % which is actually an instance of the LaTeX Project Public License - % (LPPL -- see http://www.latex-project.org/lppl.txt). - % - % This work has the maintenance status "maintained". The Current Maintainer - % of this work is Bogus\l{}aw Jackowski, Piotr Strzelczyk and Piotr Pianowski. - % - % This work consists of the files listed - % in the MANIFEST-Latin-Modern-Math.txt file. - -########################################################################### -############ A BRIEF DESCRIPTION OF THE FONT ############ -########################################################################### - -Latin Modern Math is a math companion for the Latin Modern family -of fonts (see http://www.gust.org.pl/projects/e-foundry/latin-modern) in -the OpenType format. - -The math OTF fonts should contain a special table, MATH, described in the -confidential Microsoft document "The MATH table and OpenType Features -for Math Processing". Moreover, they should contain a broad collection -of special characters (see "Draft Unicode Technical Report #25. -UNICODE SUPPORT FOR MATHEMATICS" by Barbara Beeton, Asmus Freytag, -and Murray Sargent III). In particular, math OTF fonts are expected -to contain the following scripts: a basic serif script (regular, bold, -italic and bold italic), a calligraphic script (regular and bold), -a double-struck script, a fraktur script (regular and bold), a sans-serif -script (regular, bold, oblique and bold oblique), and a monospaced script. - -The basic script is, obviously, Latin Modern. Some scripts, however, -are borrowed from other fonts (the current selection, however, may -be subject to change), belonging, however, to the "TeX circle": - - * the calligraphic and fraktur alphabets are excerpted from the renowned - Euler family (http://en.wikipedia.org/wiki/AMS_Euler); - - * the double struck script is excerpted from Alan Jeffrey's bbold font - (http://www.tug.org/texlive/Contents/live/texmf-dist/doc/latex/bbold/bbold.pdf) - - * the sans serif and monospaced alphabets are excerpted from - the Latin Modern Sans and Latin Modern Mono fonts - (http://www.gust.org.pl/projects/e-foundry/latin-modern); - sans serif bold Greek symbols (required by the already mentioned - "Unicode Technical Report #25") were prepared using D.E. Knuth's - font sources with some manual tuning - -The main math component, that is, the math extension, was programmed -from scratch, with an attempt to retain the visual compatiblility -with the original D.E. Knuth's fonts. In particular, all symbols -(with a few exceptions) appearing in the D.E. Knuth's "canonical" fonts -have the same width (rounded) as the corresponding Knuthian ones. - -Note that the members of all the mentioned alphabets, except -the main roman alphabet, should be considerd symbols, not letters; -symbols are not expected to occur in a text stream; instead, -they are expected to appear lonely, perhaps with some embellishments -like subscripts, superscripts, primes, dots above and below, etc. - -To produce the font, MetaType1 and the FontForge library were used: -the Type1 PostScript font containing all relevant characters was -generated with the MetaType1 engine, and the result was converted -into the OTF format with all the necessary data structures by -a Python script employing the FontForge library. - -Recent changes (ver. 1.958 --> ver. 1.959) comprised -mainly interline settings in OTF tables (HHEA and -OS/2) and the correction of unicode slots assigned to -the contour integrals (glyphs `clockwise contour -integral', u+2232, and `anticlockwise contour -integral', u+2233, used to have swapped slots). - - * * * - -The TeX Gyre Math Project was launched and is supported by -TeX USERS GROUPS (CS TUG, DANTE eV, GUST, NTG, TUG India, TUG, UK TUG). -Hearty thanks to the representatives of these groups and also -to all people who helped with their work, comments, ideas, -remarks, bug reports, objections, hints, consolations, etc. diff --git a/site/assets/STIXTwoMath-Regular.woff2 b/site/assets/STIXTwoMath-Regular.woff2 deleted file mode 100644 index 3b97c9c8..00000000 Binary files a/site/assets/STIXTwoMath-Regular.woff2 and /dev/null differ diff --git a/site/assets/Temml-Asana.css b/site/assets/Temml-Asana.css deleted file mode 100644 index f792d0ff..00000000 --- a/site/assets/Temml-Asana.css +++ /dev/null @@ -1,57 +0,0 @@ -/* -Asana Math is released under the SIL Open Font License. See the files in this -directory for details. The font can be obtained from several TeX distributions -or package managers. The font does not seem to have a corresponding "non-MATH" -font, it is recommended to use a Palatino-like font for the surrounding text. - -The WOFF fonts have been obtained from -http://mirrors.ctan.org/fonts/ -*/ - -@font-face { - font-family: Asana Math; - src: local('Asana Math'), local('Asana-Math'), - url('./Asana-Math.woff2'); -} - -math { - font-style: normal; - font-weight: normal; - line-height: normal; - font-size-adjust: none; - text-indent: 0; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - direction: ltr; -} - -math * { - border-color: currentColor; -} - -mtext { - font-family: Asana Math; -} - -math { - font-family: Asana Math; -} - -*.mathcal { - font-feature-settings: 'salt'; -} - -.oldstylenums { - font-feature-settings: 'onum'; -} - -/* AMS environment auto-numbering via CSS counter. */ -.tml-eqn::before { - counter-increment: tmlEqnNo; - content: "(" counter(tmlEqnNo) ")"; -} - -body { - counter-reset: tmlEqnNo; -} diff --git a/site/assets/Temml-Latin-Modern.css b/site/assets/Temml-Latin-Modern.css deleted file mode 100644 index 15fd2398..00000000 --- a/site/assets/Temml-Latin-Modern.css +++ /dev/null @@ -1,68 +0,0 @@ -/* -The Latin Modern fonts are released under the GUST font license, which is -legally equivalent to the LaTeX Project Public License. See the files in this -directory for details. The fonts can be obtained from several TeX distributions -or package managers. - -The Latin Modern WOFF font has been obtained from -http://www.gust.org.pl/projects/e-foundry/ - -The Temml.woff2 is a clone of KaTeX_Script-Regular, except that the code points -have been changed from ASCII to Unicode Mathematical Alphanumeric Symbols Script capitals, -Unicode range 1D49C to 1D4B5. -*/ - -@font-face { - font-family: 'Temml'; - src: url('Temml.woff2') format('woff2'); - font-weight: normal; - font-style: normal; -} - -@font-face { - font-family: Latin Modern Math; - src: url('./latinmodernmath.woff2'); -} - -math { - font-style: normal; - font-weight: normal; - line-height: normal; - font-size-adjust: none; - text-indent: 0; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - direction: ltr; -} - -math * { - border-color: currentColor; -} - -.latin-modern math { - font-family: "Latin Modern Math", "Times New Roman", math; -} - -math { - font-family: Latin Modern Math; -} - -*.mathscr { - font-family: "Temml"; -} - -.oldstylenums { - font-family: "Cambria Math", math; - font-feature-settings: 'onum'; -} - -/* AMS environment auto-numbering via CSS counter. */ -.tml-eqn::before { - counter-increment: tmlEqnNo; - content: "(" counter(tmlEqnNo) ")"; -} - -body { - counter-reset: tmlEqnNo; -} diff --git a/site/assets/Temml-Local.css b/site/assets/Temml-Local.css deleted file mode 100644 index 42c98143..00000000 --- a/site/assets/Temml-Local.css +++ /dev/null @@ -1,47 +0,0 @@ -/* -Temml.woff2 is a clone of KaTeX_Script-Regular, except that the code points -have been changed from ASCII to Unicode Mathematical Alphanumeric Symbols Script capitals, -Unicode range 1D49C to 1D4B5. -*/ - -@font-face { - font-family: 'Temml'; - src: url('Temml.woff2') format('woff2'); - font-weight: normal; - font-style: normal; -} - -math { - font-family: "Cambria Math", "Times New Roman", math; - font-style: normal; - font-weight: normal; - line-height: normal; - font-size-adjust: none; - text-indent: 0; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - direction: ltr; -} - -math * { - border-color: currentColor; -} - -math .mathscr { - font-family: "Temml"; -} - -math .oldstylenums { - font-feature-settings: 'onum'; -} - -/* AMS environment auto-numbering via CSS counter. */ -.tml-eqn::before { - counter-increment: tmlEqnNo; - content: "(" counter(tmlEqnNo) ")"; -} - -body { - counter-reset: tmlEqnNo; -} diff --git a/site/assets/Temml-STIX2.css b/site/assets/Temml-STIX2.css deleted file mode 100644 index 7b0dbbc1..00000000 --- a/site/assets/Temml-STIX2.css +++ /dev/null @@ -1,56 +0,0 @@ -/* -XITS is released under the SIL Open Font License. -See https://github.com/stipub/stixfonts/blob/master/OFL.txt details. - -The WOFF font has been obtained from -https://github.com/stipub/stixfonts -*/ - -@font-face { - font-family: STIX2; - src: local('STIXTwoMath-Regular'), - url('./STIXTwoMath-Regular.woff2'); -} - -math { - font-style: normal; - font-weight: normal; - line-height: normal; - font-size-adjust: none; - text-indent: 0; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - direction: ltr; -} - -math * { - border-color: currentColor; -} - -mtext { - font-family: STIX2; -} - -math { - font-family: STIX2, math; -} - -*.mathscr { - font-feature-settings: 'ss01'; -} - -.oldstylenums { - font-family: "Cambria Math", math; - font-feature-settings: 'onum'; -} - -/* AMS environment auto-numbering via CSS counter. */ -.tml-eqn::before { - counter-increment: tmlEqnNo; - content: "(" counter(tmlEqnNo) ")"; -} - -body { - counter-reset: tmlEqnNo; -} diff --git a/site/assets/Temml-XITS.css b/site/assets/Temml-XITS.css deleted file mode 100644 index 32421750..00000000 --- a/site/assets/Temml-XITS.css +++ /dev/null @@ -1,63 +0,0 @@ -/* -XITS is released under the SIL Open Font License. See the files in this -directory for details. The font can be obtained from several TeX distributions -or package managers. - -The WOFF fonts have been obtained from -http://mirrors.ctan.org/fonts/ -*/ - -@font-face { - font-family: XITS Math; - src: local('XITS Math'), local('XITSMath-Regular'), - url('./xits-math.woff2'); -} -@font-face { - font-family: XITS Math; - src: local('XITS Math Bold'), local('XITSMath-Bold'), - url('./xits-mathbold.woff2'); - font-weight: bold; -} - -math { - font-style: normal; - font-weight: normal; - line-height: normal; - font-size-adjust: none; - text-indent: 0; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - direction: ltr; -} - -math * { - border-color: currentColor; -} - -mtext { - font-family: XITS; -} - -math { - font-family: XITS Math, math; -} - -*.mathcal { - font-feature-settings: 'ss01'; -} - -.oldstylenums { - font-family: "Cambria Math", math; - font-feature-settings: 'onum'; -} - -/* AMS environment auto-numbering via CSS counter. */ -.tml-eqn::before { - counter-increment: tmlEqnNo; - content: "(" counter(tmlEqnNo) ")"; -} - -body { - counter-reset: tmlEqnNo; -} diff --git a/site/assets/Temml.woff2 b/site/assets/Temml.woff2 deleted file mode 100644 index 367dda77..00000000 Binary files a/site/assets/Temml.woff2 and /dev/null differ diff --git a/site/assets/XITS-FAQ.txt b/site/assets/XITS-FAQ.txt deleted file mode 100644 index edb55c61..00000000 --- a/site/assets/XITS-FAQ.txt +++ /dev/null @@ -1,369 +0,0 @@ -OFL FAQ - Frequently Asked Questions about the SIL Open Font License (OFL) -Version 1.1-update2 - 23 August 2010 -(See http://scripts.sil.org/OFL for updates) - - -CONTENTS OF THIS FAQ -1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL -2 USING OFL FONTS FOR WEB PAGES AND ONLINE WEBFONT SERVICES -3 MODIFYING OFL-LICENSED FONTS -4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL -5 CHOOSING RESERVED FONT NAMES -6 ABOUT THE FONTLOG -7 MAKING CONTRIBUTIONS TO OFL PROJECTS -8 ABOUT THE LICENSE ITSELF -9 ABOUT SIL INTERNATIONAL -APPENDIX A - FONTLOG EXAMPLE - - -1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL - -1.1 Can I use the fonts for a book or other print publication? -Yes. You can mention the font and author in the book's colophon if you wish, but that is not required. - -1.2 Can the fonts be included with Free/Libre and Open Source Software collections such as GNU/Linux and BSD distributions? -Yes! Fonts licensed under the OFL can be freely included alongside other software under FLOSS (Free/Libre and Open Source Software) licenses. Since fonts are typically aggregated with, not merged into, existing software, there is little need to be concerned about incompatibility with existing software licenses. You may also repackage the fonts and the accompanying components in a .rpm or .deb package and include them in distribution CD/DVDs and online repositories. (Also see section 5.9 about rebuilding from source.) - -1.3 I want to distribute the fonts with my program. Does this mean my program also has to be Free/Libre and Open Source Software? -No. Only the portions based on the Font Software are required to be released under the OFL. The intent of the license is to allow aggregation or bundling with software under restricted licensing as well. - -1.4 Can I sell a software package that includes these fonts? -Yes, you can do this with both the Original Version and a Modified Version of the fonts. Examples of bundling made possible by the OFL would include: word processors, design and publishing applications, training and educational software, games and entertainment software, mobile device applications, etc. - -1.5 Can I include the fonts on a CD of freeware or commercial fonts? -Yes, as long some other font or software is also on the disk, so the OFL font is not sold by itself. - -1.6 Why won't the OFL let me sell the fonts alone? -The intent is to keep people from making money by simply redistributing the fonts. The only people who ought to profit directly from the fonts should be the original authors, and those authors have kindly given up potential direct income to distribute their fonts under the OFL. Please honour and respect their contribution! - -1.7 What about sharing OFL fonts with friends on a CD, DVD or USB stick? -You are very welcome to share open fonts with friends, family and colleagues through removable media. Just remember to include the full font package, including any copyright notices and licensing information as available in OFL.txt. In the case where you sell the font, it has to come bundled with software. - -1.8 Can I host the fonts on a web site for others to use? -Yes, as long as you make the full font package available. In most cases it may be best to point users to the main site that distributes the Original Version so they always get the most recent stable and complete version. See also discussion of webfonts in Section 2. - -1.9 Can I host the fonts on a server for use over our internal network? -Yes. If the fonts are transferred from the server to the client computer by means that allow them to be used even if the computer is no longer attached to the network, the full package (copyright notices, licensing information, etc.) should be included. - -1.10 Does the full OFL license text always need to accompany the font? -The only situation in which an OFL font can be distributed without the text of the OFL (either in a separate file or in font metadata), is when a font is embedded in a document or bundled within a program. In the case of metadata included within a font, it is legally sufficient to include only a link to the text of the OFL on http://scripts.sil.org/OFL, but we strongly recommend against this. Most modern font formats include metadata fields that will accept the full OFL text, and full inclusion increases the likelihood that users will understand and properly apply the license. - -1.11 What do you mean by 'embedding'? How does that differ from other means of distribution? -By 'embedding' we mean inclusion of the font in a document or file in a way that makes extraction (and redistribution) difficult or clearly discouraged. In many cases the names of embedded fonts might also not be obvious to those reading the document, the font data format might be altered, and only a subset of the font - only the glyphs required for the text - might be included. Any other means of delivering a font to another person is considered 'distribution', and needs to be accompanied by any copyright notices and licensing information available in OFL.txt. - -1.12 So can I embed OFL fonts in my document? -Yes, either in full or a subset. The restrictions regarding font modification and redistribution do not apply, as the font is not intended for use outside the document. - -1.13 Does embedding alter the license of the document itself? -No. Referencing or embedding an OFL font in any document does not change the license of the document itself. The requirement for fonts to remain under the OFL does not apply to any document created using the fonts and their derivatives. Similarly, creating any kind of graphic using a font under OFL does not make the resulting artwork subject to the OFL. - -1.14 If OFL fonts are extracted from a document in which they are embedded (such as a PDF file), what can be done with them? Is this a risk to author(s)? -The few utilities that can extract fonts embedded in a PDF will typically output limited amounts of outlines - not a complete font. To create a working font from this method is much more difficult and time consuming than finding the source of the original OFL font. So there is little chance that an OFL font would be extracted and redistributed inappropriately through this method. Even so, copyright laws address any misrepresentation of authorship. All Font Software released under the OFL and marked as such by the author(s) is intended to remain under this license regardless of the distribution method, and cannot be redistributed under any other license. We strongly discourage any font extraction - we recommend directly using the font sources instead - but if you extract font outlines from a document, please be considerate: use your common sense and respect the work of the author(s) and the licensing model. - -1.15 What about distributing fonts with a document? Within a compressed folder structure? Is it distribution, bundling or embedding? -Certain document formats may allow the inclusion of an unmodified font within their file structure which consists of a compressed folder containing the various resources forming the document (such as pictures and thumbnails). Including fonts within such a structure is understood as being different from embedding but rather similar to bundling (or mere aggregation) which the license explicitly allows. In this case the font is conveyed unchanged whereas embedding a font usually transforms it from the original format. The OFL does not allow anyone to extract the font from such a structure to then redistribute it under another license. The explicit permission to redistribute and embed does not cancel the requirement for the Font Software to remain under the license chosen by its author(s). - -1.16 What about ebooks shipping with open fonts? -The requirements differ depending on whether the fonts are linked, embedded or distributed (bundled or aggregated). Some ebook formats use web technologies to do font linking via @font-face, others are designed for font embedding, some use fonts distributed with the document or reading software, and a few rely solely on the fonts already present on the target system. The license requirements depend on the type of inclusion as discussed in 1.15. - -1.17 Can Font Software released under the OFL be subject to URL-based access restrictions methods or DRM (Digital Rights Management) mechanisms? -Yes, but these issues are out-of-scope for the OFL. The license itself neither encourages their use nor prohibits them since such mechanisms are not implemented in the components of the Font Software but through external software. Such restrictions are put in place for many different purposes corresponding to various usage scenarios. One common example is to limit potentially dangerous cross-site scripting attacks. However, in the spirit of libre/open fonts and unrestricted writing systems, we strongly encourage open sharing and reuse of OFL fonts, and the establishment of an environment where such restrictions are unnecessary. Note that whether you wish to use such mechanisms or you prefer not to, you must still abide by the rules set forth by the OFL when using fonts released by their authors under this license. Derivative fonts must be licensed under the OFL, even if they are part of a service for which you charge fees and/or for which access to source code is restricted. You may not sell the fonts on their own - they must be part of a larger software package, bundle or subscription plan. For example, even if the OFL font is distributed in a software package or via an online service using a DRM mechanism, the user would still have the right to extract that font, use, study, modify and redistribute it under the OFL. - -1.18 I've come across a font released under the OFL. How can I easily get more information about the Original Version? How can I know where it stands compared to the Original Version or other Modified Versions? -Consult the copyright statement(s) in the license for ways to contact the original authors. Consult the FONTLOG for information on how the font differs from the Original Version, and get in touch with the various contributors via the information in the acknowledgement section. Please consider using the Original Versions of the fonts whenever possible. - -1.19 What do you mean in condition 4? Can you provide examples of abusive promotion / endorsement / advertisement vs. normal acknowledgement? -The intent is that the goodwill and reputation of the author(s) should not be used in a way that makes it sound like the original author(s) endorse or approve of a specific Modified Version or software bundle. For example, it would not be right to advertise a word processor by naming the author(s) in a listing of software features, or to promote a Modified Version on a web site by saying "designed by ...". However, it would be appropriate to acknowledge the author(s) if your software package has a list of people who deserve thanks. We realize that this can seem to be a grey area, but the standard used to judge an acknowledgement is that if the acknowledgement benefits the author(s) it is allowed, but if it primarily benefits other parties, or could reflect poorly on the author(s), then it is not. - - -2 USING OFL FONTS FOR WEBPAGES AND ONLINE WEBFONT SERVICES - -2.1 Can I make webpages using these fonts? -Yes! Go ahead! Using CSS (Cascading Style Sheets) is recommended. Your three best options: -- referring directly in your stylesheet to open fonts which may be available on the user's system -- providing links to download the full package of the font - either from your own website or from elsewhere - so users can install it themselves -- using @font-face to distribute the font directly to browsers. This is recommended and explicitly allowed by the licensing model because it is distribution. The font file itself is distributed with other components of the webpage. It is not embedded in the webpage but referenced through a web address which will cause the browser to retrieve and use the corresponding font to render the webpage (see 1.11 and 1.15 for details related to embedding fonts into documents). As you take advantage of the @font-face cross-platform standard, be aware that webfonts are often tuned for a web environment and not intended for installation and use outside a browser. The reasons in favour of using webfonts are to allow design of dynamic text elements instead of static graphics, to make it easier for content to be localized and translated, indexed and searched, and all this with cross-platform open standards without depending on restricted extensions or plugins. You should check the CSS cascade (the order in which fonts are being called or delivered to your users) when testing. - -2.2 Can I make and use WOFF (Web Open Font Format) versions of OFL fonts? -Yes, but you need to be careful. A change in font format normally is considered modification, and Reserved Font Names (RFNs) cannot be used. Because of the design of the WOFF format, however, it is possible to create a WOFF version that is not considered modification, and so would not require a name change. You are allowed to create, use and distribute a WOFF version of an OFL font without changing the font name, but only if: - -- the original font data remains unchanged except for WOFF compression, and -- WOFF-specific metadata is either omitted altogether or present and includes, unaltered, the contents of all equivalent metadata in the original font. - -If the original font data or metadata is changed, or the WOFF-specific metadata is incomplete, the font must be considered a Modified Version, the OFL restrictions would apply and the name of the font must be changed: any RFNs cannot be used and copyright notices and licensing information must be included and cannot be deleted or modified. You must come up with a unique name - we recommend one corresponding to your domain or your particular web application. Be aware that only the original author(s) can use RFNs. This is to prevent collisions between a derivative tuned to your audience and the original upstream version and so to reduce confusion. - -Please note that most WOFF conversion tools and online services do not meet the two requirements listed above, and so their output must be considered a Modified Version. So be very careful and check to be sure that the tool or service you're using is compressing unchanged data and completely and accurately reflecting the original font metadata. - -2.3 What about other webfont formats such as EOT/EOTLite/CWT/etc.? -In most cases these formats alter the original font data more than WOFF, and do not completely support appropriate metadata, so their use must be considered modification and RFNs may not be used. - -2.4 Can I make OFL fonts available through webfont online services? -Yes, you are welcome to include OFL fonts in online webfont services as long as you properly meet all the conditions of the license. The origin and open status of the font should be clear among the other fonts you are hosting. Authorship, copyright notices and license information must be sufficiently visible to your users or subscribers so they know where the font comes from and the rights granted by the author(s). Make sure the font file contains the needed copyright notice(s) and licensing information in its metadata. Please double-check the accuracy of every field to prevent contradictory information. Other font formats, including EOT/EOTLite/CWT and superior alternatives like WOFF, already provide fields for this information. Remember that if you modify the font within your library or convert it to another format for any reason the OFL restrictions apply and you need to change the names accordingly. Please respect the author's wishes as expressed in the OFL and do not misrepresent original designers and their work. Don't lump quality open fonts together with dubious freeware or public domain fonts. Consider how you can best work with the original designers and foundries, support their efforts and generate goodwill that will benefit your service. (See 1.17 for details related to URL-based access restrictions methods or DRM mechanisms). - -2.5 Can I make and publish CMS themes or templates that use OFL fonts? Can I include the fonts themselves in the themes or templates? Can I sell the whole package? -Yes, you are very welcome to integrate open fonts into themes and templates for your preferred CMS and make them more widely available. Be aware that you can only sell the fonts and your CMS add-on as part of a software bundle. (See 1.4 for details and examples about selling bundles). - -2.6 Some webfont formats and services provide ways of "optimising" the font for a particular website or web application; is that allowed? -Yes, it is permitted, but remember that these optimised versions are Modified Versions and so must follow OFL requirements like appropriate renaming. Also you need to bear in mind the other important parameters beyond compression, speed and responsiveness: you need to consider the audience of your particular website or web application, as choosing some optimisation parameters may turn out to be less than ideal for them. Subsetting by removing certain glyphs or features may seriously limit functionality of the font in various languages used by your users. It may also introduce degradation of quality in the rendering or specific bugs on the various platforms compared to the original font. In other words, remember that one person's optimised font may be another person's missing feature. Various advanced typographic features are also available through CSS and may provide the desired effects without the need to modify the font. - - -3 MODIFYING OFL-LICENSED FONTS - -3.1 Can I change the fonts? Are there any limitations to what things I can and cannot change? -You are allowed to change anything, as long as such changes do not violate the terms of the license. In other words, you are not allowed to remove the copyright statement(s) from the font, but you could put additional information into it that covers your contribution. - -3.2 I have a font that needs a few extra glyphs - can I take them from an OFL licensed font and copy them into mine? -Yes, but if you distribute that font to others it must be under the OFL, and include the information mentioned in condition 2 of the license. - -3.3 Can I charge people for my additional work? In other words, if I add a bunch of special glyphs and/or OpenType/Graphite code, can I sell the enhanced font? -Not by itself. Derivative fonts must be released under the OFL and cannot be sold by themselves. It is permitted, however, to include them in a larger software package (such as text editors, office suites or operating systems), even if the larger package is sold. In that case, you are strongly encouraged, but not required, to also make that derived font easily and freely available outside of the larger package. - -3.4 Can I pay someone to enhance the fonts for my use and distribution? -Yes. This is a good way to fund the further development of the fonts. Keep in mind, however, that if the font is distributed to others it must be under the OFL. You won't be able to recover your investment by exclusively selling the font, but you will be making a valuable contribution to the community. Please remember how you have benefited from the contributions of others. - -3.5 I need to make substantial revisions to the font to make it work with my program. It will be a lot of work, and a big investment, and I want to be sure that it can only be distributed with my program. Can I restrict its use? -No. If you redistribute a Modified Version of the font it must be under the OFL. You may not restrict it in any way beyond what the OFL permits and requires. This is intended to ensure that all released improvements to the fonts become available to everyone. But you will likely get an edge over competitors by being the first to distribute a bundle with the enhancements. Again, please remember how you have benefited from the contributions of others. - -3.6 Do I have to make any derivative fonts (including extended source files, build scripts, documentation, etc.) publicly available? -No, but please consider sharing your improvements with others. You may find that you receive in return more than what you gave. - -3.7 If a trademark is claimed in the OFL font, does that trademark need to remain in modified fonts? -Yes, any trademark notices must remain in any derivative fonts to respect trademark laws, but you may add any additional trademarks you claim, officially registered or not. For example if an OFL font called "Foo" contains a notice that "Foo is a trademark of Acme", then if you rename the font to "Bar" when creating a Modified Version, the new trademark notice could say "Foo is a trademark of Acme Inc. - Bar is a trademark of Roadrunner Technologies Ltd.". Trademarks work alongside the OFL and are not subject to the terms of the licensing agreement. Please refer to the appropriate trademark laws. - - -4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL - -4.1 Can I use the SIL OFL for my own fonts? -Yes! We heartily encourage everyone to use the OFL to distribute their own original fonts. It is a carefully constructed license that allows great freedom along with enough artistic integrity protection for the work of the authors as well as clear rules for other contributors and those who redistribute the fonts. The licensing model is used successfully by various organisations, both for-profit and not-for-profit, to release fonts of varying levels of scope and complexity. - -4.2 What do I have to do to apply the OFL to my font? -If you want to release your fonts under the OFL, we recommend you do the following: - -4.2.1 Put your copyright and Reserved Font Names information at the beginning of the main OFL.txt file in place of the dedicated placeholders. Include this file in your release package. - -4.2.2 Put your copyright and the OFL text with Reserved Font Names into your font files (the copyright and license fields). A link to the OFL text on the OFL web site is an acceptable (but not recommended) alternative. Also add this information to any other components (build scripts, glyph databases, documentation, test files, etc). Depending on the format of your fonts and sources, you can use template human-readable headers or machine-readable metadata. - -4.2.3 Write an initial FONTLOG.txt for your font and include it in the release package. - -4.2.4 Include the relevant practical documentation on the license by including the OFL-FAQ.txt in your package. - -4.3 Will you make my font OFL for me? -We won't do the work for you. We can, however, try to answer your questions, unfortunately we do not have the resources to review and check your font packages for correct use of the OFL. - -4.4 Will you distribute my OFL font for me? -No, although if the font is of sufficient quality and general interest we may include a link to it on our partial list of OFL fonts on the OFL web site. You may wish to consider other open font catalogs or hosting services, such as the Unifont Font Guide (http://unifont.org/fontguide), The League of Movable Type (http://theleagueofmovabletype.com), Kernest (http://kernest.com/) or the Open Font Library (http://openfontlibrary.org/), which despite the name has no direct relationship to the OFL or SIL. We do not endorse any particular catalog or hosting service - it is your responsibility to determine if the service is right for you. - -4.5 Why should I use the OFL for my fonts? -- to meet needs for fonts that can be modified to support minority languages -- to provide a legal and clear way for people to respect your work but still use it (and reduce piracy) -- to involve others in your font project -- to enable your fonts to be expanded with new weights and improved writing system/language support -- to allow more technical font developers to add features to your design (such as OpenType and Graphite support) -- to renew the life of an old font lying on your hard drive with no business model -- to allow your font to be included in Libre Software operating systems like Ubuntu -- to give your font world status and wide, unrestricted distribution -- to educate students about quality typeface and font design -- to expand your test base and get more useful feedback -- to extend your reach to new markets when users see your metadata and go to your website -- to get your font more easily into one of the webfont online services -- to attract attention for your commercial fonts -- to make money through webfont services -- to make money by bundling fonts with applications -- to make money adjusting and extending existing open fonts -- to get a better chance that foundations/NGOs/charities/companies who commission fonts will pick you -- to be part of a sharing design and development community -- to give back and contribute to a growing body of font sources - - -5 CHOOSING RESERVED FONT NAMES - -5.1 What are Reserved Font Names? -These are font names, or portions of font names, that the author has chosen to reserve for use only with the Original Version of the font, or for Modified Version(s) created by the original author. - -5.2 Why can't I use the Reserved Font Names in my derivative font names? I'd like people to know where the design came from. -The best way to acknowledge the source of the design is to thank the original authors and any other contributors in the files that are distributed with your revised font (although no acknowledgement is required). The FONTLOG is a natural place to do this. Reserved Font Names ensure that the only fonts that have the original names are the unmodified Original Versions. This allows designers to maintain artistic integrity while allowing collaboration to happen. It eliminates potential confusion and name conflicts. When choosing a name, be creative and avoid names that reuse almost all the same letters in the same order or sound like the original. It will help everyone if Original Versions and Modified Versions can easily be distinguished from one another and from other derivatives. Any substitution and matching mechanism is outside the scope of the license. - -5.3 What do you mean by "primary name as presented to the user"? Are you referring to the font menu name? -Yes, this applies to the font menu name and other mechanisms that specify a font in a document. It would be fine, however, to keep a text reference to the original fonts in the description field, in your modified source file or in documentation provided alongside your derivative as long as no one could be confused that your modified source is the original. But you cannot use the Reserved Font Names in any way to identify the font to the user (unless the Copyright Holder(s) allow(s) it through a separate agreement). Users who install derivatives (Modified Versions) on their systems should not see any of the original Reserved Font Names in their font menus, for example. Again, this is to ensure that users are not confused and do not mistake one font for another and so expect features only another derivative or the Original Version can actually offer. - -5.4 Am I not allowed to use any part of the Reserved Font Names? -You may not use individual words from the Reserved Font Names, but you would be allowed to use parts of words, as long as you do not use any word from the Reserved Font Names entirely. We do not recommend using parts of words because of potential confusion, but it is allowed. For example, if "Foobar" was a Reserved Font Name, you would be allowed to use "Foo" or "bar", although we would not recommend it. Such an unfortunate choice would confuse the users of your fonts as well as make it harder for other designers to contribute. - -5.5 So what should I, as an author, identify as Reserved Font Names? -Original authors are encouraged to name their fonts using clear, distinct names, and only declare the unique parts of the name as Reserved Font Names. For example, the author of a font called "Foobar Sans" would declare "Foobar" as a Reserved Font Name, but not "Sans", as that is a common typographical term, and may be a useful word to use in a derivative font name. Reserved Font Names should also be single words. A font called "Flowing River" should have Reserved Font Names "Flowing" and "River", not "Flowing River". You also need to be very careful about reserving font names which are already linked to trademarks (whether registered or not) which you do not own. - -5.6 Do I, as an author, have to identify any Reserved Font Names? -No, but we strongly encourage you to do so. This is to avoid confusion between your work and Modified Versions. - -5.7 Are any names (such as the main font name) reserved by default? -No. That is a change to the license as of version 1.1. If you want any names to be Reserved Font Names, they must be specified after the copyright statement(s). - -5.8 Is there any situation in which I can use Reserved Font Names for a Modified Version? -The Copyright Holder(s) can give certain trusted parties the right to use any of the Reserved Font Names through separate written agreements. For example, even if "Foobar" is a RFN, you could write up an agreement to give company "XYZ" the right to distribute a modified version with a name that includes "Foobar". This allows for freedom without confusion. - -5.9 Do font rebuilds require a name change? Do I have to change the name of the font when my packaging workflow includes a full rebuild from source? -Yes, all rebuilds which change the font data and the smart code are Modified Versions and the requirements of the OFL apply: you need to respect what the Author(s) have chosen in terms of Reserved Font Names. However if a package (or installer) is simply a wrapper or a compressed structure around the final font - leaving them intact on the inside - then no name change is required. Please get in touch with the author(s) and copyright holder(s) to inquire about the presence of font sources beyond the final font file(s) and the recommended build path. That build path may very well be non-trivial and hard to reproduce accurately by the maintainer. If a full font build path is made available by the upstream author(s) please be aware that any regressions and changes you may introduce when doing a rebuild for packaging purposes is your responsibility as a package maintainer since you are effectively creating a separate branch. You should make it very clear to your users that your rebuilt version is not the canonical one from upstream. - -5.10 Can I add other Reserved Font Names when making a derivative font? -Yes. List your additional Reserved Font Names after your additional copyright statement, as indicated with example placeholders at the top of the OFL.txt file. Be sure you do not remove any exiting RFNs but only add your own. - - -6 ABOUT THE FONTLOG - -6.1 What is this FONTLOG thing exactly? -It has three purposes: 1) to provide basic information on the font to users and other developers, 2) to document changes that have been made to the font or accompanying files, either by the original authors or others, and 3) to provide a place to acknowledge authors and other contributors. Please use it! - -6.2 Is the FONTLOG required? -It is not a requirement of the license, but we strongly recommend you have one. - -6.3 Am I required to update the FONTLOG when making Modified Versions? -No, but users, designers and other developers might get very frustrated with you if you don't. People need to know how derivative fonts differ from the original, and how to take advantage of the changes, or build on them. There are utilities that can help create and maintain a FONTLOG, such as the FONTLOG support in FontForge. - -6.4 What should the FONTLOG look like? -It is typically a separate text file (FONTLOG.txt), but can take other formats. It commonly includes these four sections: - -- brief header describing the FONTLOG itself and name of the font family -- Basic Font Information - description of the font family, purpose and breadth -- ChangeLog - chronological listing of changes -- Acknowledgements - list of authors and contributors with contact information - -It could also include other sections, such as: where to find documentation, how to make contributions, information on contributing organizations, source code details, and a short design guide. See Appendix A for an example FONTLOG. - - -7 MAKING CONTRIBUTIONS TO OFL PROJECTS - -7.1 Can I contribute work to OFL projects? -In many cases, yes. It is common for OFL fonts to be developed by a team of people who welcome contributions from the wider community. Contact the original authors for specific information on how to participate in their projects. - -7.2 Why should I contribute my changes back to the original authors? -It would benefit many people if you contributed back in response to what you've received. Your contributions and improvements to the fonts and other components could be a tremendous help and would encourage others to contribute as well and 'give back'. You will then benefit from other people's contributions as well. Sometimes maintaining your own separate version takes more effort than merging back with the original. Be aware that any contributions, however, must be either your own original creation or work that you own, and you may be asked to affirm that clearly when you contribute. - -7.3 I've made some very nice improvements to the font. Will you consider adopting them and putting them into future Original Versions? -Most authors would be very happy to receive such contributions. Keep in mind that it is unlikely that they would want to incorporate major changes that would require additional work on their end. Any contributions would likely need to be made for all the fonts in a family and match the overall design and style. Authors are encouraged to include a guide to the design with the fonts. It would also help to have contributions submitted as patches or clearly marked changes - the use of smart source revision control systems like subversion, svk, mercurial, git or bzr is a good idea. Please follow the recommendations given by the author(s) in terms of preferred source formats and configuration parameters for sending contributions. If this is not indicated in a FONTLOG or other documentation of the font, consider asking them directly. Examples of useful contributions are bug fixes, additional glyphs, stylistic alternates (and the smart font code to access them) or improved hinting. Keep in mind that some kinds of changes (esp. hinting) may be technically difficult to integrate. - -7.4 How can I financially support the development of OFL fonts? -It is likely that most authors of OFL fonts would accept financial contributions - contact them for instructions on how to do this. Such contributions would support future development. You can also pay for others to enhance the fonts and contribute the results back to the original authors for inclusion in the Original Version. - - -8 ABOUT THE LICENSE ITSELF - -8.1 I see that this is version 1.1 of the license. Will there be later changes? -Version 1.1 is the first minor revision of the OFL. We are confident that version 1.1 will meet most needs, but are open to future improvements. Any revisions would be for future font releases, and previously existing licenses would remain in effect. No retroactive changes are possible, although the Copyright Holder(s) can re-release the font under a revised OFL. All versions will be available on our web site: http://scripts.sil.org/OFL. - -8.2 Does this license restrict the rights of the Copyright Holder(s)? -No. The Copyright Holder(s) still retain(s) all the rights to their creation; they are only releasing a portion of it for use in a specific way. For example, the Copyright Holder(s) may choose to release a 'basic' version of their font under the OFL, but sell a restricted 'enhanced' version. Only the Copyright Holder(s) can do this. - -8.3 Is the OFL a contract or a license? -The OFL is a license and not a contract and so does not require you to sign it to have legal validity. By using, modifying and redistributing components under the OFL you indicate that you accept the license. - -8.4 I really like the terms of the OFL, but want to change it a little. Am I allowed to take ideas and actual wording from the OFL and put them into my own custom license for distributing my fonts? -We strongly recommend against creating your very own unique open licensing model. Using a modified or derivative license will likely cut you off - along with the font(s) under that license - from the community of designers using the OFL, potentially expose you and your users to legal liabilities, and possibly put your work and rights at risk. The OFL went though a community and legal review process that took years of effort, and that review is only applicable to an unmodified OFL. The text of the OFL has been written by SIL (with review and consultation from the community) and is copyright (c) 2005-2010 SIL International. You may re-use the ideas and wording (in part, not in whole) in another non-proprietary license provided that you call your license by another unambiguous name, that you do not use the preamble, that you do not mention SIL and that you clearly present your license as different from the OFL so as not to cause confusion by being too similar to the original. If you feel the OFL does not meet your needs for an open license, please contact us. - -8.5 Can I translate the license and the FAQ into other languages? -SIL certainly recognises the need for people who are not familiar with English to be able to understand the OFL and its use. Making the license very clear and readable has been a key goal for the OFL, but we know that people understand their own language best. - -If you are an experienced translator, you are very welcome to translate the OFL and OFL-FAQ so that designers and users in your language community can understand the license better. But only the original English version of the license has legal value and has been approved by the community. Translations do not count as legal substitutes and should only serve as a way to explain the original license. SIL - as the author and steward of the license for the community at large - does not approve any translation of the OFL as legally valid because even small translation ambiguities could be abused and create problems. - -SIL gives permission to publish unofficial translations into other languages provided that they comply with the following guidelines: - -- Put the following disclaimer in both English and the target language stating clearly that the translation is unofficial: - -"This is an unofficial translation of the SIL Open Font License into . It was not published by SIL International, and does not legally state the distribution terms for fonts that use the OFL. A release under the OFL is only valid when using the original English text. However, we recognize that this unofficial translation will help users and designers not familiar with English to better understand and use the OFL. We encourage designers who consider releasing their creation under the OFL to read the OFL-FAQ in their own language if it is available. Please go to http://scripts.sil.org/OFL for the official version of the license and the accompanying OFL-FAQ." - -- Keep your unofficial translation current and update it at our request if needed, for example if there is any ambiguity which could lead to confusion. - -If you start such a unofficial translation effort of the OFL and OFL-FAQ please let us know. - - -9 ABOUT SIL INTERNATIONAL - -9.1 Who is SIL International and what do they do? -SIL serves language communities worldwide, building their capacity for sustainable language development, by means of research, translation, training and materials development. SIL makes its services available to all without regard to religious belief, political ideology, gender, race, or ethnic background. SIL's members and volunteers share a Christian commitment. - -9.2 What does this have to do with font licensing? -The ability to read, write, type and publish in one's own language is one of the most critical needs for millions of people around the world. This requires fonts that are widely available and support lesser-known languages. SIL develops - and encourages others to develop - a complete stack of writing systems implementation components available under open licenses. This open stack includes input methods, smart fonts, smart rendering libraries and smart applications. There has been a need for a common open license that is specifically applicable to fonts and related software (a crucial component of this stack), so SIL developed the SIL Open Font License with the help of the Free/Libre and Open Source Software community. - -9.3 How can I contact SIL? -Our main web site is: http://www.sil.org/ -Our site about complex scripts is: http://scripts.sil.org/ -Information about this license (and contact information) is at: http://scripts.sil.org/OFL - - -APPENDIX A - FONTLOG EXAMPLE - -Here is an example of the recommended format for a FONTLOG, although other formats are allowed. - ------ -FONTLOG for the GlobalFontFamily fonts - -This file provides detailed information on the GlobalFontFamily Font Software. This information should be distributed along with the GlobalFontFamily fonts and any derivative works. - -Basic Font Information - -GlobalFontFamily is a Unicode typeface family that supports all languages that use the Latin script and its variants, and could be expanded to support other scripts. - -NewWorldFontFamily is based on the GlobalFontFamily and also supports Greek, Hebrew, Cyrillic and Armenian. - -More specifically, this release supports the following Unicode ranges... -This release contains... -Documentation can be found at... -To contribute to the project... - -ChangeLog - -1 August 2008 (Tom Parker) GlobalFontFamily version 1.2.1 -- Tweaked the smart font code (Branch merged with trunk version) -- Provided improved build and debugging environment for smart behaviours - -7 February 2007 (Pat Johnson) NewWorldFontFamily Version 1.3 -- Added Greek and Cyrillic glyphs - -7 March 2006 (Fred Foobar) NewWorldFontFamily Version 1.2 -- Tweaked contextual behaviours - -1 Feb 2005 (Jane Doe) NewWorldFontFamily Version 1.1 -- Improved build script performance and verbosity -- Extended the smart code documentation -- Corrected minor typos in the documentation -- Fixed position of combining inverted breve below (U+032F) -- Added OpenType/Graphite smart code for Armenian -- Added Armenian glyphs (U+0531 -> U+0587) -- Released as "NewWorldFontFamily" - -1 Jan 2005 (Joe Smith) GlobalFontFamily Version 1.0 -- Initial release - -Acknowledgements - -If you make modifications be sure to add your name (N), email (E), web-address (if you have one) (W) and description (D). This list is in alphabetical order. - -N: Jane Doe -E: jane@university.edu -W: http://art.university.edu/projects/fonts -D: Contributor - Armenian glyphs and code - -N: Fred Foobar -E: fred@foobar.org -W: http://foobar.org -D: Contributor - misc Graphite fixes - -N: Pat Johnson -E: pat@fontstudio.org -W: http://pat.fontstudio.org -D: Designer - Greek & Cyrillic glyphs based on Roman design - -N: Tom Parker -E: tom@company.com -W: http://www.company.com/tom/projects/fonts -D: Engineer - original smart font code - -N: Joe Smith -E: joe@fontstudio.org -W: http://joe.fontstudio.org -D: Designer - original Roman glyphs - -Fontstudio.org is an not-for-profit design group whose purpose is... -Foobar.org is a distributed community of developers... -Company.com is a small business who likes to support community designers... -University.edu is a renowed educational institution with a strong design department... ------ diff --git a/site/assets/XITS-README.txt b/site/assets/XITS-README.txt deleted file mode 100644 index 4611489a..00000000 --- a/site/assets/XITS-README.txt +++ /dev/null @@ -1,37 +0,0 @@ -The XITS font project -====================== - -XITS is a Times-like typeface for mathematical and scientific publishing, -based on [STIX fonts][1]. The main mission of XITS is to provide a -version of STIX fonts enriched with the OpenType MATH extension, making -it suitable for high quality mathematic typesetting with OpenType MATH -capable layout systems, like MS Office 2007 and the new TeX engines -XeTeX and LuaTeX. - -XITS font is free, open source font, under [Open Font License][2], -version 1.1. - -The current version of XITS is based on version 1.1.0-beta1 of STIX fonts. - -This is work in progress, feedback, bug reports and even patches are -welcomed. - -Developers ----------- - -The preferred way for modifying the fonts is by editing the SFD files under -`sources`, using [Sorts Mill Tools][3] or [FontForge][4]. When submitting -patches, please make sure they are as clean as possible, avoiding any unrelated -or unnecessary changes. - -To build the fonts from source you need a make program (only GNU Make is -tested), either [Sorts Mill Tools][3] (preferred) or [FontForge][4] with Python -support, and [FontTools][5]. - - - -[1]: http://www.stixfonts.org -[2]: http://scripts.sil.org/OFL -[3]: http://sortsmill.bitbucket.org/ -[4]: http://fontforge.org/ -[5]: http://github.com/behdad/fonttools diff --git a/site/assets/XITS.txt b/site/assets/XITS.txt deleted file mode 100644 index 15435ef4..00000000 --- a/site/assets/XITS.txt +++ /dev/null @@ -1,103 +0,0 @@ -STIX Font License - -24 May 2010 - -Copyright (c) 2001-2010 by the STI Pub Companies, consisting of the American -Institute of Physics, the American Chemical Society, the American Mathematical -Society, the American Physical Society, Elsevier, Inc., and The Institute of -Electrical and Electronic Engineers, Inc. (www.stixfonts.org), with Reserved -Font Name STIX Fonts, STIX Fonts (TM) is a trademark of The Institute of -Electrical and Electronics Engineers, Inc. - -Portions copyright (c) 1998-2003 by MicroPress, Inc. (www.micropress-inc.com), -with Reserved Font Name TM Math. To obtain additional mathematical fonts, please -contact MicroPress, Inc., 68-30 Harrow Street, Forest Hills, NY 11375, USA, -Phone: (718) 575-1816. - -Portions copyright (c) 1990 by Elsevier, Inc. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - ---------------------------------------------------------------------------- -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ---------------------------------------------------------------------------- - -PREAMBLE - -The goals of the Open Font License (OFL) are to stimulate worldwide development -of collaborative font projects, to support the font creation efforts of academic -and linguistic communities, and to provide a free and open framework in which -fonts may be shared and improved in partnership with others. - -The OFL allows the licensed fonts to be used, studied, modified and redistributed -freely as long as they are not sold by themselves. The fonts, including any -derivative works, can be bundled, embedded, redistributed and/or sold with any -software provided that any reserved names are not used by derivative works. The -fonts and derivatives, however, cannot be released under any other type of license. -The requirement for fonts to remain under this license does not apply to any -document created using the fonts or their derivatives. - -DEFINITIONS - -"Font Software" refers to the set of files released by the Copyright Holder(s) under -this license and clearly marked as such. This may include source files, build -scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the copyright -statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, or -substituting -- in part or in whole -- any of the components of the Original Version, -by changing formats or by porting the Font Software to a new environment. - -"Author" refers to any designer, engineer, programmer, technical writer or other -person who contributed to the Font Software. - -PERMISSION & CONDITIONS - -Permission is hereby granted, free of charge, to any person obtaining a copy of the -Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell -modified and unmodified copies of the Font Software, subject to the following -conditions: - -1) Neither the Font Software nor any of its individual components, in Original or -Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, redistributed -and/or sold with any software, provided that each copy contains the above copyright -notice and this license. These can be included either as stand-alone text files, -human-readable headers or in the appropriate machine-readable metadata fields within -text or binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless -explicit written permission is granted by the corresponding Copyright Holder. This -restriction only applies to the primary font name as presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall -not be used to promote, endorse or advertise any Modified Version, except to -acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with -their explicit written permission. - -5) The Font Software, modified or unmodified, in part or in whole, must be distributed -entirely under this license, and must not be distributed under any other license. The -requirement for fonts to remain under this license does not apply to any document -created using the Font Software. - -TERMINATION - -This license becomes null and void if any of the above conditions are not met. - -DISCLAIMER - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER -RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR -INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/site/assets/latinmodernmath.woff2 b/site/assets/latinmodernmath.woff2 deleted file mode 100644 index 81369b87..00000000 Binary files a/site/assets/latinmodernmath.woff2 and /dev/null differ diff --git a/site/assets/mhchem.min.js b/site/assets/mhchem.min.js deleted file mode 100644 index 2eafa389..00000000 --- a/site/assets/mhchem.min.js +++ /dev/null @@ -1 +0,0 @@ -temml.__defineMacro("\\ce",(function(t){return chemParse(t.consumeArgs(1)[0],"ce")})),temml.__defineMacro("\\pu",(function(t){return chemParse(t.consumeArgs(1)[0],"pu")})),temml.__defineMacro("\\uniDash","{\\rule{0.672em}{0.06em}}"),temml.__defineMacro("\\triDash","{\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}}"),temml.__defineMacro("\\tripleDash","\\kern0.075em\\raise0.25em{\\triDash}\\kern0.075em"),temml.__defineMacro("\\tripleDashOverLine","\\kern0.075em\\mathrlap{\\raise0.125em{\\uniDash}}\\raise0.34em{\\triDash}\\kern0.075em"),temml.__defineMacro("\\tripleDashOverDoubleLine","\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\triDash}}\\raise0.27em{\\uniDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em"),temml.__defineMacro("\\tripleDashBetweenDoubleLine","\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\uniDash}}\\raise0.27em{\\triDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em");var chemParse=function(t,e){for(var r="",a=t.length&&t[t.length-1].loc.start,n=t.length-1;n>=0;n--)t[n].loc.start>a&&(r+=" ",a=t[n].loc.start),r+=t[n].text,a+=t[n].text.length;return texify.go(mhchemParser.go(r,e))},mhchemParser={go:function(t,e){if(!t)return[];void 0===e&&(e="ce");var r,a="0",n={};n.parenthesisLevel=0,t=(t=(t=t.replace(/\n/g," ")).replace(/[\u2212\u2013\u2014\u2010]/g,"-")).replace(/[\u2026]/g,"...");for(var o=10,i=[];;){r!==t?(o=10,r=t):o--;var c=mhchemParser.stateMachines[e],s=c.transitions[a]||c.transitions["*"];t:for(var u=0;u0))return i;if(m.revisit||(t=p.remainder),!m.toContinue)break t}}if(o<=0)throw["MhchemBugU","mhchem bug U. Please report."]}},concatArray:function(t,e){if(e)if(Array.isArray(e))for(var r=0;r":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(t){return mhchemParser.patterns.findObserveGroups(t,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(t){return mhchemParser.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",!0)},"\\x{}":function(t){return mhchemParser.patterns.findObserveGroups(t,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}0":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\color{","","","}")},"\\color{(...)}{(...)}1":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\color{","","","}","{","","","}")},"\\color(...){(...)}2":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(t){return mhchemParser.patterns.findObserveGroups(t,"\\ce{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(t){var e;if(e=t.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/))return{match_:e[0],remainder:t.substr(e[0].length)};var r=mhchemParser.patterns.findObserveGroups(t,"","$","$","");return r&&(e=r.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/))?{match_:e[0],remainder:t.substr(e[0].length)}:null},amount2:function(t){return this.amount(t)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(t){if(t.match(/^\([a-z]+\)$/))return null;var e=t.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);return e?{match_:e[0],remainder:t.substr(e[0].length)}:null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(t,e,r,a,n,o,i,c,s,u){var p=function(t,e){if("string"==typeof e)return 0!==t.indexOf(e)?null:e;var r=t.match(e);return r?r[0]:null},m=p(t,e);if(null===m)return null;if(t=t.substr(m.length),null===(m=p(t,r)))return null;var h=function(t,e,r){for(var a=0;e":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:!1},nextState:"2"},q:{action_:{type_:"- after o/d",option:!1},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:!0},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{}},space:{a:{nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". |* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}0":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:!0},as:{action_:["output","sb=true"],nextState:"1",revisit:!0},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:!0},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(t,e){var r;if((t.d||"").match(/^[0-9]+$/)){var a=t.d;t.d=void 0,r=this.output(t),t.b=a}else r=this.output(t);return mhchemParser.actions["o="](t,e),r},"d= kv":function(t,e){t.d=e,t.dType="kv"},"charge or bond":function(t,e){if(t.beginsWithBond){var r=[];return mhchemParser.concatArray(r,this.output(t)),mhchemParser.concatArray(r,mhchemParser.actions.bond(t,e,"-")),r}t.d=e},"- after o/d":function(t,e,r){var a=mhchemParser.patterns.match_("orbital",t.o||""),n=mhchemParser.patterns.match_("one lowercase greek letter $",t.o||""),o=mhchemParser.patterns.match_("one lowercase latin letter $",t.o||""),i=mhchemParser.patterns.match_("$one lowercase latin letter$ $",t.o||""),c="-"===e&&(a&&""===a.remainder||n||o||i);!c||t.a||t.b||t.p||t.d||t.q||a||!o||(t.o="$"+t.o+"$");var s=[];return c?(mhchemParser.concatArray(s,this.output(t)),s.push({type_:"hyphen"})):(a=mhchemParser.patterns.match_("digits",t.d||""),r&&a&&""===a.remainder?(mhchemParser.concatArray(s,mhchemParser.actions["d="](t,e)),mhchemParser.concatArray(s,this.output(t))):(mhchemParser.concatArray(s,this.output(t)),mhchemParser.concatArray(s,mhchemParser.actions.bond(t,e,"-")))),s},"a to o":function(t){t.o=t.a,t.a=void 0},"sb=true":function(t){t.sb=!0},"sb=false":function(t){t.sb=!1},"beginsWithBond=true":function(t){t.beginsWithBond=!0},"beginsWithBond=false":function(t){t.beginsWithBond=!1},"parenthesisLevel++":function(t){t.parenthesisLevel++},"parenthesisLevel--":function(t){t.parenthesisLevel--},"state of aggregation":function(t,e){return{type_:"state of aggregation",p1:mhchemParser.go(e,"o")}},comma:function(t,e){var r=e.replace(/\s*$/,"");return r!==e&&0===t.parenthesisLevel?{type_:"comma enumeration L",p1:r}:{type_:"comma enumeration M",p1:r}},output:function(t,e,r){var a,n,o;t.r?(n="M"===t.rdt?mhchemParser.go(t.rd,"tex-math"):"T"===t.rdt?[{type_:"text",p1:t.rd||""}]:mhchemParser.go(t.rd),o="M"===t.rqt?mhchemParser.go(t.rq,"tex-math"):"T"===t.rqt?[{type_:"text",p1:t.rq||""}]:mhchemParser.go(t.rq),a={type_:"arrow",r:t.r,rd:n,rq:o}):(a=[],(t.a||t.b||t.p||t.o||t.q||t.d||r)&&(t.sb&&a.push({type_:"entitySkip"}),t.o||t.q||t.d||t.b||t.p||2===r?t.o||t.q||t.d||!t.b&&!t.p?t.o&&"kv"===t.dType&&mhchemParser.patterns.match_("d-oxidation$",t.d||"")?t.dType="oxidation":t.o&&"kv"===t.dType&&!t.q&&(t.dType=void 0):(t.o=t.a,t.d=t.b,t.q=t.p,t.a=t.b=t.p=void 0):(t.o=t.a,t.a=void 0),a.push({type_:"chemfive",a:mhchemParser.go(t.a,"a"),b:mhchemParser.go(t.b,"bd"),p:mhchemParser.go(t.p,"pq"),o:mhchemParser.go(t.o,"o"),q:mhchemParser.go(t.q,"pq"),d:mhchemParser.go(t.d,"oxidation"===t.dType?"oxidation":"bd"),dType:t.dType})));for(var i in t)"parenthesisLevel"!==i&&"beginsWithBond"!==i&&delete t[i];return a},"oxidation-output":function(t,e){var r=["{"];return mhchemParser.concatArray(r,mhchemParser.go(e,"oxidation")),r.push("}"),r},"frac-output":function(t,e){return{type_:"frac-ce",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"overset-output":function(t,e){return{type_:"overset",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"underset-output":function(t,e){return{type_:"underset",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"underbrace-output":function(t,e){return{type_:"underbrace",p1:mhchemParser.go(e[0]),p2:mhchemParser.go(e[1])}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:mhchemParser.go(e[1])}},"r=":function(t,e){t.r=e},"rdt=":function(t,e){t.rdt=e},"rd=":function(t,e){t.rd=e},"rqt=":function(t,e){t.rqt=e},"rq=":function(t,e){t.rq=e},operator:function(t,e,r){return{type_:"operator",kind_:r||e}}}},a:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},"$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"{text}"}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(t){if(t.text_){var e={type_:"text",p1:t.text_};for(var r in t)delete t[r];return e}}}},pq:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{nextState:"!f",revisit:!0}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{nextState:"f",revisit:!0}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"!f",revisit:!0}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(t,e){return{type_:"state of aggregation subscript",p1:mhchemParser.go(e,"o")}},"color-output":function(t,e){return{type_:"color",color1:e[0],color2:mhchemParser.go(e[1],"pq")}}}},bd:{transitions:mhchemParser.createTransitions({empty:{"*":{}},x$:{0:{nextState:"!f",revisit:!0}},formula$:{0:{nextState:"f",revisit:!0}},else:{0:{nextState:"!f",revisit:!0}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(t,e){return{type_:"color",color1:e[0],color2:mhchemParser.go(e[1],"bd")}}}},oxidation:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(t,e){return{type_:"roman numeral",p1:e||""}}}},"tex-math":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var r in t)delete t[r];return e}}}},"tex-math tight":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(t,e){t.o=(t.o||"")+"{"+e+"}"},output:function(t){if(t.o){var e={type_:"tex-math",p1:t.o};for(var r in t)delete t[r];return e}}}},"9,9":{transitions:mhchemParser.createTransitions({empty:{"*":{}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return{type_:"commaDecimal"}}}},pu:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(t,e){var r=[];return"+-"===e[0]||"+/-"===e[0]?r.push("\\pm "):e[0]&&r.push(e[0]),e[1]&&(mhchemParser.concatArray(r,mhchemParser.go(e[1],"pu-9,9")),e[2]&&(e[2].match(/[,.]/)?mhchemParser.concatArray(r,mhchemParser.go(e[2],"pu-9,9")):r.push(e[2])),e[3]=e[4]||e[3],e[3]&&(e[3]=e[3].trim(),"e"===e[3]||"*"===e[3].substr(0,1)?r.push({type_:"cdot"}):r.push({type_:"times"}))),e[3]&&r.push("10^{"+e[5]+"}"),r},"number^":function(t,e){var r=[];return"+-"===e[0]||"+/-"===e[0]?r.push("\\pm "):e[0]&&r.push(e[0]),mhchemParser.concatArray(r,mhchemParser.go(e[1],"pu-9,9")),r.push("^{"+e[2]+"}"),r},operator:function(t,e,r){return{type_:"operator",kind_:r||e}},space:function(){return{type_:"pu-space-1"}},output:function(t){var e,r=mhchemParser.patterns.match_("{(...)}",t.d||"");r&&""===r.remainder&&(t.d=r.match_);var a=mhchemParser.patterns.match_("{(...)}",t.q||"");if(a&&""===a.remainder&&(t.q=a.match_),t.d&&(t.d=t.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.d=t.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F")),t.q){t.q=t.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),t.q=t.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");var n={d:mhchemParser.go(t.d,"pu"),q:mhchemParser.go(t.q,"pu")};"//"===t.o?e={type_:"pu-frac",p1:n.d,p2:n.q}:(e=n.d,n.d.length>1||n.q.length>1?e.push({type_:" / "}):e.push({type_:"/"}),mhchemParser.concatArray(e,n.q))}else e=mhchemParser.go(t.d,"pu-2");for(var o in t)delete t[o];return e}}},"pu-2":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return{type_:"tight cdot"}},"^(-1)":function(t,e){t.rm+="^{"+e+"}"},space:function(){return{type_:"pu-space-2"}},output:function(t){var e=[];if(t.rm){var r=mhchemParser.patterns.match_("{(...)}",t.rm||"");e=r&&""===r.remainder?mhchemParser.go(r.match_,"pu"):{type_:"rm",p1:t.rm}}for(var a in t)delete t[a];return e}}},"pu-9,9":{transitions:mhchemParser.createTransitions({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return{type_:"commaDecimal"}},"output-0":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){var r=t.text_.length%3;0===r&&(r=3);for(var a=t.text_.length-3;a>0;a-=3)e.push(t.text_.substr(a,3)),e.push({type_:"1000 separator"});e.push(t.text_.substr(0,r)),e.reverse()}else e.push(t.text_);for(var n in t)delete t[n];return e},"output-o":function(t){var e=[];if(t.text_=t.text_||"",t.text_.length>4){for(var r=t.text_.length-3,a=0;a":case"→":case"⟶":return"\\yields";case"<-":return"\\yieldsLeft";case"<->":return"\\mesomerism";case"<--\x3e":return"\\yieldsLeftRight";case"<=>":case"⇌":return"\\equilibrium";case"<=>>":return"\\equilibriumRight";case"<<=>":return"\\equilibriumLeft";default:throw assertNever(t),["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(t){switch(t){case"-":case"1":return"{-}";case"=":case"2":return"{=}";case"#":case"3":return"{\\equiv}";case"~":return"{\\tripleDash}";case"~-":return"{\\tripleDashOverLine}";case"~=":case"~--":return"{\\tripleDashOverDoubleLine}";case"-~-":return"{\\tripleDashBetweenDoubleLine}";case"...":return"{{\\cdot}{\\cdot}{\\cdot}}";case"....":return"{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case"->":return"{\\rightarrow}";case"<-":return"{\\leftarrow}";case"<":return"{<}";case">":return"{>}";default:throw assertNever(t),["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(t){switch(t){case"+":return" {}+{} ";case"-":return" {}-{} ";case"=":return" {}={} ";case"<":return" {}<{} ";case">":return" {}>{} ";case"<<":return" {}\\ll{} ";case">>":return" {}\\gg{} ";case"\\pm":return" {}\\pm{} ";case"\\approx":case"$\\approx$":return" {}\\approx{} ";case"v":case"(v)":return" \\downarrow{} ";case"^":case"(^)":return" \\uparrow{} ";default:throw assertNever(t),["MhchemBugT","mhchem bug T. Please report."]}}};function assertNever(t){}function assertString(t){} \ No newline at end of file diff --git a/site/assets/physics.js b/site/assets/physics.js deleted file mode 100644 index 803ccc31..00000000 --- a/site/assets/physics.js +++ /dev/null @@ -1,132 +0,0 @@ -/* eslint-disable no-undef */ - -/**************************************************** - * - * physics.js - * - * Implements the Physics Package for LaTeX input. - * - * --------------------------------------------------------------------- - * - * The original version of this file is licensed as follows: - * Copyright (c) 2015-2016 Kolen Cheung . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * --------------------------------------------------------------------- - * - * This file has been revised from the original in the following ways: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \Re and \Im are not used, to avoid conflict with existing LaTeX letters. - * - * This revision of the file is released under the MIT license. - * https://mit-license.org/ - */ -temml.__defineMacro("\\quantity", "{\\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\qty", "{\\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\pqty", "{\\left( #1 \\right)}"); -temml.__defineMacro("\\bqty", "{\\left[ #1 \\right]}"); -temml.__defineMacro("\\vqty", "{\\left\\vert #1 \\right\\vert}"); -temml.__defineMacro("\\Bqty", "{\\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\absolutevalue", "{\\left\\vert #1 \\right\\vert}"); -temml.__defineMacro("\\abs", "{\\left\\vert #1 \\right\\vert}"); -temml.__defineMacro("\\norm", "{\\left\\Vert #1 \\right\\Vert}"); -temml.__defineMacro("\\evaluated", "{\\left.#1 \\right\\vert}"); -temml.__defineMacro("\\eval", "{\\left.#1 \\right\\vert}"); -temml.__defineMacro("\\order", "{\\mathcal{O} \\left( #1 \\right)}"); -temml.__defineMacro("\\commutator", "{\\left[ #1 , #2 \\right]}"); -temml.__defineMacro("\\comm", "{\\left[ #1 , #2 \\right]}"); -temml.__defineMacro("\\anticommutator", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\acomm", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\poissonbracket", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\pb", "{\\left\\{ #1 , #2 \\right\\}}"); -temml.__defineMacro("\\vectorbold", "{\\boldsymbol{ #1 }}"); -temml.__defineMacro("\\vb", "{\\boldsymbol{ #1 }}"); -temml.__defineMacro("\\vectorarrow", "{\\vec{\\boldsymbol{ #1 }}}"); -temml.__defineMacro("\\va", "{\\vec{\\boldsymbol{ #1 }}}"); -temml.__defineMacro("\\vectorunit", "{{\\boldsymbol{\\hat{ #1 }}}}"); -temml.__defineMacro("\\vu", "{{\\boldsymbol{\\hat{ #1 }}}}"); -temml.__defineMacro("\\dotproduct", "\\mathbin{\\boldsymbol\\cdot}"); -temml.__defineMacro("\\vdot", "{\\boldsymbol\\cdot}"); -temml.__defineMacro("\\crossproduct", "\\mathbin{\\boldsymbol\\times}"); -temml.__defineMacro("\\cross", "\\mathbin{\\boldsymbol\\times}"); -temml.__defineMacro("\\cp", "\\mathbin{\\boldsymbol\\times}"); -temml.__defineMacro("\\gradient", "{\\boldsymbol\\nabla}"); -temml.__defineMacro("\\grad", "{\\boldsymbol\\nabla}"); -temml.__defineMacro("\\divergence", "{\\grad\\vdot}"); -//temml.__defineMacro("\\div", "{\\grad\\vdot}"); Not included in Temml. Conflicts w/LaTeX \div -temml.__defineMacro("\\curl", "{\\grad\\cross}"); -temml.__defineMacro("\\laplacian", "\\nabla^2"); -temml.__defineMacro("\\tr", "{\\operatorname{tr}}"); -temml.__defineMacro("\\Tr", "{\\operatorname{Tr}}"); -temml.__defineMacro("\\rank", "{\\operatorname{rank}}"); -temml.__defineMacro("\\erf", "{\\operatorname{erf}}"); -temml.__defineMacro("\\Res", "{\\operatorname{Res}}"); -temml.__defineMacro("\\principalvalue", "{\\mathcal{P}}"); -temml.__defineMacro("\\pv", "{\\mathcal{P}}"); -temml.__defineMacro("\\PV", "{\\operatorname{P.V.}}"); -// Temml does not use the next two lines. They conflict with LaTeX letters. -//temml.__defineMacro("\\Re", "{\\operatorname{Re} \\left\\{ #1 \\right\\}}"); -//temml.__defineMacro("\\Im", "{\\operatorname{Im} \\left\\{ #1 \\right\\}}"); -temml.__defineMacro("\\qqtext", "{\\quad\\text{ #1 }\\quad}"); -temml.__defineMacro("\\qq", "{\\quad\\text{ #1 }\\quad}"); -temml.__defineMacro("\\qcomma", "{\\text{,}\\quad}"); -temml.__defineMacro("\\qc", "{\\text{,}\\quad}"); -temml.__defineMacro("\\qcc", "{\\quad\\text{c.c.}\\quad}"); -temml.__defineMacro("\\qif", "{\\quad\\text{if}\\quad}"); -temml.__defineMacro("\\qthen", "{\\quad\\text{then}\\quad}"); -temml.__defineMacro("\\qelse", "{\\quad\\text{else}\\quad}"); -temml.__defineMacro("\\qotherwise", "{\\quad\\text{otherwise}\\quad}"); -temml.__defineMacro("\\qunless", "{\\quad\\text{unless}\\quad}"); -temml.__defineMacro("\\qgiven", "{\\quad\\text{given}\\quad}"); -temml.__defineMacro("\\qusing", "{\\quad\\text{using}\\quad}"); -temml.__defineMacro("\\qassume", "{\\quad\\text{assume}\\quad}"); -temml.__defineMacro("\\qsince", "{\\quad\\text{since}\\quad}"); -temml.__defineMacro("\\qlet", "{\\quad\\text{let}\\quad}"); -temml.__defineMacro("\\qfor", "{\\quad\\text{for}\\quad}"); -temml.__defineMacro("\\qall", "{\\quad\\text{all}\\quad}"); -temml.__defineMacro("\\qeven", "{\\quad\\text{even}\\quad}"); -temml.__defineMacro("\\qodd", "{\\quad\\text{odd}\\quad}"); -temml.__defineMacro("\\qinteger", "{\\quad\\text{integer}\\quad}"); -temml.__defineMacro("\\qand", "{\\quad\\text{and}\\quad}"); -temml.__defineMacro("\\qor", "{\\quad\\text{or}\\quad}"); -temml.__defineMacro("\\qas", "{\\quad\\text{as}\\quad}"); -temml.__defineMacro("\\qin", "{\\quad\\text{in}\\quad}"); -temml.__defineMacro("\\differential", "{\\text{d}}"); -temml.__defineMacro("\\dd", "{\\text{d}}"); -temml.__defineMacro("\\derivative", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -temml.__defineMacro("\\dv", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -temml.__defineMacro("\\partialderivative", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}"); -temml.__defineMacro("\\pdv", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}"); -temml.__defineMacro("\\variation", "{\\delta}"); -temml.__defineMacro("\\var", "{\\delta}"); -temml.__defineMacro("\\functionalderivative", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -temml.__defineMacro("\\fdv", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -temml.__defineMacro("\\innerproduct", "{\\left\\langle {#1} \\mid { #2} \\right\\rangle}"); -temml.__defineMacro("\\outerproduct", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\dyad", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\ketbra", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\op", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -temml.__defineMacro("\\expectationvalue", "{\\left\\langle {#1 } \\right\\rangle}"); -temml.__defineMacro("\\expval", "{\\left\\langle {#1 } \\right\\rangle}"); -temml.__defineMacro("\\ev", "{\\left\\langle {#1 } \\right\\rangle}"); -temml.__defineMacro("\\matrixelement", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -temml.__defineMacro("\\matrixel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -temml.__defineMacro("\\mel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); diff --git a/site/assets/temml.min.js b/site/assets/temml.min.js deleted file mode 100644 index b71c30cd..00000000 --- a/site/assets/temml.min.js +++ /dev/null @@ -1 +0,0 @@ -var temml=function(){"use strict";class e{constructor(t,r){let n,o=" "+t;const s=r&&r.loc;if(s&&s.start<=s.end){const e=s.lexer.input;n=s.start;const t=s.end;n===e.length?o+=" at end of input: ":o+=" at position "+(n+1)+": ";const r=e.slice(n,t).replace(/[^]/g,"$&̲");let a,i;a=n>15?"…"+e.slice(n-15,n):e.slice(0,n),i=t+15":">","<":"<",'"':""","'":"'"},n=/[&><"']/g;const o=function(e){return"ordgroup"===e.type||"color"===e.type?1===e.body.length?o(e.body[0]):e:"font"===e.type?o(e.body):e};var s={contains:function(e,t){return-1!==e.indexOf(t)},deflt:function(e,t){return void 0===e?t:e},escape:function(e){return String(e).replace(n,(e=>r[e]))},hyphenate:function(e){return e.replace(t,"-$1").toLowerCase()},getBaseElem:o,isCharacterBox:function(e){const t=o(e);return"mathord"===t.type||"textord"===t.type||"atom"===t.type},protocolFromUrl:function(e){const t=/^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(e);return null!=t?t[1]:"_relative"},round:function(e){return+e.toFixed(4)},consolidateText:e=>{if("mrow"!==e.type)return e;if(0===e.children.length)return e;const t=e.children[0];if(!t.attributes||"mtext"!==t.type)return e;const r=t.attributes.mathvariant||"";for(let n=1;n0&&" "===t.children[0].text.charAt(n-1)&&(t.children[0].text=t.children[0].text.slice(0,-1)+" "),t}};class a{constructor(e){e=e||{},this.displayMode=s.deflt(e.displayMode,!1),this.annotate=s.deflt(e.annotate,!1),this.elementIsMath=s.deflt(e.elementIsMath,!1),this.leqno=s.deflt(e.leqno,!1),this.errorColor=s.deflt(e.errorColor,"#b22222"),this.preventTagLap=s.deflt(e.preventTagLap,!1),this.macros=e.macros||{},this.xml=s.deflt(e.xml,!1),this.colorIsTextColor=s.deflt(e.colorIsTextColor,!1),this.strict=s.deflt(e.strict,!1),this.trust=s.deflt(e.trust,!1),this.maxSize=void 0===e.maxSize?[1/0,1/0]:Array.isArray(e.maxSize)?e.maxSize:[1/0,1/0],this.maxExpand=Math.max(0,s.deflt(e.maxExpand,1e3))}isTrusted(e){e.url&&!e.protocol&&(e.protocol=s.protocolFromUrl(e.url));const t="function"==typeof this.trust?this.trust(e):this.trust;return Boolean(t)}}const i={},l={};function c({type:e,names:t,props:r,handler:n,mathmlBuilder:o}){const s={type:e,numArgs:r.numArgs,argTypes:r.argTypes,allowedInArgument:!!r.allowedInArgument,allowedInText:!!r.allowedInText,allowedInMath:void 0===r.allowedInMath||r.allowedInMath,numOptionalArgs:r.numOptionalArgs||0,infix:!!r.infix,primitive:!!r.primitive,handler:n};for(let e=0;ee.toText())).join("")}}const h=function(e){return e.filter((e=>e)).join(" ")},g=function(e,t){this.classes=e||[],this.attributes={},this.style=t||{}},f=function(e){const t=document.createElement(e);t.className=h(this.classes);for(const e in this.style)Object.prototype.hasOwnProperty.call(this.style,e)&&(t.style[e]=this.style[e]);for(const e in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,e)&&t.setAttribute(e,this.attributes[e]);for(let e=0;e`,t};class y{constructor(e,t,r){g.call(this,e,r),this.children=t||[]}setAttribute(e,t){this.attributes[e]=t}toNode(){return f.call(this,"span")}toMarkup(){return b.call(this,"span")}}class w{constructor(e){this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return s.escape(this.text)}}class x{constructor(e,t,r){this.alt=t,this.src=e,this.classes=["mord"],this.style=r}hasClass(e){return s.contains(this.classes,e)}toNode(){const e=document.createElement("img");e.src=this.src,e.alt=this.alt,e.className="mord";for(const t in this.style)Object.prototype.hasOwnProperty.call(this.style,t)&&(e.style[t]=this.style[t]);return e}toMarkup(){let e=`${this.alt}0&&(e.className=h(this.classes));for(const t in this.style)Object.prototype.hasOwnProperty.call(this.style,t)&&(e.style[t]=this.style[t]);for(let t=0;t0&&(e+=` class="${s.escape(h(this.classes))}"`);let t="";for(const e in this.style)Object.prototype.hasOwnProperty.call(this.style,e)&&(t+=`${s.hyphenate(e)}:${this.style[e]};`);t&&(e+=` style="${t}"`),e+=">";for(let t=0;t",e}toText(){return this.children.map((e=>e.toText())).join("")}}class A{constructor(e){this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return s.escape(this.toText())}toText(){return this.text}}const v=e=>{let t;return 1===e.length&&"mrow"===e[0].type?(t=e.pop(),t.type="mstyle"):t=new k("mstyle",e),t};var T={MathNode:k,TextNode:A,newDocumentFragment:function(e){return new d(e)}};const N={widehat:"^",widecheck:"ˇ",widetilde:"~",wideparen:"⏜",utilde:"~",overleftarrow:"←",underleftarrow:"←",xleftarrow:"←",overrightarrow:"→",underrightarrow:"→",xrightarrow:"→",underbrace:"⏟",overbrace:"⏞",overgroup:"⏠",overparen:"⏜",undergroup:"⏡",underparen:"⏝",overleftrightarrow:"↔",underleftrightarrow:"↔",xleftrightarrow:"↔",Overrightarrow:"⇒",xRightarrow:"⇒",overleftharpoon:"↼",xleftharpoonup:"↼",overrightharpoon:"⇀",xrightharpoonup:"⇀",xLeftarrow:"⇐",xLeftrightarrow:"⇔",xhookleftarrow:"↩",xhookrightarrow:"↪",xmapsto:"↦",xrightharpoondown:"⇁",xleftharpoondown:"↽",xtwoheadleftarrow:"↞",xtwoheadrightarrow:"↠",xlongequal:"=",xrightleftarrows:"⇄",yields:"→",yieldsLeft:"←",mesomerism:"↔",longrightharpoonup:"⇀",longleftharpoondown:"↽",eqrightharpoonup:"⇀",eqleftharpoondown:"↽","\\cdrightarrow":"→","\\cdleftarrow":"←","\\cdlongequal":"="};var S=function(e){const t=new T.TextNode(N[e.slice(1)]),r=new T.MathNode("mo",[t]);return r.setAttribute("stretchy","true"),r};const q={bin:1,close:1,inner:1,open:1,punct:1,rel:1},B={"accent-token":1,mathord:1,"op-token":1,spacing:1,textord:1},M={math:{},text:{}};function O(e,t,r,n,o){M[e][n]={group:t,replace:r},o&&r&&(M[e][r]=M[e][n])}const C="math",z="text",E="accent-token",I="bin",L="close",$="inner",F="mathord",G="op-token",D="open",P="punct",R="rel",j="spacing",U="textord";O(C,R,"≡","\\equiv",!0),O(C,R,"≺","\\prec",!0),O(C,R,"≻","\\succ",!0),O(C,R,"∼","\\sim",!0),O(C,R,"⟂","\\perp",!0),O(C,R,"⪯","\\preceq",!0),O(C,R,"⪰","\\succeq",!0),O(C,R,"≃","\\simeq",!0),O(C,R,"≌","\\backcong",!0),O(C,R,"|","\\mid",!0),O(C,R,"≪","\\ll",!0),O(C,R,"≫","\\gg",!0),O(C,R,"≍","\\asymp",!0),O(C,R,"∥","\\parallel"),O(C,R,"⋈","\\bowtie",!0),O(C,R,"⌣","\\smile",!0),O(C,R,"⊑","\\sqsubseteq",!0),O(C,R,"⊒","\\sqsupseteq",!0),O(C,R,"≐","\\doteq",!0),O(C,R,"⌢","\\frown",!0),O(C,R,"∋","\\ni",!0),O(C,R,"∌","\\notni",!0),O(C,R,"∝","\\propto",!0),O(C,R,"⊢","\\vdash",!0),O(C,R,"⊣","\\dashv",!0),O(C,R,"∋","\\owns"),O(C,R,"≘","\\arceq",!0),O(C,R,"≙","\\wedgeq",!0),O(C,R,"≚","\\veeeq",!0),O(C,R,"≛","\\stareq",!0),O(C,R,"≝","\\eqdef",!0),O(C,R,"≞","\\measeq",!0),O(C,R,"≟","\\questeq",!0),O(C,R,"≠","\\ne",!0),O(C,R,"≠","\\neq"),O(C,R,"∷","\\dblcolon",!0),O(C,R,"≔","\\coloneqq",!0),O(C,R,"≕","\\eqqcolon",!0),O(C,R,"∹","\\eqcolon",!0),O(C,R,"⩴","\\Coloneqq",!0),O(C,P,".","\\ldotp"),O(C,P,"·","\\cdotp"),O(C,U,"#","\\#"),O(z,U,"#","\\#"),O(C,U,"&","\\&"),O(z,U,"&","\\&"),O(C,U,"ℵ","\\aleph",!0),O(C,U,"∀","\\forall",!0),O(C,U,"ℏ","\\hbar",!0),O(C,U,"∃","\\exists",!0),O(C,U,"∇","\\nabla",!0),O(C,U,"♭","\\flat",!0),O(C,U,"ℓ","\\ell",!0),O(C,U,"♮","\\natural",!0),O(C,U,"Å","\\AA",!0),O(z,U,"Å","\\AA",!0),O(C,U,"♣","\\clubsuit",!0),O(C,U,"♧","\\varclubsuit",!0),O(C,U,"℘","\\wp",!0),O(C,U,"♯","\\sharp",!0),O(C,U,"♢","\\diamondsuit",!0),O(C,U,"♦","\\vardiamondsuit",!0),O(C,U,"ℜ","\\Re",!0),O(C,U,"♡","\\heartsuit",!0),O(C,U,"♥","\\varheartsuit",!0),O(C,U,"ℑ","\\Im",!0),O(C,U,"♠","\\spadesuit",!0),O(C,U,"♤","\\varspadesuit",!0),O(C,U,"♀","\\female",!0),O(C,U,"♂","\\male",!0),O(C,U,"§","\\S",!0),O(z,U,"§","\\S"),O(C,U,"¶","\\P",!0),O(z,U,"¶","\\P"),O(z,U,"☺","\\smiley",!0),O(C,U,"☺","\\smiley",!0),O(C,U,"†","\\dag"),O(z,U,"†","\\dag"),O(z,U,"†","\\textdagger"),O(C,U,"‡","\\ddag"),O(z,U,"‡","\\ddag"),O(z,U,"‡","\\textdaggerdbl"),O(C,L,"⎱","\\rmoustache",!0),O(C,D,"⎰","\\lmoustache",!0),O(C,L,"⟯","\\rgroup",!0),O(C,D,"⟮","\\lgroup",!0),O(C,I,"∓","\\mp",!0),O(C,I,"⊖","\\ominus",!0),O(C,I,"⊎","\\uplus",!0),O(C,I,"⊓","\\sqcap",!0),O(C,I,"∗","\\ast"),O(C,I,"⊔","\\sqcup",!0),O(C,I,"◯","\\bigcirc",!0),O(C,I,"∙","\\bullet",!0),O(C,I,"‡","\\ddagger"),O(C,I,"≀","\\wr",!0),O(C,I,"⨿","\\amalg"),O(C,I,"&","\\And"),O(C,R,"⟵","\\longleftarrow",!0),O(C,R,"⇐","\\Leftarrow",!0),O(C,R,"⟸","\\Longleftarrow",!0),O(C,R,"⟶","\\longrightarrow",!0),O(C,R,"⇒","\\Rightarrow",!0),O(C,R,"⟹","\\Longrightarrow",!0),O(C,R,"↔","\\leftrightarrow",!0),O(C,R,"⟷","\\longleftrightarrow",!0),O(C,R,"⇔","\\Leftrightarrow",!0),O(C,R,"⟺","\\Longleftrightarrow",!0),O(C,R,"↦","\\mapsto",!0),O(C,R,"⟼","\\longmapsto",!0),O(C,R,"↗","\\nearrow",!0),O(C,R,"↩","\\hookleftarrow",!0),O(C,R,"↪","\\hookrightarrow",!0),O(C,R,"↘","\\searrow",!0),O(C,R,"↼","\\leftharpoonup",!0),O(C,R,"⇀","\\rightharpoonup",!0),O(C,R,"↙","\\swarrow",!0),O(C,R,"↽","\\leftharpoondown",!0),O(C,R,"⇁","\\rightharpoondown",!0),O(C,R,"↖","\\nwarrow",!0),O(C,R,"⇌","\\rightleftharpoons",!0),O(C,F,"↯","\\lightning",!0),O(C,F,"‰","\\permil",!0),O(z,U,"‰","\\permil"),O(C,R,"≮","\\nless",!0),O(C,R,"⪇","\\lneq",!0),O(C,R,"≨","\\lneqq",!0),O(C,R,"≨︀","\\lvertneqq"),O(C,R,"⋦","\\lnsim",!0),O(C,R,"⪉","\\lnapprox",!0),O(C,R,"⊀","\\nprec",!0),O(C,R,"⋠","\\npreceq",!0),O(C,R,"⋨","\\precnsim",!0),O(C,R,"⪹","\\precnapprox",!0),O(C,R,"≁","\\nsim",!0),O(C,R,"∤","\\nmid",!0),O(C,R,"∤","\\nshortmid"),O(C,R,"⊬","\\nvdash",!0),O(C,R,"⊭","\\nvDash",!0),O(C,R,"⋪","\\ntriangleleft"),O(C,R,"⋬","\\ntrianglelefteq",!0),O(C,R,"⊄","\\nsubset",!0),O(C,R,"⊅","\\nsupset",!0),O(C,R,"⊊","\\subsetneq",!0),O(C,R,"⊊︀","\\varsubsetneq"),O(C,R,"⫋","\\subsetneqq",!0),O(C,R,"⫋︀","\\varsubsetneqq"),O(C,R,"≯","\\ngtr",!0),O(C,R,"⪈","\\gneq",!0),O(C,R,"≩","\\gneqq",!0),O(C,R,"≩︀","\\gvertneqq"),O(C,R,"⋧","\\gnsim",!0),O(C,R,"⪊","\\gnapprox",!0),O(C,R,"⊁","\\nsucc",!0),O(C,R,"⋡","\\nsucceq",!0),O(C,R,"⋩","\\succnsim",!0),O(C,R,"⪺","\\succnapprox",!0),O(C,R,"≆","\\ncong",!0),O(C,R,"∦","\\nparallel",!0),O(C,R,"∦","\\nshortparallel"),O(C,R,"⊯","\\nVDash",!0),O(C,R,"⋫","\\ntriangleright"),O(C,R,"⋭","\\ntrianglerighteq",!0),O(C,R,"⊋","\\supsetneq",!0),O(C,R,"⊋","\\varsupsetneq"),O(C,R,"⫌","\\supsetneqq",!0),O(C,R,"⫌︀","\\varsupsetneqq"),O(C,R,"⊮","\\nVdash",!0),O(C,R,"⪵","\\precneqq",!0),O(C,R,"⪶","\\succneqq",!0),O(C,I,"⊴","\\unlhd"),O(C,I,"⊵","\\unrhd"),O(C,R,"↚","\\nleftarrow",!0),O(C,R,"↛","\\nrightarrow",!0),O(C,R,"⇍","\\nLeftarrow",!0),O(C,R,"⇏","\\nRightarrow",!0),O(C,R,"↮","\\nleftrightarrow",!0),O(C,R,"⇎","\\nLeftrightarrow",!0),O(C,R,"△","\\vartriangle"),O(C,U,"ℏ","\\hslash"),O(C,U,"▽","\\triangledown"),O(C,U,"◊","\\lozenge"),O(C,U,"Ⓢ","\\circledS"),O(C,U,"®","\\circledR",!0),O(z,U,"®","\\circledR"),O(z,U,"®","\\textregistered"),O(C,U,"∡","\\measuredangle",!0),O(C,U,"∄","\\nexists"),O(C,U,"℧","\\mho"),O(C,U,"Ⅎ","\\Finv",!0),O(C,U,"⅁","\\Game",!0),O(C,U,"‵","\\backprime"),O(C,U,"▲","\\blacktriangle"),O(C,U,"▼","\\blacktriangledown"),O(C,U,"■","\\blacksquare"),O(C,U,"⧫","\\blacklozenge"),O(C,U,"★","\\bigstar"),O(C,U,"∢","\\sphericalangle",!0),O(C,U,"∁","\\complement",!0),O(C,U,"ð","\\eth",!0),O(z,U,"ð","ð"),O(C,U,"╱","\\diagup"),O(C,U,"╲","\\diagdown"),O(C,U,"□","\\square"),O(C,U,"□","\\Box"),O(C,U,"◊","\\Diamond"),O(C,U,"¥","\\yen",!0),O(z,U,"¥","\\yen",!0),O(C,U,"✓","\\checkmark",!0),O(z,U,"✓","\\checkmark"),O(C,U,"✗","\\ballotx",!0),O(z,U,"✗","\\ballotx"),O(z,U,"•","\\textbullet"),O(C,U,"ℶ","\\beth",!0),O(C,U,"ℸ","\\daleth",!0),O(C,U,"ℷ","\\gimel",!0),O(C,U,"ϝ","\\digamma",!0),O(C,U,"ϰ","\\varkappa"),O(C,D,"⌜","\\ulcorner",!0),O(C,L,"⌝","\\urcorner",!0),O(C,D,"⌞","\\llcorner",!0),O(C,L,"⌟","\\lrcorner",!0),O(C,R,"≦","\\leqq",!0),O(C,R,"⩽","\\leqslant",!0),O(C,R,"⪕","\\eqslantless",!0),O(C,R,"≲","\\lesssim",!0),O(C,R,"⪅","\\lessapprox",!0),O(C,R,"≊","\\approxeq",!0),O(C,I,"⋖","\\lessdot"),O(C,R,"⋘","\\lll",!0),O(C,R,"≶","\\lessgtr",!0),O(C,R,"⋚","\\lesseqgtr",!0),O(C,R,"⪋","\\lesseqqgtr",!0),O(C,R,"≑","\\doteqdot"),O(C,R,"≓","\\risingdotseq",!0),O(C,R,"≒","\\fallingdotseq",!0),O(C,R,"∽","\\backsim",!0),O(C,R,"⋍","\\backsimeq",!0),O(C,R,"⫅","\\subseteqq",!0),O(C,R,"⋐","\\Subset",!0),O(C,R,"⊏","\\sqsubset",!0),O(C,R,"≼","\\preccurlyeq",!0),O(C,R,"⋞","\\curlyeqprec",!0),O(C,R,"≾","\\precsim",!0),O(C,R,"⪷","\\precapprox",!0),O(C,R,"⊲","\\vartriangleleft"),O(C,R,"⊴","\\trianglelefteq"),O(C,R,"⊨","\\vDash",!0),O(C,R,"⊪","\\Vvdash",!0),O(C,R,"⌣","\\smallsmile"),O(C,R,"⌢","\\smallfrown"),O(C,R,"≏","\\bumpeq",!0),O(C,R,"≎","\\Bumpeq",!0),O(C,R,"≧","\\geqq",!0),O(C,R,"⩾","\\geqslant",!0),O(C,R,"⪖","\\eqslantgtr",!0),O(C,R,"≳","\\gtrsim",!0),O(C,R,"⪆","\\gtrapprox",!0),O(C,I,"⋗","\\gtrdot"),O(C,R,"⋙","\\ggg",!0),O(C,R,"≷","\\gtrless",!0),O(C,R,"⋛","\\gtreqless",!0),O(C,R,"⪌","\\gtreqqless",!0),O(C,R,"≖","\\eqcirc",!0),O(C,R,"≗","\\circeq",!0),O(C,R,"≜","\\triangleq",!0),O(C,R,"∼","\\thicksim"),O(C,R,"≈","\\thickapprox"),O(C,R,"⫆","\\supseteqq",!0),O(C,R,"⋑","\\Supset",!0),O(C,R,"⊐","\\sqsupset",!0),O(C,R,"≽","\\succcurlyeq",!0),O(C,R,"⋟","\\curlyeqsucc",!0),O(C,R,"≿","\\succsim",!0),O(C,R,"⪸","\\succapprox",!0),O(C,R,"⊳","\\vartriangleright"),O(C,R,"⊵","\\trianglerighteq"),O(C,R,"⊩","\\Vdash",!0),O(C,R,"∣","\\shortmid"),O(C,R,"∥","\\shortparallel"),O(C,R,"≬","\\between",!0),O(C,R,"⋔","\\pitchfork",!0),O(C,R,"∝","\\varpropto"),O(C,R,"◀","\\blacktriangleleft"),O(C,R,"∴","\\therefore",!0),O(C,R,"∍","\\backepsilon"),O(C,R,"▶","\\blacktriangleright"),O(C,R,"∵","\\because",!0),O(C,R,"⋘","\\llless"),O(C,R,"⋙","\\gggtr"),O(C,I,"⊲","\\lhd"),O(C,I,"⊳","\\rhd"),O(C,R,"≂","\\eqsim",!0),O(C,R,"⋈","\\Join"),O(C,R,"≑","\\Doteq",!0),O(C,R,"⥽","\\strictif",!0),O(C,R,"⥼","\\strictfi",!0),O(C,I,"∔","\\dotplus",!0),O(C,I,"∖","\\smallsetminus"),O(C,I,"⋒","\\Cap",!0),O(C,I,"⋓","\\Cup",!0),O(C,I,"⩞","\\doublebarwedge",!0),O(C,I,"⊟","\\boxminus",!0),O(C,I,"⊞","\\boxplus",!0),O(C,I,"⋇","\\divideontimes",!0),O(C,I,"⋉","\\ltimes",!0),O(C,I,"⋊","\\rtimes",!0),O(C,I,"⋋","\\leftthreetimes",!0),O(C,I,"⋌","\\rightthreetimes",!0),O(C,I,"⋏","\\curlywedge",!0),O(C,I,"⋎","\\curlyvee",!0),O(C,I,"⊝","\\circleddash",!0),O(C,I,"⊛","\\circledast",!0),O(C,I,"⊺","\\intercal",!0),O(C,I,"⋒","\\doublecap"),O(C,I,"⋓","\\doublecup"),O(C,I,"⊠","\\boxtimes",!0),O(C,R,"⇢","\\dashrightarrow",!0),O(C,R,"⇠","\\dashleftarrow",!0),O(C,R,"⇇","\\leftleftarrows",!0),O(C,R,"⇆","\\leftrightarrows",!0),O(C,R,"⇚","\\Lleftarrow",!0),O(C,R,"↞","\\twoheadleftarrow",!0),O(C,R,"↢","\\leftarrowtail",!0),O(C,R,"↫","\\looparrowleft",!0),O(C,R,"⇋","\\leftrightharpoons",!0),O(C,R,"↶","\\curvearrowleft",!0),O(C,R,"↺","\\circlearrowleft",!0),O(C,R,"↰","\\Lsh",!0),O(C,R,"⇈","\\upuparrows",!0),O(C,R,"↿","\\upharpoonleft",!0),O(C,R,"⇃","\\downharpoonleft",!0),O(C,R,"⊶","\\origof",!0),O(C,R,"⊷","\\imageof",!0),O(C,R,"⊸","\\multimap",!0),O(C,R,"↭","\\leftrightsquigarrow",!0),O(C,R,"⇉","\\rightrightarrows",!0),O(C,R,"⇄","\\rightleftarrows",!0),O(C,R,"↠","\\twoheadrightarrow",!0),O(C,R,"↣","\\rightarrowtail",!0),O(C,R,"↬","\\looparrowright",!0),O(C,R,"↷","\\curvearrowright",!0),O(C,R,"↻","\\circlearrowright",!0),O(C,R,"↱","\\Rsh",!0),O(C,R,"⇊","\\downdownarrows",!0),O(C,R,"↾","\\upharpoonright",!0),O(C,R,"⇂","\\downharpoonright",!0),O(C,R,"⇝","\\rightsquigarrow",!0),O(C,R,"⇝","\\leadsto"),O(C,R,"⇛","\\Rrightarrow",!0),O(C,R,"↾","\\restriction"),O(C,U,"‘","`"),O(C,U,"$","\\$"),O(z,U,"$","\\$"),O(z,U,"$","\\textdollar"),O(C,U,"%","\\%"),O(z,U,"%","\\%"),O(C,U,"_","\\_"),O(z,U,"_","\\_"),O(z,U,"_","\\textunderscore"),O(z,U,"␣","\\textvisiblespace",!0),O(C,U,"∠","\\angle",!0),O(C,U,"∞","\\infty",!0),O(C,U,"′","\\prime"),O(C,U,"△","\\triangle"),O(z,U,"Α","\\Alpha",!0),O(z,U,"Β","\\Beta",!0),O(z,U,"Γ","\\Gamma",!0),O(z,U,"Δ","\\Delta",!0),O(z,U,"Ε","\\Epsilon",!0),O(z,U,"Ζ","\\Zeta",!0),O(z,U,"Η","\\Eta",!0),O(z,U,"Θ","\\Theta",!0),O(z,U,"Ι","\\Iota",!0),O(z,U,"Κ","\\Kappa",!0),O(z,U,"Λ","\\Lambda",!0),O(z,U,"Μ","\\Mu",!0),O(z,U,"Ν","\\Nu",!0),O(z,U,"Ξ","\\Xi",!0),O(z,U,"Ο","\\Omicron",!0),O(z,U,"Π","\\Pi",!0),O(z,U,"Ρ","\\Rho",!0),O(z,U,"Σ","\\Sigma",!0),O(z,U,"Τ","\\Tau",!0),O(z,U,"Υ","\\Upsilon",!0),O(z,U,"Φ","\\Phi",!0),O(z,U,"Χ","\\Chi",!0),O(z,U,"Ψ","\\Psi",!0),O(z,U,"Ω","\\Omega",!0),O(C,F,"Α","\\Alpha",!0),O(C,F,"Β","\\Beta",!0),O(C,F,"Γ","\\Gamma",!0),O(C,F,"Δ","\\Delta",!0),O(C,F,"Ε","\\Epsilon",!0),O(C,F,"Ζ","\\Zeta",!0),O(C,F,"Η","\\Eta",!0),O(C,F,"Θ","\\Theta",!0),O(C,F,"Ι","\\Iota",!0),O(C,F,"Κ","\\Kappa",!0),O(C,F,"Λ","\\Lambda",!0),O(C,F,"Μ","\\Mu",!0),O(C,F,"Ν","\\Nu",!0),O(C,F,"Ξ","\\Xi",!0),O(C,F,"Ο","\\Omicron",!0),O(C,F,"Π","\\Pi",!0),O(C,F,"Ρ","\\Rho",!0),O(C,F,"Σ","\\Sigma",!0),O(C,F,"Τ","\\Tau",!0),O(C,F,"Υ","\\Upsilon",!0),O(C,F,"Φ","\\Phi",!0),O(C,F,"Χ","\\Chi",!0),O(C,F,"Ψ","\\Psi",!0),O(C,F,"Ω","\\Omega",!0),O(C,D,"¬","\\neg",!0),O(C,D,"¬","\\lnot"),O(C,U,"⊤","\\top"),O(C,U,"⊥","\\bot"),O(C,U,"∅","\\emptyset"),O(C,U,"ø","\\varnothing"),O(C,F,"α","\\alpha",!0),O(C,F,"β","\\beta",!0),O(C,F,"γ","\\gamma",!0),O(C,F,"δ","\\delta",!0),O(C,F,"ϵ","\\epsilon",!0),O(C,F,"ζ","\\zeta",!0),O(C,F,"η","\\eta",!0),O(C,F,"θ","\\theta",!0),O(C,F,"ι","\\iota",!0),O(C,F,"κ","\\kappa",!0),O(C,F,"λ","\\lambda",!0),O(C,F,"μ","\\mu",!0),O(C,F,"ν","\\nu",!0),O(C,F,"ξ","\\xi",!0),O(C,F,"ο","\\omicron",!0),O(C,F,"π","\\pi",!0),O(C,F,"ρ","\\rho",!0),O(C,F,"σ","\\sigma",!0),O(C,F,"τ","\\tau",!0),O(C,F,"υ","\\upsilon",!0),O(C,F,"ϕ","\\phi",!0),O(C,F,"χ","\\chi",!0),O(C,F,"ψ","\\psi",!0),O(C,F,"ω","\\omega",!0),O(C,F,"ε","\\varepsilon",!0),O(C,F,"ϑ","\\vartheta",!0),O(C,F,"ϖ","\\varpi",!0),O(C,F,"ϱ","\\varrho",!0),O(C,F,"ς","\\varsigma",!0),O(C,F,"φ","\\varphi",!0),O(C,F,"Ϙ","\\Coppa",!0),O(C,F,"ϙ","\\coppa",!0),O(C,F,"ϙ","\\varcoppa",!0),O(C,F,"Ϟ","\\Koppa",!0),O(C,F,"ϟ","\\koppa",!0),O(C,F,"Ϡ","\\Sampi",!0),O(C,F,"ϡ","\\sampi",!0),O(C,F,"Ϛ","\\Stigma",!0),O(C,F,"ϛ","\\stigma",!0),O(C,F,"⫫","\\Bot"),O(C,I,"∗","∗",!0),O(C,I,"+","+"),O(C,I,"*","*"),O(C,I,"⁄","⁄"),O(C,I,"−","-",!0),O(C,I,"⋅","\\cdot",!0),O(C,I,"∘","\\circ",!0),O(C,I,"÷","\\div",!0),O(C,I,"±","\\pm",!0),O(C,I,"×","\\times",!0),O(C,I,"∩","\\cap",!0),O(C,I,"∪","\\cup",!0),O(C,I,"∖","\\setminus",!0),O(C,I,"∧","\\land"),O(C,I,"∨","\\lor"),O(C,I,"∧","\\wedge",!0),O(C,I,"∨","\\vee",!0),O(C,D,"⟦","\\llbracket",!0),O(C,L,"⟧","\\rrbracket",!0),O(C,D,"⟨","\\langle",!0),O(C,D,"|","\\lvert"),O(C,D,"‖","\\lVert"),O(C,U,"!","\\oc"),O(C,U,"?","\\wn"),O(C,U,"↓","\\shpos"),O(C,U,"↕","\\shift"),O(C,U,"↑","\\shneg"),O(C,L,"?","?"),O(C,L,"!","!"),O(C,L,"‼","‼"),O(C,L,"⟩","\\rangle",!0),O(C,L,"|","\\rvert"),O(C,L,"‖","\\rVert"),O(C,D,"⦃","\\lBrace",!0),O(C,L,"⦄","\\rBrace",!0),O(C,R,"=","\\equal",!0),O(C,R,":",":"),O(C,R,"≈","\\approx",!0),O(C,R,"≅","\\cong",!0),O(C,R,"≥","\\ge"),O(C,R,"≥","\\geq",!0),O(C,R,"←","\\gets"),O(C,R,">","\\gt",!0),O(C,R,"∈","\\in",!0),O(C,R,"∉","\\notin",!0),O(C,R,"","\\@not"),O(C,R,"⊂","\\subset",!0),O(C,R,"⊃","\\supset",!0),O(C,R,"⊆","\\subseteq",!0),O(C,R,"⊇","\\supseteq",!0),O(C,R,"⊈","\\nsubseteq",!0),O(C,R,"⊈","\\nsubseteqq"),O(C,R,"⊉","\\nsupseteq",!0),O(C,R,"⊉","\\nsupseteqq"),O(C,R,"⊨","\\models"),O(C,R,"←","\\leftarrow",!0),O(C,R,"≤","\\le"),O(C,R,"≤","\\leq",!0),O(C,R,"<","\\lt",!0),O(C,R,"→","\\rightarrow",!0),O(C,R,"→","\\to"),O(C,R,"≱","\\ngeq",!0),O(C,R,"≱","\\ngeqq"),O(C,R,"≱","\\ngeqslant"),O(C,R,"≰","\\nleq",!0),O(C,R,"≰","\\nleqq"),O(C,R,"≰","\\nleqslant"),O(C,R,"⫫","\\Perp",!0),O(C,j," ","\\ "),O(C,j," ","\\space"),O(C,j," ","\\nobreakspace"),O(z,j," ","\\ "),O(z,j," "," "),O(z,j," ","\\space"),O(z,j," ","\\nobreakspace"),O(C,j,null,"\\nobreak"),O(C,j,null,"\\allowbreak"),O(C,P,",",","),O(z,P,":",":"),O(C,P,";",";"),O(C,I,"⊼","\\barwedge",!0),O(C,I,"⊻","\\veebar",!0),O(C,I,"⊙","\\odot",!0),O(C,I,"⊕","\\oplus",!0),O(C,I,"⊗","\\otimes",!0),O(C,U,"∂","\\partial",!0),O(C,I,"⊘","\\oslash",!0),O(C,I,"⊚","\\circledcirc",!0),O(C,I,"⊡","\\boxdot",!0),O(C,I,"△","\\bigtriangleup"),O(C,I,"▽","\\bigtriangledown"),O(C,I,"†","\\dagger"),O(C,I,"⋄","\\diamond"),O(C,I,"⋆","\\star"),O(C,I,"◃","\\triangleleft"),O(C,I,"▹","\\triangleright"),O(C,D,"{","\\{"),O(z,U,"{","\\{"),O(z,U,"{","\\textbraceleft"),O(C,L,"}","\\}"),O(z,U,"}","\\}"),O(z,U,"}","\\textbraceright"),O(C,D,"{","\\lbrace"),O(C,L,"}","\\rbrace"),O(C,D,"[","\\lbrack",!0),O(z,U,"[","\\lbrack",!0),O(C,L,"]","\\rbrack",!0),O(z,U,"]","\\rbrack",!0),O(C,D,"(","\\lparen",!0),O(C,L,")","\\rparen",!0),O(z,U,"<","\\textless",!0),O(z,U,">","\\textgreater",!0),O(C,D,"⌊","\\lfloor",!0),O(C,L,"⌋","\\rfloor",!0),O(C,D,"⌈","\\lceil",!0),O(C,L,"⌉","\\rceil",!0),O(C,U,"\\","\\backslash"),O(C,U,"|","|"),O(C,U,"|","\\vert"),O(z,U,"|","\\textbar",!0),O(C,U,"‖","\\|"),O(C,U,"‖","\\Vert"),O(z,U,"‖","\\textbardbl"),O(z,U,"~","\\textasciitilde"),O(z,U,"\\","\\textbackslash"),O(z,U,"^","\\textasciicircum"),O(C,R,"↑","\\uparrow",!0),O(C,R,"⇑","\\Uparrow",!0),O(C,R,"↓","\\downarrow",!0),O(C,R,"⇓","\\Downarrow",!0),O(C,R,"↕","\\updownarrow",!0),O(C,R,"⇕","\\Updownarrow",!0),O(C,G,"∐","\\coprod"),O(C,G,"⋁","\\bigvee"),O(C,G,"⋀","\\bigwedge"),O(C,G,"⨄","\\biguplus"),O(C,G,"⋂","\\bigcap"),O(C,G,"⋃","\\bigcup"),O(C,G,"∫","\\int"),O(C,G,"∫","\\intop"),O(C,G,"∬","\\iint"),O(C,G,"∭","\\iiint"),O(C,G,"∏","\\prod"),O(C,G,"∑","\\sum"),O(C,G,"⨂","\\bigotimes"),O(C,G,"⨁","\\bigoplus"),O(C,G,"⨀","\\bigodot"),O(C,G,"∮","\\oint"),O(C,G,"∯","\\oiint"),O(C,G,"∰","\\oiiint"),O(C,G,"∱","\\intclockwise"),O(C,G,"∲","\\varointclockwise"),O(C,G,"⨌","\\iiiint"),O(C,G,"⨍","\\intbar"),O(C,G,"⨎","\\intBar"),O(C,G,"⨏","\\fint"),O(C,G,"⨒","\\rppolint"),O(C,G,"⨓","\\scpolint"),O(C,G,"⨕","\\pointint"),O(C,G,"⨖","\\sqint"),O(C,G,"⨗","\\intlarhk"),O(C,G,"⨘","\\intx"),O(C,G,"⨙","\\intcap"),O(C,G,"⨚","\\intcup"),O(C,G,"⨅","\\bigsqcap"),O(C,G,"⨆","\\bigsqcup"),O(C,G,"∫","\\smallint"),O(z,$,"…","\\textellipsis"),O(C,$,"…","\\mathellipsis"),O(z,$,"…","\\ldots",!0),O(C,$,"…","\\ldots",!0),O(C,$,"⋰","\\iddots",!0),O(C,$,"⋯","\\@cdots",!0),O(C,$,"⋱","\\ddots",!0),O(C,U,"⋮","\\varvdots"),O(C,E,"ˊ","\\acute"),O(C,E,"`","\\grave"),O(C,E,"¨","\\ddot"),O(C,E,"⃛","\\dddot"),O(C,E,"⃜","\\ddddot"),O(C,E,"~","\\tilde"),O(C,E,"‾","\\bar"),O(C,E,"˘","\\breve"),O(C,E,"ˇ","\\check"),O(C,E,"^","\\hat"),O(C,E,"⃗","\\vec"),O(C,E,"˙","\\dot"),O(C,E,"˚","\\mathring"),O(C,F,"ı","\\imath",!0),O(C,F,"ȷ","\\jmath",!0),O(C,U,"ı","ı"),O(C,U,"ȷ","ȷ"),O(z,U,"ı","\\i",!0),O(z,U,"ȷ","\\j",!0),O(z,U,"ß","\\ss",!0),O(z,U,"æ","\\ae",!0),O(z,U,"œ","\\oe",!0),O(z,U,"ø","\\o",!0),O(C,F,"ø","\\o",!0),O(z,U,"Æ","\\AE",!0),O(z,U,"Œ","\\OE",!0),O(z,U,"Ø","\\O",!0),O(C,F,"Ø","\\O",!0),O(z,E,"ˊ","\\'"),O(z,E,"ˋ","\\`"),O(z,E,"ˆ","\\^"),O(z,E,"˜","\\~"),O(z,E,"ˉ","\\="),O(z,E,"˘","\\u"),O(z,E,"˙","\\."),O(z,E,"¸","\\c"),O(z,E,"˚","\\r"),O(z,E,"ˇ","\\v"),O(z,E,"¨",'\\"'),O(z,E,"˝","\\H"),O(C,E,"ˊ","\\'"),O(C,E,"ˋ","\\`"),O(C,E,"ˆ","\\^"),O(C,E,"˜","\\~"),O(C,E,"ˉ","\\="),O(C,E,"˘","\\u"),O(C,E,"˙","\\."),O(C,E,"¸","\\c"),O(C,E,"˚","\\r"),O(C,E,"ˇ","\\v"),O(C,E,"¨",'\\"'),O(C,E,"˝","\\H");const _={"--":!0,"---":!0,"``":!0,"''":!0};O(z,U,"–","--",!0),O(z,U,"–","\\textendash"),O(z,U,"—","---",!0),O(z,U,"—","\\textemdash"),O(z,U,"‘","`",!0),O(z,U,"‘","\\textquoteleft"),O(z,U,"’","'",!0),O(z,U,"’","\\textquoteright"),O(z,U,"“","``",!0),O(z,U,"“","\\textquotedblleft"),O(z,U,"”","''",!0),O(z,U,"”","\\textquotedblright"),O(C,U,"°","\\degree",!0),O(z,U,"°","\\degree"),O(z,U,"°","\\textdegree",!0),O(C,U,"£","\\pounds"),O(C,U,"£","\\mathsterling",!0),O(z,U,"£","\\pounds"),O(z,U,"£","\\textsterling",!0),O(C,U,"✠","\\maltese"),O(z,U,"✠","\\maltese"),O(C,U,"€","\\euro",!0),O(z,U,"€","\\euro",!0),O(z,U,"€","\\texteuro"),O(C,U,"©","\\copyright",!0),O(z,U,"©","\\textcopyright"),O(C,U,"𝛤","\\varGamma"),O(C,U,"𝛥","\\varDelta"),O(C,U,"𝛩","\\varTheta"),O(C,U,"𝛬","\\varLambda"),O(C,U,"𝛯","\\varXi"),O(C,U,"𝛱","\\varPi"),O(C,U,"𝛴","\\varSigma"),O(C,U,"𝛶","\\varUpsilon"),O(C,U,"𝛷","\\varPhi"),O(C,U,"𝛹","\\varPsi"),O(C,U,"𝛺","\\varOmega"),O(z,U,"𝛤","\\varGamma"),O(z,U,"𝛥","\\varDelta"),O(z,U,"𝛩","\\varTheta"),O(z,U,"𝛬","\\varLambda"),O(z,U,"𝛯","\\varXi"),O(z,U,"𝛱","\\varPi"),O(z,U,"𝛴","\\varSigma"),O(z,U,"𝛶","\\varUpsilon"),O(z,U,"𝛷","\\varPhi"),O(z,U,"𝛹","\\varPsi"),O(z,U,"𝛺","\\varOmega");const H='0123456789/@."';for(let e=0;e=0;n--){const o=e[n];if("mstyle"===o.type&&o.attributes.mathcolor){const s=o.attributes.mathcolor,a=J(o.children,t,r,s);a.type&&"mtable"!==a.type||e.splice(n,1,...a.children)}}}const o=n?"mstyle":"mrow",s=[];let a=[],i=[],l=!1;for(let c=0;c0){const e=new T.MathNode(o,i);n&&e.setAttribute("mathcolor",n),a.push(new T.MathNode(o,i))}a.push(m),i=[];const e=new T.MathNode("mtd",a);s.push(new T.MathNode("mtr",[e])),a=[]}else if(i.push(m),!m.type||"mo"!==m.type||t||r)l=!0;else{if(l&&!m.attributes.form){const t=c0){const e=new T.MathNode(o,i);n&&e.setAttribute("mathcolor",n),a.push(e)}if(s.length>0){const e=new T.MathNode("mtd",a),r=new T.MathNode("mtr",[e]);s.push(r);const n=new T.MathNode("mtable",s);return t||(n.setAttribute("columnalign","left"),n.setAttribute("rowspacing","0em")),n}return T.newDocumentFragment(a)}const Y=function(e,t,r){return!M[t][e]||!M[t][e].replace||55349===e.charCodeAt(0)||Object.prototype.hasOwnProperty.call(_,e)&&r&&(r.fontFamily&&"tt"===r.fontFamily.slice(4,6)||r.font&&"tt"===r.font.slice(4,6))||(e=M[t][e].replace),new T.TextNode(e)},K=function(e){return 1===e.length?e[0]:new T.MathNode("mrow",e)},Q=e=>"atom"===e.type&&"rel"===e.family||"mclass"===e.type&&"mrel"===e.mclass,ee=function(e,t,r){if(1===e.length){const n=re(e[0],t);return r&&n instanceof k&&"mo"===n.type&&(n.setAttribute("lspace","0em"),n.setAttribute("rspace","0em")),[n]}const n=[];for(let r=0;r0&&Q(e[r])&&Q(e[r-1])&&o.setAttribute("lspace","0em"),n.push(o)}return n},te=function(e,t,r){return K(ee(e,t,r))},re=function(t,r){if(!t)return new T.MathNode("mrow");if(l[t.type]){return l[t.type](t,r)}throw new e("Got group of unknown type: '"+t.type+"'")},ne=e=>{const t=new T.MathNode("mtd",[]);return t.setAttribute("style","padding: 0;width: 50%;"),t};function oe(e,t,r,n){let o=null;1===e.length&&"tag"===e[0].type&&(o=e[0].tag,e=e[0].body);const a=ee(e,r),i=0===a.length?null:a[0];let l,c=1===a.length&&null===o&&i instanceof k&&("mstyle"!==i.type||!i.attributes.mathcolor)?a[0]:J(a,n.displayMode,n.annotate);if(o&&(c=((e,t,r,n,o)=>{t=te(t[0].body,r),(t=s.consolidateText(t)).classes=["tml-tag"],o||((t=new T.MathNode("mpadded",[t])).setAttribute("style","width:0;"),t.setAttribute("width","0"),t.setAttribute(n?"rspace":"lspace","-1width")),t=new T.MathNode("mtd",[t]),o||t.setAttribute("style","padding: 0; min-width:0"),e=new T.MathNode("mtd",[e]);const a=n?[t,ne(),e,ne()]:[ne(),e,ne(),t],i=new T.MathNode("mtr",a,["tml-tageqn"]),l=new T.MathNode("mtable",[i]);return l.setAttribute("width","100%"),l.setAttribute("displaystyle","true"),l})(c,o,r,n.leqno,n.preventTagLap)),n.annotate){const e=new T.MathNode("annotation",[new T.TextNode(t)]);e.setAttribute("encoding","application/x-tex"),l=new T.MathNode("semantics",[c,e])}const m=n.annotate?new T.MathNode("math",[l]):new T.MathNode("math",[c]);return n.xml&&m.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML"),n.displayMode&&m.setAttribute("display","block"),m}const se=(e,t)=>{const r=e.isStretchy?S(e.label):new T.MathNode("mo",[Y(e.label,e.mode)]);e.isStretchy||r.setAttribute("stretchy","false");const n=new T.MathNode("\\c"===e.label?"munder":"mover",[re(e.base,t),r]);return n.setAttribute("accent","true"),n},ae=new RegExp(["\\acute","\\grave","\\ddot","\\dddot","\\ddddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map((e=>`\\${e}`)).join("|"));c({type:"accent",names:["\\acute","\\grave","\\ddot","\\dddot","\\ddddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\overparen","\\widecheck","\\widehat","\\wideparen","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overleftharpoon","\\overrightharpoon"],props:{numArgs:1},handler:(e,t)=>{const r=u(t[0]),n=!ae.test(e.funcName),o=!n||"\\widehat"===e.funcName||"\\widetilde"===e.funcName||"\\widecheck"===e.funcName;return{type:"accent",mode:e.parser.mode,label:e.funcName,isStretchy:n,isShifty:o,base:r}},mathmlBuilder:se}),c({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\c","\\u","\\.",'\\"',"\\r","\\H","\\v"],props:{numArgs:1,allowedInText:!0,allowedInMath:!0,argTypes:["primitive"]},handler:(e,t)=>{const r=u(t[0]),n=e.parser.mode;return"math"===n&&e.parser.settings.strict&&console.log(`Temml parse error: Command ${e.funcName} is invalid in math mode.`),{type:"accent",mode:n,label:e.funcName,isStretchy:!1,isShifty:!0,base:r}},mathmlBuilder:se}),c({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underparen","\\utilde"],props:{numArgs:1},handler:({parser:e,funcName:t},r)=>{const n=r[0];return{type:"accentUnder",mode:e.mode,label:t,base:n}},mathmlBuilder:(e,t)=>{const r=S(e.label),n=new T.MathNode("munder",[re(e.base,t),r]);return n.setAttribute("accentunder","true"),n}});const ie={pt:800/803,pc:9600/803,dd:1238/1157*800/803,cc:12.792133216944668,nd:685/642*800/803,nc:1370/107*800/803,sp:1/65536*800/803,mm:25.4/72,cm:2.54/72,in:1/72,px:96/72},le=["em","ex","mu","pt","mm","cm","in","px","bp","pc","dd","cc","nd","nc","sp"],ce=function(e){return"string"!=typeof e&&(e=e.unit),le.indexOf(e)>-1},me=e=>[1,.7,.5][Math.max(e-1,0)],ue=function(t,r){let n=t.number;if(r.maxSize[0]<0&&n>0)return{number:0,unit:"em"};const o=t.unit;switch(o){case"mm":case"cm":case"in":case"px":return n*ie[o]>r.maxSize[1]?{number:r.maxSize[1],unit:"pt"}:{number:n,unit:o};case"em":case"ex":return"ex"===o&&(n*=.431),n=Math.min(n/me(r.level),r.maxSize[0]),{number:s.round(n),unit:"em"};case"bp":return n>r.maxSize[1]&&(n=r.maxSize[1]),{number:n,unit:"pt"};case"pt":case"pc":case"dd":case"cc":case"nd":case"nc":case"sp":return n=Math.min(n*ie[o],r.maxSize[1]),{number:s.round(n),unit:"pt"};case"mu":return n=Math.min(n/18,r.maxSize[0]),{number:s.round(n),unit:"em"};default:throw new e("Invalid unit: '"+o+"'")}},pe=(e,t,r="0.3em")=>{const n=new T.MathNode("mpadded",e?[e]:[]);return n.setAttribute("width",t),n.setAttribute("lspace",r),n},de=(e,t)=>(e/me(t)).toFixed(4)+"em",he=(e,t,r,n)=>{const o=S(e),s="eq"===e.slice(1,3),a="x"===e.charAt(1)?"1.75":"cd"===e.slice(2,4)?"3.0":s?"1.0":"2.0";o.setAttribute("minsize",String(a)+"em"),o.setAttribute("lspace","0"),o.setAttribute("rspace",s?"0.5em":"0");const i=n.withLevel(n.level<2?2:3),l=de(a,i.level),c=de(s?0:.3,i.level);let m=de(s?-.4:.6,i.level);"-"!==m.charAt(0)&&(m="+"+m);const u=t&&t.body&&(t.body.body||t.body.length>0)?pe(re(t,i),m,c):pe(null,l,"0"),p=r&&r.body&&(r.body.body||r.body.length>0)?pe(re(r,i),m,c):pe(null,l,"0");return new T.MathNode("munderover",[o,p,u])};c({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\yields","\\yieldsLeft","\\mesomerism","\\longrightharpoonup","\\longleftharpoondown","\\\\cdrightarrow","\\\\cdleftarrow","\\\\cdlongequal"],props:{numArgs:1,numOptionalArgs:1},handler:({parser:e,funcName:t},r,n)=>({type:"xArrow",mode:e.mode,name:t,body:r[0],below:n[0]}),mathmlBuilder(e,t){const r=he(e.name,e.body,e.below,t),n=new T.MathNode("mpadded",[r]);return n.setAttribute("lspace","0.2778em"),n.setAttribute("width","+0.5556em"),n}});const ge={"\\xtofrom":["\\xrightarrow","\\xleftarrow"],"\\xleftrightharpoons":["\\xleftharpoonup","\\xrightharpoondown"],"\\xrightleftharpoons":["\\xrightharpoonup","\\xleftharpoondown"],"\\yieldsLeftRight":["\\yields","\\yieldsLeft"],"\\equilibrium":["\\longrightharpoonup","\\longleftharpoondown"],"\\equilibriumRight":["\\longrightharpoonup","\\eqleftharpoondown"],"\\equilibriumLeft":["\\eqrightharpoonup","\\longleftharpoondown"]};function fe(e,t){if(!e||e.type!==t)throw new Error(`Expected node of type ${t}, but got `+(e?`node of type ${e.type}`:String(e)));return e}function be(e){const t=ye(e);if(!t)throw new Error("Expected node of symbol group type, but got "+(e?`node of type ${e.type}`:String(e)));return t}function ye(e){return e&&("atom"===e.type||Object.prototype.hasOwnProperty.call(B,e.type))?e:null}c({type:"stackedArrow",names:["\\xtofrom","\\xleftrightharpoons","\\xrightleftharpoons","\\yieldsLeftRight","\\equilibrium","\\equilibriumRight","\\equilibriumLeft"],props:{numArgs:1,numOptionalArgs:1},handler({parser:e,funcName:t},r,n){const o=r[0]?{type:"hphantom",mode:e.mode,body:r[0]}:null,s=n[0]?{type:"hphantom",mode:e.mode,body:n[0]}:null;return{type:"stackedArrow",mode:e.mode,name:t,body:r[0],upperArrowBelow:s,lowerArrowBody:o,below:n[0]}},mathmlBuilder(e,t){const r=ge[e.name][0],n=ge[e.name][1],o=he(r,e.body,e.upperArrowBelow,t),s=he(n,e.lowerArrowBody,e.below,t);let a;const i=new T.MathNode("mpadded",[o]);if(i.setAttribute("voffset","0.3em"),i.setAttribute("height","+0.3em"),i.setAttribute("depth","-0.3em"),"\\equilibriumLeft"===e.name){const e=new T.MathNode("mpadded",[s]);e.setAttribute("width","0.5em"),a=new T.MathNode("mpadded",[e,i])}else i.setAttribute("width","\\equilibriumRight"===e.name?"0.5em":"0"),a=new T.MathNode("mpadded",[i,s]);return a.setAttribute("voffset","-0.18em"),a.setAttribute("width","+0.5556em"),a.setAttribute("height","-0.18em"),a.setAttribute("depth","+0.18em"),a.setAttribute("lspace","0.2778em"),a}}),c({type:"cancelto",names:["\\cancelto"],props:{numArgs:2},handler:({parser:e},t)=>({type:"cancelto",mode:e.mode,value:t[0],expression:t[1]}),mathmlBuilder(e,t){const r=new T.MathNode("mpadded",[re(e.value,t)]);r.setAttribute("depth","-0.1em"),r.setAttribute("height","+0.1em"),r.setAttribute("voffset","0.1em");const n=new T.MathNode("menclose",[re(e.expression,t)]);return n.setAttribute("notation","updiagonalarrow"),new T.MathNode("msup",[n,r])}});const we={">":"\\\\cdrightarrow","<":"\\\\cdleftarrow","=":"\\\\cdlongequal",A:"\\uparrow",V:"\\downarrow","|":"\\Vert",".":"no arrow"},xe=e=>"textord"===e.type&&"@"===e.text;function ke(e,t,r){const n=we[e];switch(n){case"\\\\cdrightarrow":case"\\\\cdleftarrow":return r.callFunction(n,[t[0]],[t[1]]);case"\\uparrow":case"\\downarrow":{const e={type:"atom",text:n,mode:"math",family:"rel"},o={type:"ordgroup",mode:"math",body:[r.callFunction("\\\\cdleft",[t[0]],[]),r.callFunction("\\Big",[e],[]),r.callFunction("\\\\cdright",[t[1]],[])]};return r.callFunction("\\\\cdparent",[o],[])}case"\\\\cdlongequal":return r.callFunction("\\\\cdlongequal",[],[]);case"\\Vert":{const e={type:"textord",text:"\\Vert",mode:"math"};return r.callFunction("\\Big",[e],[])}default:return{type:"textord",text:" ",mode:"math"}}}c({type:"cdlabel",names:["\\\\cdleft","\\\\cdright"],props:{numArgs:1},handler:({parser:e,funcName:t},r)=>({type:"cdlabel",mode:e.mode,side:t.slice(4),label:r[0]}),mathmlBuilder(e,t){let r=new T.MathNode("mrow",[re(e.label,t)]);return r=new T.MathNode("mpadded",[r]),r.setAttribute("width","0"),"left"===e.side&&r.setAttribute("lspace","-1width"),r.setAttribute("voffset","0.7em"),r=new T.MathNode("mstyle",[r]),r.setAttribute("displaystyle","false"),r.setAttribute("scriptlevel","1"),r}}),c({type:"cdlabelparent",names:["\\\\cdparent"],props:{numArgs:1},handler:({parser:e},t)=>({type:"cdlabelparent",mode:e.mode,fragment:t[0]}),mathmlBuilder:(e,t)=>new T.MathNode("mrow",[re(e.fragment,t)])}),c({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler({parser:t,token:r},n){const o=fe(n[0],"ordgroup").body;let s="";for(let e=0;e{let t=e.toString(16);return 1===t.length&&(t="0"+t),t},Be=JSON.parse('{\n "Apricot": "#ffb484",\n "Aquamarine": "#08b4bc",\n "Bittersweet": "#c84c14",\n "blue": "#0000FF",\n "Blue": "#303494",\n "BlueGreen": "#08b4bc",\n "BlueViolet": "#503c94",\n "BrickRed": "#b8341c",\n "brown": "#BF8040",\n "Brown": "#802404",\n "BurntOrange": "#f8941c",\n "CadetBlue": "#78749c",\n "CarnationPink": "#f884b4",\n "Cerulean": "#08a4e4",\n "CornflowerBlue": "#40ace4",\n "cyan": "#00FFFF",\n "Cyan": "#08acec",\n "Dandelion": "#ffbc44",\n "darkgray": "#404040",\n "DarkOrchid": "#a8548c",\n "Emerald": "#08ac9c",\n "ForestGreen": "#089c54",\n "Fuchsia": "#90348c",\n "Goldenrod": "#ffdc44",\n "gray": "#808080",\n "Gray": "#98949c",\n "green": "#00FF00",\n "Green": "#08a44c",\n "GreenYellow": "#e0e474",\n "JungleGreen": "#08ac9c",\n "Lavender": "#f89cc4",\n "lightgray": "#c0c0c0",\n "lime": "#BFFF00",\n "LimeGreen": "#90c43c",\n "magenta": "#FF00FF",\n "Magenta": "#f0048c",\n "Mahogany": "#b0341c",\n "Maroon": "#b03434",\n "Melon": "#f89c7c",\n "MidnightBlue": "#086494",\n "Mulberry": "#b03c94",\n "NavyBlue": "#086cbc",\n "olive": "#7F7F00",\n "OliveGreen": "#407c34",\n "orange": "#FF8000",\n "Orange": "#f8843c",\n "OrangeRed": "#f0145c",\n "Orchid": "#b074ac",\n "Peach": "#f8945c",\n "Periwinkle": "#8074bc",\n "PineGreen": "#088c74",\n "pink": "#ff7f7f",\n "Plum": "#98248c",\n "ProcessBlue": "#08b4ec",\n "purple": "#BF0040",\n "Purple": "#a0449c",\n "RawSienna": "#983c04",\n "red": "#ff0000",\n "Red": "#f01c24",\n "RedOrange": "#f86434",\n "RedViolet": "#a0246c",\n "Rhodamine": "#f0549c",\n "Royallue": "#0874bc",\n "RoyalPurple": "#683c9c",\n "RubineRed": "#f0047c",\n "Salmon": "#f8948c",\n "SeaGreen": "#30bc9c",\n "Sepia": "#701404",\n "SkyBlue": "#48c4dc",\n "SpringGreen": "#c8dc64",\n "Tan": "#e09c74",\n "teal": "#007F7F",\n "TealBlue": "#08acb4",\n "Thistle": "#d884b4",\n "Turquoise": "#08b4cc",\n "violet": "#800080",\n "Violet": "#60449c",\n "VioletRed": "#f054a4",\n "WildStrawberry": "#f0246c",\n "yellow": "#FFFF00",\n "Yellow": "#fff404",\n "YellowGreen": "#98cc6c",\n "YellowOrange": "#ffa41c"\n}'),Me=(t,r)=>{let n="";if("HTML"===t){if(!Ae.test(r))throw new e("Invalid HTML input.");n=r}else if("RGB"===t){if(!Te.test(r))throw new e("Invalid RGB input.");r.split(",").map((e=>{n+=qe(Number(e.trim()))}))}else{if(!Ne.test(r))throw new e("Invalid rbg input.");r.split(",").map((t=>{const r=Number(t.trim());if(r>1)throw new e("Color rgb input must be < 1.");n+=qe(255*r)}))}return"#"!==n.charAt(0)&&(n="#"+n),n},Oe=(t,r,n)=>{const o=`\\\\color@${t}`;if(!ve.exec(t))throw new e("Invalid color: '"+t+"'",n);return Se.test(t)?"#"+t:("#"===t.charAt(0)||(r.has(o)?t=r.get(o).tokens[0].text:Be[t]&&(t=Be[t])),t)},Ce=(e,t)=>{const r=ee(e.body,t.withColor(e.color)),n=v(r);return n.setAttribute("mathcolor",e.color),new T.MathNode("mrow",[n])};c({type:"color",names:["\\textcolor"],props:{numArgs:2,numOptionalArgs:1,allowedInText:!0,argTypes:["raw","raw","original"]},handler({parser:e,token:t},r,n){const o=n[0]&&fe(n[0],"raw").string;let s="";if(o){const e=fe(r[0],"raw").string;s=Me(o,e)}else s=Oe(fe(r[0],"raw").string,e.gullet.macros,t);const a=r[1];return{type:"color",mode:e.mode,color:s,body:p(a)}},mathmlBuilder:Ce}),c({type:"color",names:["\\color"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0,argTypes:["raw","raw"]},handler({parser:e,token:t},r,n){const o=n[0]&&fe(n[0],"raw").string;let s="";if(o){const e=fe(r[0],"raw").string;s=Me(o,e)}else s=Oe(fe(r[0],"raw").string,e.gullet.macros,t);e.gullet.macros.set("\\current@color",s);const a=e.parseExpression(!0,"\\color");return{type:"color",mode:e.mode,color:s,body:a}},mathmlBuilder:Ce}),c({type:"color",names:["\\definecolor"],props:{numArgs:3,allowedInText:!0,argTypes:["raw","raw","raw"]},handler({parser:t,funcName:r,token:n},o){const s=fe(o[0],"raw").string;if(!/^[A-Za-z]+$/.test(s))throw new e("Color name must be latin letters.",n);const a=fe(o[1],"raw").string;if(!["HTML","RGB","rgb"].includes(a))throw new e("Color model must be HTML, RGB, or rgb.",n);const i=fe(o[2],"raw").string,l=Me(a,i);return t.gullet.macros.set(`\\\\color@${s}`,{tokens:[{text:l}],numArgs:0}),{type:"internal",mode:t.mode}}}),c({type:"cr",names:["\\\\"],props:{numArgs:0,numOptionalArgs:1,argTypes:["size"],allowedInText:!0},handler({parser:e},t,r){const n=r[0],o=!e.settings.displayMode;return{type:"cr",mode:e.mode,newLine:o,size:n&&fe(n,"size").value}},mathmlBuilder(e,t){const r=new T.MathNode("mo");if(e.newLine&&(r.setAttribute("linebreak","newline"),e.size)){const n=ue(e.size,t);r.setAttribute("height",n.number+n.unit)}return r}});const ze=t=>{const r=t.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(r))throw new e("Expected a control sequence",t);return r},Ee=(e,t,r)=>{let n=e.gullet.macros.get(r.text);null==n&&(r.noexpand=!0,n={tokens:[r],numArgs:0,unexpandable:!e.gullet.isExpandable(r.text)}),e.gullet.macros.set(t,n)};c({type:"internal",names:["\\def","\\edef"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler({parser:t,funcName:r}){let n=t.gullet.popToken();const o=n.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(o))throw new e("Expected a control sequence",n);let s,a=0;const i=[[]];for(;"{"!==t.gullet.future().text;)if(n=t.gullet.popToken(),"#"===n.text){if("{"===t.gullet.future().text){s=t.gullet.future(),i[a].push("{");break}if(n=t.gullet.popToken(),!/^[1-9]$/.test(n.text))throw new e(`Invalid argument number "${n.text}"`);if(parseInt(n.text)!==a+1)throw new e(`Argument number "${n.text}" out of order`);a++,i.push([])}else{if("EOF"===n.text)throw new e("Expected a macro definition");i[a].push(n.text)}let{tokens:l}=t.gullet.consumeArg();return s&&l.unshift(s),"\\edef"===r&&(l=t.gullet.expandTokens(l),l.reverse()),t.gullet.macros.set(o,{tokens:l,numArgs:a,delimiters:i}),{type:"internal",mode:t.mode}}}),c({type:"internal",names:["\\let"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler({parser:e,funcName:t}){const r=ze(e.gullet.popToken());e.gullet.consumeSpaces();const n=(e=>{let t=e.gullet.popToken();return"="===t.text&&(t=e.gullet.popToken()," "===t.text&&(t=e.gullet.popToken())),t})(e);return Ee(e,r,n),{type:"internal",mode:e.mode}}}),c({type:"internal",names:["\\futurelet"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler({parser:e,funcName:t}){const r=ze(e.gullet.popToken()),n=e.gullet.popToken(),o=e.gullet.popToken();return Ee(e,r,o),e.gullet.pushToken(o),e.gullet.pushToken(n),{type:"internal",mode:e.mode}}}),c({type:"internal",names:["\\newcommand","\\renewcommand","\\providecommand"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler({parser:t,funcName:r}){let n="";const o=t.gullet.popToken();"{"===o.text?(n=ze(t.gullet.popToken()),t.gullet.popToken()):n=ze(o);const s=t.gullet.isDefined(n);if(s&&"\\newcommand"===r)throw new e(`\\newcommand{${n}} attempting to redefine ${n}; use \\renewcommand`);if(!s&&"\\renewcommand"===r)throw new e(`\\renewcommand{${n}} when command ${n} does not yet exist; use \\newcommand`);let a=0;if("["===t.gullet.future().text){let r=t.gullet.popToken();if(r=t.gullet.popToken(),!/^[0-9]$/.test(r.text))throw new e(`Invalid number of arguments: "${r.text}"`);if(a=parseInt(r.text),r=t.gullet.popToken(),"]"!==r.text)throw new e(`Invalid argument "${r.text}"`)}const{tokens:i}=t.gullet.consumeArg();return t.gullet.macros.set(n,{tokens:i,numArgs:a}),{type:"internal",mode:t.mode}}});const Ie={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},Le=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","⌊","⌋","\\lceil","\\rceil","⌈","⌉","<",">","\\langle","⟨","\\rangle","⟩","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","⟮","⟯","\\lmoustache","\\rmoustache","⎰","⎱","\\llbracket","\\rrbracket","⟦","⟦","\\lBrace","\\rBrace","⦃","⦄","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."],$e=[0,1.2,1.8,2.4,3];function Fe(t,r){"ordgroup"===t.type&&1===t.body.length&&"⁄"===t.body[0].text&&(t={type:"textord",text:"/",mode:"math"});const n=ye(t);if(n&&s.contains(Le,n.text))return s.contains(["<","\\lt"],n.text)&&(n.text="⟨"),s.contains([">","\\gt"],n.text)&&(n.text="⟩"),"/"===n.text&&(n.text="∕"),"\\backslash"===n.text&&(n.text="∖"),n;throw new e(n?`Invalid delimiter '${n.text}' after '${r.funcName}'`:`Invalid delimiter type '${t.type}'`,t)}c({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],props:{numArgs:1,argTypes:["primitive"]},handler:(e,t)=>{const r=Fe(t[0],e);return{type:"delimsizing",mode:e.parser.mode,size:Ie[e.funcName].size,mclass:Ie[e.funcName].mclass,delim:r.text}},mathmlBuilder:e=>{const t=[];"."===e.delim&&(e.delim=""),t.push(Y(e.delim,e.mode));const r=new T.MathNode("mo",t);return"mopen"===e.mclass||"mclose"===e.mclass?r.setAttribute("fence","true"):r.setAttribute("fence","false"),"∖"===e.delim&&r.setAttribute("stretchy","true"),r.setAttribute("symmetric","true"),r.setAttribute("minsize",$e[e.size]+"em"),r.setAttribute("maxsize",$e[e.size]+"em"),r}}),c({type:"leftright-right",names:["\\right"],props:{numArgs:1,argTypes:["primitive"]},handler:(t,r)=>{const n=t.parser.gullet.macros.get("\\current@color");if(n&&"string"!=typeof n)throw new e("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:t.parser.mode,delim:Fe(r[0],t).text,color:n}}}),c({type:"leftright",names:["\\left"],props:{numArgs:1,argTypes:["primitive"]},handler:(e,t)=>{const r=Fe(t[0],e),n=e.parser;++n.leftrightDepth;const o=n.parseExpression(!1);--n.leftrightDepth,n.expect("\\right",!1);const s=fe(n.parseFunction(),"leftright-right");return{type:"leftright",mode:n.mode,body:o,left:r.text,right:s.delim,rightColor:s.color}},mathmlBuilder:(e,t)=>{!function(e){if(!e.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}(e);const r=ee(e.body,t);"."===e.left&&(e.left="");const n=new T.MathNode("mo",[Y(e.left,e.mode)]);n.setAttribute("fence","true"),n.setAttribute("form","prefix"),"∖"===e.left&&n.setAttribute("stretchy","true"),r.unshift(n),"."===e.right&&(e.right="");const o=new T.MathNode("mo",[Y(e.right,e.mode)]);return o.setAttribute("fence","true"),o.setAttribute("form","postfix"),"∖"===e.right&&o.setAttribute("stretchy","true"),e.rightColor&&o.setAttribute("mathcolor",e.rightColor),r.push(o),K(r)}}),c({type:"middle",names:["\\middle"],props:{numArgs:1,argTypes:["primitive"]},handler:(t,r)=>{const n=Fe(r[0],t);if(!t.parser.leftrightDepth)throw new e("\\middle without preceding \\left",n);return{type:"middle",mode:t.parser.mode,delim:n.text}},mathmlBuilder:(e,t)=>{const r=Y(e.delim,e.mode),n=new T.MathNode("mo",[r]);return n.setAttribute("fence","true"),n.setAttribute("lspace","0.05em"),n.setAttribute("rspace","0.05em"),n}});const Ge=(e,t)=>{const r=new T.MathNode(e.label.indexOf("colorbox")>-1?"mpadded":"menclose",[re(e.body,t)]);switch(e.label){case"\\cancel":r.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":r.setAttribute("notation","downdiagonalstrike");break;case"\\longdiv":r.setAttribute("notation","longdiv");break;case"\\phase":r.setAttribute("notation","phasorangle");break;case"\\sout":r.setAttribute("notation","horizontalstrike");break;case"\\fbox":r.setAttribute("notation","box");break;case"\\angl":r.setAttribute("notation","actuarial");break;case"\\fcolorbox":case"\\colorbox":{const t=3;r.setAttribute("width",`+${2*t}pt`),r.setAttribute("height",`+${2*t}pt`),r.setAttribute("lspace",`${t}pt`),r.setAttribute("voffset",`${t}pt`),"\\fcolorbox"===e.label&&r.setAttribute("style","border: 0.06em solid "+String(e.borderColor));break}case"\\xcancel":r.setAttribute("notation","updiagonalstrike downdiagonalstrike")}return e.backgroundColor&&r.setAttribute("mathbackground",e.backgroundColor),r};c({type:"enclose",names:["\\colorbox"],props:{numArgs:2,numOptionalArgs:1,allowedInText:!0,argTypes:["raw","raw","text"]},handler({parser:e,funcName:t},r,n){const o=n[0]&&fe(n[0],"raw").string;let s="";if(o){const e=fe(r[0],"raw").string;s=Me(o,e)}else s=Oe(fe(r[0],"raw").string,e.gullet.macros);const a=r[1];return{type:"enclose",mode:e.mode,label:t,backgroundColor:s,body:a}},mathmlBuilder:Ge}),c({type:"enclose",names:["\\fcolorbox"],props:{numArgs:3,numOptionalArgs:1,allowedInText:!0,argTypes:["raw","raw","raw","text"]},handler({parser:e,funcName:t},r,n){const o=n[0]&&fe(n[0],"raw").string;let s,a="";if(o){const e=fe(r[0],"raw").string,t=fe(r[0],"raw").string;a=Me(o,e),s=Me(o,t)}else a=Oe(fe(r[0],"raw").string,e.gullet.macros),s=Oe(fe(r[1],"raw").string,e.gullet.macros);const i=r[2];return{type:"enclose",mode:e.mode,label:t,backgroundColor:s,borderColor:a,body:i}},mathmlBuilder:Ge}),c({type:"enclose",names:["\\fbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler:({parser:e},t)=>({type:"enclose",mode:e.mode,label:"\\fbox",body:t[0]})}),c({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\sout","\\angl","\\phase","\\longdiv"],props:{numArgs:1},handler({parser:e,funcName:t},r){const n=r[0];return{type:"enclose",mode:e.mode,label:t,body:n}},mathmlBuilder:Ge});const De={};function Pe({type:e,names:t,props:r,handler:n,mathmlBuilder:o}){const s={type:e,numArgs:r.numArgs||0,allowedInText:!1,numOptionalArgs:0,handler:n};for(let e=0;e{if(!t.parser.settings.displayMode)throw new e(`{${t.envName}} can be used only in display mode.`)},We=(e,t,r)=>{let n;const o=e.tags.shift();if(o){if(!o.body)return n=new T.MathNode("mtd",[]),n.setAttribute("style","padding: 0; min-width:0"),n;n=te(o.body,t),n.classes=["tml-tag"]}else{if("multline"===e.colSeparationType&&(e.leqno&&0!==r||!e.leqno&&r!==e.body.length-1))return n=new T.MathNode("mtd",[]),n.setAttribute("style","padding: 0; min-width:0"),n;n=new T.MathNode("mtext",[],["tml-eqn"])}return e.preventTagLap||(n=new T.MathNode("mpadded",[n]),n.setAttribute("style","width:0;"),n.setAttribute("width","0"),e.leqno||n.setAttribute("lspace","-1width")),n=new T.MathNode("mtd",[n]),e.preventTagLap||n.setAttribute("style","padding: 0; min-width:0"),n};function Xe(t,{hskipBeforeAndAfter:r,addJot:n,cols:o,arraystretch:s,colSeparationType:a,addEqnNum:i,singleRow:l,emptySingleRow:c,maxNumCols:m,leqno:u},p){if(t.gullet.beginGroup(),l||t.gullet.macros.set("\\cr","\\\\\\relax"),i&&(t.gullet.macros.set("\\tag","\\env@tag{\\text{#1}}"),t.gullet.macros.set("\\notag","\\env@notag"),t.gullet.macros.set("\\nonumber","\\env@notag")),void 0===s||Number.isNaN(s)){const r=t.gullet.expandMacroAsText("\\arraystretch");if(null==r)s=1;else if(!(s=parseFloat(r))||s<0)throw new e(`Invalid \\arraystretch: ${r}`)}t.gullet.beginGroup();let d=[];const h=[d],g=[],f=[];let b;const y=[];for(y.push(He(t));;){let r=t.parseExpression(!1,l?"\\end":"\\\\");if(i&&!b)for(let e=0;e1||!c)&&h.pop(),y.length0){const t=e.cols;let r="",n=!1,o=0,s=t.length;"separator"===t[0].type&&(l+="left ",o=1),"separator"===t[t.length-1].type&&(l+="right ",s-=1);for(let e=o;e0?"top ":"",l+=u[u.length-1].length>0?"bottom ":"";for(let e=1;ee.length)));return s.cols=new Array(a).fill({type:"align",align:n}),r?{type:"leftright",mode:t.mode,body:[s],left:r[0],right:r[1],rightColor:void 0}:s},mathmlBuilder:Ye}),Pe({type:"array",names:["smallmatrix"],props:{numArgs:0},handler(e){const t=Xe(e.parser,{arraystretch:.5},"script");return t.colSeparationType="small",t},mathmlBuilder:Ye}),Pe({type:"array",names:["subarray"],props:{numArgs:1},handler(t,r){const n=(ye(r[0])?[r[0]]:fe(r[0],"ordgroup").body).map((function(t){const r=be(t).text;if(-1!=="lc".indexOf(r))return{type:"align",align:r};throw new e("Unknown column alignment: "+r,t)}));if(n.length>1)throw new e("{subarray} can contain only one column");let o={cols:n,hskipBeforeAndAfter:!1,colSeparationType:"array",arraystretch:0};if(o=Xe(t.parser,o,"script"),o.body.length>0&&o.body[0].length>1)throw new e("{subarray} can contain only one column");return o},mathmlBuilder:Ye}),Pe({type:"array",names:["cases","dcases","rcases","drcases"],props:{numArgs:0},handler(e){const t=Xe(e.parser,{cols:[{type:"align",align:"l"},{type:"align",align:"l"}],colSeparationType:"cases"},Ze(e.envName));return{type:"leftright",mode:e.mode,body:[t],left:e.envName.indexOf("r")>-1?".":"\\{",right:e.envName.indexOf("r")>-1?"\\}":".",rightColor:void 0}},mathmlBuilder:Ye}),Pe({type:"array",names:["align","align*","aligned","split"],props:{numArgs:0},handler:Ke,mathmlBuilder:Ye}),Pe({type:"array",names:["gathered","gather","gather*"],props:{numArgs:0},handler(e){s.contains(["gather","gather*"],e.envName)&&Ve(e);const t={cols:[{type:"align",align:"c"}],addJot:!0,colSeparationType:"gather",addEqnNum:"gather"===e.envName,emptySingleRow:!0,leqno:e.parser.settings.leqno};return Xe(e.parser,t,"display")},mathmlBuilder:Ye}),Pe({type:"array",names:["alignat","alignat*","alignedat"],props:{numArgs:1},handler:Ke,mathmlBuilder:Ye}),Pe({type:"array",names:["equation","equation*"],props:{numArgs:0},handler(e){Ve(e);const t={addEqnNum:"equation"===e.envName,emptySingleRow:!0,singleRow:!0,maxNumCols:1,colSeparationType:"gather",leqno:e.parser.settings.leqno};return Xe(e.parser,t,"display")},mathmlBuilder:Ye}),Pe({type:"array",names:["multline","multline*"],props:{numArgs:0},handler(e){Ve(e);const t={addEqnNum:"multline"===e.envName,maxNumCols:1,colSeparationType:"multline",leqno:e.parser.settings.leqno};return Xe(e.parser,t,"display")},mathmlBuilder:Ye}),Pe({type:"array",names:["CD"],props:{numArgs:0},handler:t=>(Ve(t),function(t){const r=[];for(t.gullet.beginGroup(),t.gullet.macros.set("\\cr","\\\\\\relax"),t.gullet.beginGroup();;){r.push(t.parseExpression(!1,"\\\\")),t.gullet.endGroup(),t.gullet.beginGroup();const n=t.fetch().text;if("&"!==n&&"\\\\"!==n){if("\\end"===n){0===r[r.length-1].length&&r.pop();break}throw new e("Expected \\\\ or \\cr or \\end",t.nextToken)}t.consume()}let n=[];const o=[n];for(let i=0;i-1);else{if(!("<>AV".indexOf(o)>-1))throw new e('Expected one of "<>AV=|." after @.');for(let t=0;t<2;t++){let n=!0;for(let c=r+1;c({type:"envTag",mode:e.mode,body:t[0]}),mathmlBuilder:(e,t)=>new T.MathNode("mrow")}),c({type:"noTag",names:["\\env@notag"],props:{numArgs:0},handler:({parser:e})=>({type:"noTag",mode:e.mode}),mathmlBuilder:(e,t)=>new T.MathNode("mrow")});const et=(e,t)=>{const r=e.font,n=t.withFont(r),o=re(e.body,n);if(0===o.children.length)return o;if("boldsymbol"===r&&["mo","mpadded"].includes(o.type))return o.style.fontWeight="bold",o;let s="mo"===o.children[0].type;for(let e=1;e{const n=u(r[0]);let o=t;return o in tt&&(o=tt[o]),{type:"font",mode:e.mode,font:o.slice(1),body:n}},mathmlBuilder:et}),c({type:"font",names:["\\rm","\\sf","\\tt","\\bf","\\it","\\cal"],props:{numArgs:0,allowedInText:!0},handler:({parser:e,funcName:t,breakOnTokenText:r},n)=>{const{mode:o}=e,s=e.parseExpression(!0,r);return{type:"font",mode:o,font:`math${t.slice(1)}`,body:{type:"ordgroup",mode:e.mode,body:s}}},mathmlBuilder:et});const rt=["display","text","script","scriptscript"],nt={auto:-1,display:0,text:0,script:1,scriptscript:2},ot=(e,t)=>{const r="auto"===e.scriptLevel?t.incrementLevel():"display"===e.scriptLevel?t.withLevel(je):"text"===e.scriptLevel?t.withLevel(Ue):t.withLevel(_e);let n=new T.MathNode("mfrac",[re(e.numer,r),re(e.denom,r)]);if(e.hasBarLine){if(e.barSize){const r=ue(e.barSize,t);n.setAttribute("linethickness",r.number+r.unit)}}else n.setAttribute("linethickness","0px");if(null!=e.leftDelim||null!=e.rightDelim){const t=[];if(null!=e.leftDelim){const r=new T.MathNode("mo",[new T.TextNode(e.leftDelim.replace("\\",""))]);r.setAttribute("fence","true"),t.push(r)}if(t.push(n),null!=e.rightDelim){const r=new T.MathNode("mo",[new T.TextNode(e.rightDelim.replace("\\",""))]);r.setAttribute("fence","true"),t.push(r)}n=K(t)}return"auto"!==e.scriptLevel&&(n=new T.MathNode("mstyle",[n]),n.setAttribute("displaystyle",String("display"===e.scriptLevel)),n.setAttribute("scriptlevel",nt[e.scriptLevel])),n};c({type:"genfrac",names:["\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac","\\\\bracefrac","\\\\brackfrac"],props:{numArgs:2,allowedInArgument:!0},handler:({parser:e,funcName:t},r)=>{const n=r[0],o=r[1];let s=!1,a=null,i=null,l="auto";switch(t){case"\\dfrac":case"\\frac":case"\\tfrac":s=!0;break;case"\\\\atopfrac":s=!1;break;case"\\dbinom":case"\\binom":case"\\tbinom":a="(",i=")";break;case"\\\\bracefrac":a="\\{",i="\\}";break;case"\\\\brackfrac":a="[",i="]";break;default:throw new Error("Unrecognized genfrac command")}switch(t){case"\\dfrac":case"\\dbinom":l="display";break;case"\\tfrac":case"\\tbinom":l="text"}return{type:"genfrac",mode:e.mode,continued:!1,numer:n,denom:o,hasBarLine:s,leftDelim:a,rightDelim:i,scriptLevel:l,barSize:null}},mathmlBuilder:ot}),c({type:"genfrac",names:["\\cfrac"],props:{numArgs:2},handler:({parser:e,funcName:t},r)=>{const n=r[0],o=r[1];return{type:"genfrac",mode:e.mode,continued:!0,numer:n,denom:o,hasBarLine:!0,leftDelim:null,rightDelim:null,scriptLevel:"display",barSize:null}}}),c({type:"infix",names:["\\over","\\choose","\\atop","\\brace","\\brack"],props:{numArgs:0,infix:!0},handler({parser:e,funcName:t,token:r}){let n;switch(t){case"\\over":n="\\frac";break;case"\\choose":n="\\binom";break;case"\\atop":n="\\\\atopfrac";break;case"\\brace":n="\\\\bracefrac";break;case"\\brack":n="\\\\brackfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",mode:e.mode,replaceWith:n,token:r}}});const st=function(e){let t=null;return e.length>0&&(t=e,t="."===t?null:t),t};c({type:"genfrac",names:["\\genfrac"],props:{numArgs:6,allowedInArgument:!0,argTypes:["math","math","size","text","math","math"]},handler({parser:e},t){const r=t[4],n=t[5],o=u(t[0]),s="atom"===o.type&&"open"===o.family?st(o.text):null,a=u(t[1]),i="atom"===a.type&&"close"===a.family?st(a.text):null,l=fe(t[2],"size");let c,m=null;l.isBlank?c=!0:(m=l.value,c=m.number>0);let p="auto",d=t[3];if("ordgroup"===d.type){if(d.body.length>0){const e=fe(d.body[0],"textord");p=rt[Number(e.text)]}}else d=fe(d,"textord"),p=rt[Number(d.text)];return{type:"genfrac",mode:e.mode,numer:r,denom:n,continued:!1,hasBarLine:c,barSize:m,leftDelim:s,rightDelim:i,scriptLevel:p}},mathmlBuilder:ot}),c({type:"infix",names:["\\above"],props:{numArgs:1,argTypes:["size"],infix:!0},handler:({parser:e,funcName:t,token:r},n)=>({type:"infix",mode:e.mode,replaceWith:"\\\\abovefrac",barSize:fe(n[0],"size").value,token:r})}),c({type:"genfrac",names:["\\\\abovefrac"],props:{numArgs:3,argTypes:["math","size","math"]},handler:({parser:e,funcName:t},r)=>{const n=r[0],o=function(e){if(!e)throw new Error("Expected non-null, but got "+String(e));return e}(fe(r[1],"infix").barSize),s=r[2],a=o.number>0;return{type:"genfrac",mode:e.mode,numer:n,denom:s,continued:!1,hasBarLine:a,barSize:o,leftDelim:null,rightDelim:null,scriptLevel:"auto"}},mathmlBuilder:ot});c({type:"horizBrace",names:["\\overbrace","\\underbrace"],props:{numArgs:1},handler:({parser:e,funcName:t},r)=>({type:"horizBrace",mode:e.mode,label:t,isOver:/^\\over/.test(t),base:r[0]}),mathmlBuilder:(e,t)=>{const r=S(e.label);return new T.MathNode(e.isOver?"mover":"munder",[re(e.base,t),r])}}),c({type:"href",names:["\\href"],props:{numArgs:2,argTypes:["url","original"],allowedInText:!0},handler:({parser:t,token:r},n)=>{const o=n[1],s=fe(n[0],"url").url;if(!t.settings.isTrusted({command:"\\href",url:s}))throw new e('Function "\\href" is not trusted',r);return{type:"href",mode:t.mode,href:s,body:p(o)}},mathmlBuilder:(e,t)=>{let r=te(e.body,t);return r instanceof k||(r=new k("mrow",[r])),r.setAttribute("href",e.href),r}}),c({type:"href",names:["\\url"],props:{numArgs:1,argTypes:["url"],allowedInText:!0},handler:({parser:t,token:r},n)=>{const o=fe(n[0],"url").url;if(!t.settings.isTrusted({command:"\\url",url:o}))throw new e('Function "\\url" is not trusted',r);const s=[];for(let e=0;e{const s=fe(o[0],"raw").string,a=o[1];if(t.settings.strict)throw new e(`Function "${r}" is disabled in strict mode`,n);let i;const l={};switch(r){case"\\class":l.class=s,i={command:"\\class",class:s};break;case"\\id":l.id=s,i={command:"\\id",id:s};break;case"\\style":l.style=s,i={command:"\\style",style:s};break;case"\\data":{const t=s.split(",");for(let r=0;r{const r=te(e.body,t),n=[];e.attributes.class&&n.push(...e.attributes.class.trim().split(/\s+/)),r.classes=n;for(const t in e.attributes)"class"!==t&&Object.prototype.hasOwnProperty.call(e.attributes,t)&&r.setAttribute(t,e.attributes[t]);return r}});const at=function(t){if(/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(t))return{number:+t,unit:"bp"};{const r=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(t);if(!r)throw new e("Invalid size: '"+t+"' in \\includegraphics");const n={number:+(r[1]+r[2]),unit:r[3]};if(!ce(n))throw new e("Invalid unit: '"+n.unit+"' in \\includegraphics.");return n}};c({type:"includegraphics",names:["\\includegraphics"],props:{numArgs:1,numOptionalArgs:1,argTypes:["raw","url"],allowedInText:!1},handler:({parser:t,token:r},n,o)=>{let s={number:0,unit:"em"},a={number:.9,unit:"em"},i={number:0,unit:"em"},l="";if(o[0]){const t=fe(o[0],"raw").string.split(",");for(let r=0;r{const r=ue(e.height,t),n={number:0,unit:"em"};e.totalheight.number>0&&e.totalheight.unit===r.unit&&e.totalheight.number>r.number&&(n.number=e.totalheight.number-r.number,n.unit=r.unit);let o=0;e.width.number>0&&(o=ue(e.width,t));const s={height:r.number+n.number+"em"};o.number>0&&(s.width=o.number+o.unit),n.number>0&&(s.verticalAlign=-n.number+n.unit);const a=new x(e.src,e.alt,s);return a.height=r,a.depth=n,new T.MathNode("mtext",[a])}}),c({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],props:{numArgs:1,argTypes:["size"],primitive:!0,allowedInText:!0},handler({parser:t,funcName:r,token:n},o){const s=fe(o[0],"size");if(t.settings.strict){const o="m"===r[1],a="mu"===s.value.unit;if(o){if(!a)throw new e(`LaTeX's ${r} supports only mu units, not ${s.value.unit} units`,n);if("math"!==t.mode)throw new e(`LaTeX's ${r} works only in math mode`,n)}else if(a)throw new e(`LaTeX's ${r} doesn't support mu units`,n)}return{type:"kern",mode:t.mode,dimension:s.value}},mathmlBuilder(e,t){const r=ue(e.dimension,t),n="em"===r.unit?it(r.number):"";if("text"===e.mode&&n.length>0){const e=new T.TextNode(n);return new T.MathNode("mtext",[e])}{const e=new T.MathNode("mspace");return e.setAttribute("width",r.number+r.unit),e}}});const it=function(e){return e>=.05555&&e<=.05556?" ":e>=.1666&&e<=.1667?" ":e>=.2222&&e<=.2223?" ":e>=.2777&&e<=.2778?"  ":""},lt=/[^A-Za-z_0-9-]/g;c({type:"label",names:["\\label"],props:{numArgs:1,argTypes:["raw"]},handler:({parser:e},t)=>({type:"label",mode:e.mode,string:t[0].string.replace(lt,"")}),mathmlBuilder(e,t){const r=new T.MathNode("mrow",[],["tml-label"]);return e.string.length>0&&r.setAttribute("id",e.string),r}});const ct=["\\clap","\\llap","\\rlap"];c({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap","\\clap","\\llap","\\rlap"],props:{numArgs:1,allowedInText:!0},handler:({parser:t,funcName:r,token:n},o)=>{if(ct.includes(r)){if(t.settings.strict&&"text"!==t.mode)throw new e(`{${r}} can be used only in text mode.\n Try \\math${r.slice(1)}`,n);r=r.slice(1)}else r=r.slice(5);const s=o[0];return{type:"lap",mode:t.mode,alignment:r,body:s}},mathmlBuilder:(e,t)=>{const r=new T.MathNode("mpadded",[re(e.body,t)]);if("rlap"===e.alignment)e.body.body.length>0&&"genfrac"===e.body.body[0].type&&r.setAttribute("lspace","0.16667em");else{const t="llap"===e.alignment?"-1":"-0.5";r.setAttribute("lspace",t+"width")}return r.setAttribute("width","0px"),r}}),c({type:"ordgroup",names:["\\(","$"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler({funcName:e,parser:t},r){const n=t.mode;t.switchMode("math");const o="\\("===e?"\\)":"$",s=t.parseExpression(!1,o);return t.expect(o),t.switchMode(n),{type:"ordgroup",mode:t.mode,body:s}}}),c({type:"text",names:["\\)","\\]"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler(t,r){throw new e(`Mismatched ${t.funcName}`,r)}});c({type:"mathchoice",names:["\\mathchoice"],props:{numArgs:4,primitive:!0},handler:({parser:e},t)=>({type:"mathchoice",mode:e.mode,display:p(t[0]),text:p(t[1]),script:p(t[2]),scriptscript:p(t[3])}),mathmlBuilder:(e,t)=>{const r=((e,t)=>{switch(t.level){case Re:return e.display;case je:return e.text;case Ue:return e.script;case _e:return e.scriptscript;default:return e.text}})(e,t);return te(r,t)}});const mt=["text","textord","mathord","atom"];function ut(e,t){let r;const n=ee(e.body,t);if("minner"===e.mclass)r=new T.MathNode("mpadded",n);else if("mord"===e.mclass)e.isCharacterBox||"mathord"===n[0].type?(r=n[0],r.type="mi"):r=new T.MathNode("mi",n);else{e.mustPromote?(r=n[0],r.type="mo",e.isCharacterBox&&e.body[0].text&&/[A-Za-z]/.test(e.body[0].text)&&r.setAttribute("mathvariant","italic")):r=new T.MathNode("mo",n);const o=t.level<2;"mbin"===e.mclass?(r.attributes.lspace=o?"0.2222em":"0",r.attributes.rspace=o?"0.2222em":"0"):"mrel"===e.mclass?(r.attributes.lspace=o?"0.2778em":"0",r.attributes.rspace=o?"0.2778em":"0"):"mpunct"===e.mclass?(r.attributes.lspace="0em",r.attributes.rspace=o?"0.1667em":"0"):"mopen"===e.mclass||"mclose"===e.mclass?(r.attributes.lspace="0em",r.attributes.rspace="0em"):"minner"===e.mclass&&o&&(r.attributes.lspace="0.0556em",r.attributes.width="+0.1111em"),"mopen"!==e.mclass&&"mclose"!==e.mclass&&(delete r.attributes.stretchy,delete r.attributes.form)}return r}c({type:"mclass",names:["\\mathord","\\mathbin","\\mathrel","\\mathopen","\\mathclose","\\mathpunct","\\mathinner"],props:{numArgs:1,primitive:!0},handler({parser:e,funcName:t},r){const n=r[0],o=s.isCharacterBox(n);let a=!0;const i={type:"mathord",text:"",mode:e.mode},l=n.body?n.body:[n];for(const e of l){if(!mt.includes(e.type)){a=!1;break}e.text?i.text+=e.text:e.body&&e.body.map((e=>{i.text+=e.text}))}return{type:"mclass",mode:e.mode,mclass:"m"+t.slice(5),body:p(a?i:n),isCharacterBox:o,mustPromote:a}},mathmlBuilder:ut});const pt=e=>{const t="ordgroup"===e.type&&e.body.length?e.body[0]:e;return"atom"!==t.type||"bin"!==t.family&&"rel"!==t.family?"mord":"m"+t.family};c({type:"mclass",names:["\\@binrel"],props:{numArgs:2},handler:({parser:e},t)=>({type:"mclass",mode:e.mode,mclass:pt(t[0]),body:p(t[1]),isCharacterBox:s.isCharacterBox(t[1])})}),c({type:"mclass",names:["\\stackrel","\\overset","\\underset"],props:{numArgs:2},handler({parser:e,funcName:t},r){const n=r[1],o=r[0],s={type:"op",mode:n.mode,limits:!0,alwaysHandleSupSub:!0,parentIsSupSub:!1,symbol:!1,stack:!0,suppressBaseShift:"\\stackrel"!==t,body:p(n)};return{type:"supsub",mode:o.mode,base:s,sup:"\\underset"===t?null:o,sub:"\\underset"===t?o:null}},mathmlBuilder:ut});const dt=(e,t,r)=>{if(!e)return r;const n=re(e,t);return"mrow"===n.type&&0===n.children.length?r:n};c({type:"multiscript",names:["\\sideset","\\pres@cript"],props:{numArgs:3},handler({parser:t,funcName:r,token:n},o){if(0===o[2].body.length)throw new e(r+"cannot parse an empty base.");const s=o[2].body[0];if(t.settings.strict&&"\\sideset"===r&&!s.symbol)throw new e("The base of \\sideset must be a big operator. Try \\prescript.");if(o[0].body.length>0&&"supsub"!==o[0].body[0].type||o[1].body.length>0&&"supsub"!==o[1].body[0].type)throw new e("\\sideset can parse only subscripts and superscripts in its first two arguments",n);const a=o[0].body.length>0?o[0].body[0]:null,i=o[1].body.length>0?o[1].body[0]:null;return a||i?a?{type:"multiscript",mode:t.mode,isSideset:"\\sideset"===r,prescripts:a,postscripts:i,base:s}:{type:"styling",mode:t.mode,scriptLevel:"text",body:[{type:"supsub",mode:t.mode,base:s,sup:i.sup,sub:i.sub}]}:s},mathmlBuilder(e,t){const r=re(e.base,t),n=new T.MathNode("mprescripts"),o=new T.MathNode("none");let s=[];const a=dt(e.prescripts.sub,t,o),i=dt(e.prescripts.sup,t,o);if(e.isSideset&&(a.setAttribute("style","text-align: left;"),i.setAttribute("style","text-align: left;")),e.postscripts){s=[r,dt(e.postscripts.sub,t,o),dt(e.postscripts.sup,t,o),n,a,i]}else s=[r,n,a,i];return new T.MathNode("mmultiscripts",s)}}),c({type:"not",names:["\\not"],props:{numArgs:1,primitive:!0,allowedInText:!1},handler({parser:e},t){const r=s.isCharacterBox(t[0]);let n;if(r)n=p(t[0]),"\\"===n[0].text.charAt(0)&&(n[0].text=M.math[n[0].text].replace),n[0].text=n[0].text.slice(0,1)+"̸"+n[0].text.slice(1);else{n=[{type:"textord",mode:"math",text:"̸"},{type:"kern",mode:"math",dimension:{number:-.6,unit:"em"}},t[0]]}return{type:"not",mode:e.mode,body:n,isCharacterBox:r}},mathmlBuilder(e,t){if(e.isCharacterBox){return ee(e.body,t)[0]}return te(e.body,t,!0)}});const ht=["textord","mathord","atom"],gt=["\\smallint"],ft=["textord","mathord","ordgroup","close","leftright"],bt=["}","\\left","\\middle","\\right"],yt=e=>e.length>0&&(Le.includes(e)||Ie[e]||bt.includes(e)),wt=(e,t)=>{let r;if(e.symbol)r=new k("mo",[Y(e.name,e.mode)]),s.contains(gt,e.name)?r.setAttribute("largeop","false"):r.setAttribute("movablelimits","false");else if(e.body)r=new k("mo",ee(e.body,t));else if(r=new k("mi",[new A(e.name.slice(1))]),!e.parentIsSupSub){const t=new k("mo",[Y("⁡","text")]);r=new k("mpadded",[r,t]);const n=e.needsLeadingSpace?.1667:0,o=e.isFollowedByDelimiter?0:.1666;e.needsLeadingSpace&&r.setAttribute("lspace","0.1667em"),n+o>0&&r.setAttribute("width",`+${n+o}em`)}return r},xt={"∏":"\\prod","∐":"\\coprod","∑":"\\sum","⋀":"\\bigwedge","⋁":"\\bigvee","⋂":"\\bigcap","⋃":"\\bigcup","⨀":"\\bigodot","⨁":"\\bigoplus","⨂":"\\bigotimes","⨄":"\\biguplus","⨅":"\\bigsqcap","⨆":"\\bigsqcup"};c({type:"op",names:["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcap","\\bigsqcup","\\smallint","∏","∐","∑","⋀","⋁","⋂","⋃","⨀","⨁","⨂","⨄","⨆"],props:{numArgs:0},handler:({parser:e,funcName:t},r)=>{let n=t;return 1===n.length&&(n=xt[n]),{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:!0,stack:!1,name:n}},mathmlBuilder:wt}),c({type:"op",names:["\\mathop"],props:{numArgs:1,primitive:!0},handler:({parser:e},t)=>{const r=t[0],n=r.body?r.body:[r],o=1===n.length&&ht.includes(n[0].type);return{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:o,stack:!1,name:o?n[0].text:null,body:o?null:p(r)}},mathmlBuilder:wt});const kt={"∫":"\\int","∬":"\\iint","∭":"\\iiint","∮":"\\oint","∯":"\\oiint","∰":"\\oiiint","∱":"\\intclockwise","∲":"\\varointclockwise","⨌":"\\iiiint","⨍":"\\intbar","⨎":"\\intBar","⨏":"\\fint","⨒":"\\rppolint","⨓":"\\scpolint","⨕":"\\pointint","⨖":"\\sqint","⨗":"\\intlarhk","⨘":"\\intx","⨙":"\\intcap","⨚":"\\intcup"};c({type:"op",names:["\\arcsin","\\arccos","\\arctan","\\arctg","\\arcctg","\\arg","\\ch","\\cos","\\cosec","\\cosh","\\cot","\\cotg","\\coth","\\csc","\\ctg","\\cth","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\sh","\\sgn","\\tan","\\tanh","\\tg","\\th"],props:{numArgs:0},handler({parser:e,funcName:t}){const r=e.prevAtomType,n=e.gullet.future().text;return{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!1,stack:!1,isFollowedByDelimiter:yt(n),needsLeadingSpace:r.length>0&&s.contains(ft,r),name:t}},mathmlBuilder:wt}),c({type:"op",names:["\\det","\\gcd","\\inf","\\lim","\\max","\\min","\\Pr","\\sup"],props:{numArgs:0},handler({parser:e,funcName:t}){const r=e.prevAtomType,n=e.gullet.future().text;return{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:!1,stack:!1,isFollowedByDelimiter:yt(n),needsLeadingSpace:r.length>0&&s.contains(ft,r),name:t}},mathmlBuilder:wt}),c({type:"op",names:["\\int","\\iint","\\iiint","\\iiiint","\\oint","\\oiint","\\oiiint","\\intclockwise","\\varointclockwise","\\intbar","\\intBar","\\fint","\\rppolint","\\scpolint","\\pointint","\\sqint","\\intlarhk","\\intx","\\intcap","\\intcup","∫","∬","∭","∮","∯","∰","∱","∲","⨌","⨍","⨎","⨏","⨒","⨓","⨕","⨖","⨗","⨘","⨙","⨚"],props:{numArgs:0},handler({parser:e,funcName:t}){let r=t;return 1===r.length&&(r=kt[r]),{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!0,stack:!1,name:r}},mathmlBuilder:wt});const At={};function vt(e,t){At[e]=t}c({type:"operatorname",names:["\\operatorname@","\\operatornamewithlimits"],props:{numArgs:1,allowedInArgument:!0},handler:({parser:e,funcName:t},r)=>{const n=r[0],o=e.prevAtomType;return{type:"operatorname",mode:e.mode,body:p(n),alwaysHandleSupSub:"\\operatornamewithlimits"===t,limits:!1,parentIsSupSub:!1,needsLeadingSpace:o.length>0&&s.contains(ft,o)}},mathmlBuilder:(e,t)=>{let r,n=ee(e.body,t.withFont("mathrm")),o=!0;for(let e=0;ee.toText())).join("");n=[new T.TextNode(e)]}else if(1===n.length&&s.contains(["mover","munder"],n[0].type)&&("mi"===n[0].children[0].type||"mtext"===n[0].children[0].type)){if(n[0].children[0].type="mi",e.parentIsSupSub)return new T.MathNode("mrow",n);{const e=new T.MathNode("mo",[Y("⁡","text")]);return T.newDocumentFragment([n[0],e])}}if(o?(r=new T.MathNode("mi",n),r.setAttribute("mathvariant","normal")):r=new T.MathNode("mrow",n),!e.parentIsSupSub){const t=new T.MathNode("mo",[Y("⁡","text")]);if(e.needsLeadingSpace){const e=new T.MathNode("mspace");return e.setAttribute("width","0.1667em"),T.newDocumentFragment([e,r,t])}return T.newDocumentFragment([r,t])}return r}}),vt("\\operatorname","\\@ifstar\\operatornamewithlimits\\operatorname@"),m({type:"ordgroup",mathmlBuilder:(e,t)=>te(e.body,t,!0)}),c({type:"overline",names:["\\overline"],props:{numArgs:1},handler({parser:e},t){const r=t[0];return{type:"overline",mode:e.mode,body:r}},mathmlBuilder(e,t){const r=new T.MathNode("mo",[new T.TextNode("_")]);r.setAttribute("stretchy","true");const n=new T.MathNode("mover",[re(e.body,t),r]);return n.setAttribute("accent","true"),n}}),c({type:"phantom",names:["\\phantom"],props:{numArgs:1,allowedInText:!0},handler:({parser:e},t)=>{const r=t[0];return{type:"phantom",mode:e.mode,body:p(r)}},mathmlBuilder:(e,t)=>{const r=ee(e.body,t);return new T.MathNode("mphantom",r)}}),c({type:"hphantom",names:["\\hphantom"],props:{numArgs:1,allowedInText:!0},handler:({parser:e},t)=>{const r=t[0];return{type:"hphantom",mode:e.mode,body:r}},mathmlBuilder:(e,t)=>{const r=ee(p(e.body),t),n=new T.MathNode("mphantom",r),o=new T.MathNode("mpadded",[n]);return o.setAttribute("height","0px"),o.setAttribute("depth","0px"),o}}),c({type:"vphantom",names:["\\vphantom"],props:{numArgs:1,allowedInText:!0},handler:({parser:e},t)=>{const r=t[0];return{type:"vphantom",mode:e.mode,body:r}},mathmlBuilder:(e,t)=>{const r=ee(p(e.body),t),n=new T.MathNode("mphantom",r),o=new T.MathNode("mpadded",[n]);return o.setAttribute("width","0px"),o}}),c({type:"pmb",names:["\\pmb"],props:{numArgs:1,allowedInText:!0},handler:({parser:e},t)=>({type:"pmb",mode:e.mode,body:p(t[0])}),mathmlBuilder(e,t){const r=ee(e.body,t),n=v(r);return n.setAttribute("style","text-shadow: 0.02em 0.01em 0.04px"),n}});const Tt=e=>e>=0?"+":"-",Nt=(e,t)=>{const r=t.withLevel(je),n=new T.MathNode("mpadded",[re(e.body,r)]),o=ue(e.dy,t);n.setAttribute("voffset",o.number+o.unit);const s=Math.abs(o.number);return n.setAttribute("height",Tt(o.number)+s+o.unit),n.setAttribute("depth",Tt(-o.number)+s+o.unit),n};c({type:"raise",names:["\\raise","\\lower"],props:{numArgs:2,argTypes:["size","primitive"],primitive:!0},handler({parser:e,funcName:t},r){const n=fe(r[0],"size").value;"\\lower"===t&&(n.number*=-1);const o=r[1];return{type:"raise",mode:e.mode,dy:n,body:o}},mathmlBuilder:Nt}),c({type:"raise",names:["\\raisebox"],props:{numArgs:2,argTypes:["size","hbox"],allowedInText:!0},handler({parser:e,funcName:t},r){const n=fe(r[0],"size").value,o=r[1];return{type:"raise",mode:e.mode,dy:n,body:o}},mathmlBuilder:Nt}),c({type:"ref",names:["\\ref","\\eqref"],props:{numArgs:1,argTypes:["raw"]},handler:({parser:e,funcName:t},r)=>({type:"ref",mode:e.mode,funcName:t,string:r[0].string.replace(lt,"")}),mathmlBuilder(e,t){const r="\\ref"===e.funcName?["tml-ref"]:["tml-ref","tml-eqref"],n=new T.MathNode("mtext",[new T.TextNode("")],r);return n.setAttribute("href","#"+e.string),n}}),c({type:"internal",names:["\\relax"],props:{numArgs:0,allowedInText:!0},handler:({parser:e})=>({type:"internal",mode:e.mode})}),c({type:"rule",names:["\\rule"],props:{numArgs:2,numOptionalArgs:1,argTypes:["size","size","size"]},handler({parser:e},t,r){const n=r[0],o=fe(t[0],"size"),s=fe(t[1],"size");return{type:"rule",mode:e.mode,shift:n&&fe(n,"size").value,width:o.value,height:s.value}},mathmlBuilder(e,t){const r=ue(e.width,t),n=ue(e.height,t),o=e.shift?ue(e.shift,t):{number:0,unit:"em"},s=t.color&&t.getColor()||"black",a=new T.MathNode("mspace");if(r.number>0&&n.number>0&&a.setAttribute("mathbackground",s),a.setAttribute("width",r.number+r.unit),a.setAttribute("height",n.number+n.unit),0===o.number)return a;const i=new T.MathNode("mpadded",[a]);return o.number>=0?i.setAttribute("height","+"+o.number+o.unit):(i.setAttribute("height",o.number+o.unit),i.setAttribute("depth","+"+-o.number+o.unit)),i.setAttribute("voffset",o.number+o.unit),i}});const St={"\\tiny":.5,"\\sixptsize":.6,"\\Tiny":.6,"\\scriptsize":.7,"\\footnotesize":.8,"\\small":.9,"\\normalsize":1,"\\large":1.2,"\\Large":1.44,"\\LARGE":1.728,"\\huge":2.074,"\\Huge":2.488};c({type:"sizing",names:["\\tiny","\\sixptsize","\\Tiny","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"],props:{numArgs:0,allowedInText:!0},handler:({breakOnTokenText:e,funcName:t,parser:r},n)=>{r.settings.strict&&"math"===r.mode&&console.log(`Temml strict-mode warning: Command ${t} is invalid in math mode.`);const o=r.parseExpression(!1,e);return{type:"sizing",mode:r.mode,funcName:t,body:o}},mathmlBuilder:(e,t)=>{const r=t.withFontSize(St[e.funcName]),n=ee(e.body,r),o=v(n),s=(St[e.funcName]/t.fontSize).toFixed(4);return o.setAttribute("mathsize",s+"em"),o}}),c({type:"smash",names:["\\smash"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0},handler:({parser:e},t,r)=>{let n=!1,o=!1;const s=r[0]&&fe(r[0],"ordgroup");if(s){let e="";for(let t=0;t{const r=new T.MathNode("mpadded",[re(e.body,t)]);return e.smashHeight&&r.setAttribute("height","0px"),e.smashDepth&&r.setAttribute("depth","0px"),r}}),c({type:"sqrt",names:["\\sqrt"],props:{numArgs:1,numOptionalArgs:1},handler({parser:e},t,r){const n=r[0],o=t[0];return{type:"sqrt",mode:e.mode,body:o,index:n}},mathmlBuilder(e,t){const{body:r,index:n}=e;return n?new T.MathNode("mroot",[re(r,t),re(n,t.incrementLevel())]):new T.MathNode("msqrt",[re(r,t)])}});const qt={display:0,text:1,script:2,scriptscript:3},Bt={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]};c({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler({breakOnTokenText:e,funcName:t,parser:r},n){const o=r.parseExpression(!0,e),s=t.slice(1,t.length-5);return{type:"styling",mode:r.mode,scriptLevel:s,body:o}},mathmlBuilder(e,t){const r=t.withLevel(qt[e.scriptLevel]),n=ee(e.body,r),o=v(n),s=Bt[e.scriptLevel];return o.setAttribute("scriptlevel",s[0]),o.setAttribute("displaystyle",s[1]),o}});const Mt=/^m(over|under|underover)$/;m({type:"supsub",mathmlBuilder(e,t){let r,n,o=!1,s=!1,a=!1;e.base&&"horizBrace"===e.base.type&&(n=!!e.sup,n===e.base.isOver&&(o=!0,r=e.base.isOver)),!e.base||e.base.stack||"op"!==e.base.type&&"operatorname"!==e.base.type||(e.base.parentIsSupSub=!0,s=!e.base.symbol,a=e.base.needsLeadingSpace);const i=e.base&&e.base.stack?[re(e.base.body[0],t)]:[re(e.base,t)],l=t.inSubOrSup();let c;if(e.sub&&i.push(re(e.sub,l)),e.sup&&i.push(re(e.sup,l)),o)c=r?"mover":"munder";else if(e.sub)if(e.sup){const r=e.base;c=r&&("op"===r.type&&r.limits||"multiscript"===r.type)&&(t.level===Re||r.alwaysHandleSupSub)||r&&"operatorname"===r.type&&r.alwaysHandleSupSub&&(t.level===Re||r.limits)?"munderover":"msubsup"}else{const r=e.base;c=r&&"op"===r.type&&r.limits&&(t.level===Re||r.alwaysHandleSupSub)||r&&"operatorname"===r.type&&r.alwaysHandleSupSub&&(r.limits||t.level===Re)?"munder":"msub"}else{const r=e.base;c=r&&"op"===r.type&&r.limits&&(t.level===Re||r.alwaysHandleSupSub)||r&&"operatorname"===r.type&&r.alwaysHandleSupSub&&(r.limits||t.level===Re)?"mover":"msup"}let m=new T.MathNode(c,i);if(s){const e=new T.MathNode("mo",[Y("⁡","text")]);if(a){const t=new T.MathNode("mspace");t.setAttribute("width","0.1667em"),m=T.newDocumentFragment([t,m,e])}else m=T.newDocumentFragment([m,e])}else Mt.test(c)&&(m=new T.MathNode("mrow",[m]));return m}});const Ot=["\\shortmid","\\nshortmid","\\shortparallel","\\nshortparallel","\\smallsetminus"];m({type:"atom",mathmlBuilder(e,t){const r=new T.MathNode("mo",[Y(e.text,e.mode)]);return"punct"===e.family?r.setAttribute("separator","true"):"open"===e.family||"close"===e.family?"open"===e.family?(r.setAttribute("form","prefix"),r.setAttribute("stretchy","false")):"close"===e.family&&(r.setAttribute("form","postfix"),r.setAttribute("stretchy","false")):"\\mid"===e.text?(r.setAttribute("lspace","0.22em"),r.setAttribute("rspace","0.22em"),r.setAttribute("stretchy","false")):Ot.includes(e.text)?r.setAttribute("mathsize","70%"):":"===e.text&&(r.attributes.lspace="0.2222em",r.attributes.rspace="0.2222em"),r}});const Ct={mathbf:"bold",mathrm:"normal",textit:"italic",mathit:"italic",mathnormal:"italic",mathbb:"double-struck",mathcal:"script",mathfrak:"fraktur",mathscr:"script",mathsf:"sans-serif",mathtt:"monospace",oldstylenums:"oldstylenums"},zt=function(e,t){if("texttt"===t.fontFamily)return"monospace";if("textsc"===t.fontFamily)return"normal";if("textsf"===t.fontFamily)return"textit"===t.fontShape&&"textbf"===t.fontWeight?"sans-serif-bold-italic":"textit"===t.fontShape?"sans-serif-italic":"textbf"===t.fontWeight?"sans-serif-bold":"sans-serif";if("textit"===t.fontShape&&"textbf"===t.fontWeight)return"bold-italic";if("textit"===t.fontShape)return"italic";if("textbf"===t.fontWeight)return"bold";const r=t.font;if(!r||"mathnormal"===r)return null;const n=e.mode;switch(r){case"mathit":case"greekItalic":return"italic";case"mathrm":{const t=e.text.codePointAt(0);return 9390,bold:e=>119743,italic:e=>119795,"bold-italic":e=>119847,script:e=>Et[e]||119899,"script-bold":e=>119951,fraktur:e=>It[e]||120003,"fraktur-bold":e=>120107,"double-struck":e=>Lt[e]||120055,"sans-serif":e=>120159,"sans-serif-bold":e=>120211,"sans-serif-italic":e=>120263,"sans-serif-bold-italic":e=>120380,monospace:e=>120367},lowerCaseLatin:{normal:e=>0,bold:e=>119737,italic:e=>"h"===e?8358:119789,"bold-italic":e=>119841,script:e=>Et[e]||119893,"script-bold":e=>119945,fraktur:e=>119997,"fraktur-bold":e=>120101,"double-struck":e=>120049,"sans-serif":e=>120153,"sans-serif-bold":e=>120205,"sans-serif-italic":e=>120257,"sans-serif-bold-italic":e=>120309,monospace:e=>120361},upperCaseGreek:{normal:e=>0,bold:e=>"∇"===e?111802:119575,italic:e=>"∇"===e?111860:119633,"bold-italic":e=>"∇"===e?111802:119575,script:e=>0,"script-bold":e=>0,fraktur:e=>0,"fraktur-bold":e=>0,"double-struck":e=>0,"sans-serif":e=>"∇"===e?111976:119749,"sans-serif-bold":e=>"∇"===e?111976:119749,"sans-serif-italic":e=>0,"sans-serif-bold-italic":e=>"∇"===e?112034:119807,monospace:e=>0},lowerCaseGreek:{normal:e=>0,bold:e=>119569,italic:e=>119627,"bold-italic":e=>"ϕ"===e?119678:119685,script:e=>0,"script-bold":e=>0,fraktur:e=>0,"fraktur-bold":e=>0,"double-struck":e=>0,"sans-serif":e=>119743,"sans-serif-bold":e=>119743,"sans-serif-italic":e=>0,"sans-serif-bold-italic":e=>119801,monospace:e=>0},varGreek:{normal:e=>0,bold:e=>$t[e]||-51,italic:e=>0,"bold-italic":e=>Ft[e]||58,script:e=>0,"script-bold":e=>0,fraktur:e=>0,"fraktur-bold":e=>0,"double-struck":e=>0,"sans-serif":e=>Gt[e]||116,"sans-serif-bold":e=>Gt[e]||116,"sans-serif-italic":e=>0,"sans-serif-bold-italic":e=>Dt[e]||174,monospace:e=>0},numeral:{normal:e=>0,bold:e=>120734,italic:e=>0,"bold-italic":e=>0,script:e=>0,"script-bold":e=>0,fraktur:e=>0,"fraktur-bold":e=>0,"double-struck":e=>120744,"sans-serif":e=>120754,"sans-serif-bold":e=>120764,"sans-serif-italic":e=>0,"sans-serif-bold-italic":e=>0,monospace:e=>120774}}),Rt=(e,t)=>{const r=e.codePointAt(0),n=64{const r=new T.MathNode("mn",[e]),n=new T.MathNode("mstyle",[r]);return n.style["font-style"]="italic",n.style["font-family"]="Cambria, 'Times New Roman', serif","bold-italic"===t&&(n.style["font-weight"]="bold"),n};m({type:"mathord",mathmlBuilder(e,t){const r=Y(e.text,e.mode,t),n=r.text.codePointAt(0),o=912Rt(e,s))).join("")),a=new T.MathNode("mn",[o])}else if("\\prime"===e.text)a=new T.MathNode("mo",[o]);else{const e=o.text;"italic"!==s&&(o.text=Rt(o.text,s)),a=new T.MathNode("mi",[o]),o.text===e&&_t.test(e)&&a.setAttribute("mathvariant","italic")}return a}});const Vt={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},Wt={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};m({type:"spacing",mathmlBuilder(t,r){let n;if(Object.prototype.hasOwnProperty.call(Wt,t.text))n=new T.MathNode("mtext",[new T.TextNode(" ")]);else{if(!Object.prototype.hasOwnProperty.call(Vt,t.text))throw new e(`Unknown type of space "${t.text}"`);n=new T.MathNode("mo"),"\\nobreak"===t.text&&n.setAttribute("linebreak","nobreak")}return n}}),m({type:"tag"});const Xt={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm","\\textsc":"textsc"},Zt={"\\textbf":"textbf","\\textmd":"textmd"},Jt={"\\textit":"textit","\\textup":"textup"};c({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textsc","\\textbf","\\textmd","\\textit","\\textup"],props:{numArgs:1,argTypes:["text"],allowedInArgument:!0,allowedInText:!0},handler({parser:e,funcName:t},r){const n=r[0];return{type:"text",mode:e.mode,body:p(n),font:t}},mathmlBuilder(e,t){const r=((e,t)=>{const r=e.font;return r?Xt[r]?t.withTextFontFamily(Xt[r]):Zt[r]?t.withTextFontWeight(Zt[r]):t.withTextFontShape(Jt[r]):t})(e,t),n=te(e.body,r);return s.consolidateText(n)}}),c({type:"tip",names:["\\mathtip"],props:{numArgs:2},handler:({parser:e},t)=>({type:"tip",mode:e.mode,body:t[0],tip:t[1]}),mathmlBuilder:(e,t)=>{const r=re(e.body,t),n=re(e.tip,t),o=new T.MathNode("maction",[r,n],["tml-tip"]);return o.setAttribute("actiontype","tooltip"),o}}),c({type:"tip",names:["\\texttip"],props:{numArgs:2,argTypes:["math","text"]},handler:({parser:e},t)=>({type:"tip",mode:e.mode,body:t[0],tip:t[1]}),mathmlBuilder:(e,t)=>{const r=re(e.body,t),n=re(e.tip,t);let o="";if("mtext"===n.type)o=n.children[0].text;else for(const e of n.children)o+=e.children[0].text;return r.setAttribute("title",o),r}}),m({type:"toggle",mathmlBuilder(e,t){const r=ee(e.body,t),n=new T.MathNode("maction",r,[],{cursor:"default"});return n.setAttribute("actiontype","toggle"),n}}),c({type:"underline",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler:({parser:e},t)=>({type:"underline",mode:e.mode,body:t[0]}),mathmlBuilder(e,t){const r=new T.MathNode("mo",[new T.TextNode("_")]);r.setAttribute("stretchy","true");const n=new T.MathNode("munder",[re(e.body,t),r]);return n.setAttribute("accentunder","true"),n}}),c({type:"verb",names:["\\verb"],props:{numArgs:0,allowedInText:!0},handler(t,r,n){throw new e("\\verb ended by end of line instead of matching delimiter")},mathmlBuilder(e,t){const r=new T.TextNode(Yt(e)),n=new T.MathNode("mtext",[r]);return n.setAttribute("mathvariant","monospace"),n}});const Yt=e=>e.body.replace(/ /g,e.star?"␣":" "),Kt=i;class Qt{constructor(e,t,r){this.lexer=e,this.start=t,this.end=r}static range(e,t){return t?e&&e.loc&&t.loc&&e.loc.lexer===t.loc.lexer?new Qt(e.loc.lexer,e.loc.start,t.loc.end):null:e&&e.loc}}class er{constructor(e,t){this.text=e,this.loc=t}range(e,t){return new er(t,Qt.range(this,e))}}const tr=new RegExp("[̀-ͯ]+$"),rr="([ \r\n\t]+)|\\\\(\n|[ \r\t]+\n?)[ \r\t]*|(number|[!-\\[\\]-‧‪-퟿豈-￿][̀-ͯ]*|[\ud800-\udbff][\udc00-\udfff][̀-ͯ]*|\\\\verb\\*([^]).*?\\4|\\\\verb([^*a-zA-Z]).*?\\5|(\\\\[a-zA-Z@]+)[ \r\n\t]*|\\\\[^\ud800-\udfff])";class nr{constructor(e,t){this.input=e,this.settings=t,this.tokenRegex=new RegExp(rr.replace("number|",t.strict?"":"\\d(?:[\\d,.]*\\d)?|"),"g"),this.catcodes={"%":14,"~":13}}setCatcode(e,t){this.catcodes[e]=t}lex(){const t=this.input,r=this.tokenRegex.lastIndex;if(r===t.length)return new er("EOF",new Qt(this,r,r));const n=this.tokenRegex.exec(t);if(null===n||n.index!==r)throw new e(`Unexpected character: '${t[r]}'`,new er(t[r],new Qt(this,r,r+1)));const o=n[6]||n[3]||(n[2]?"\\ ":" ");if(14===this.catcodes[o]){const r=t.indexOf("\n",this.tokenRegex.lastIndex);if(-1===r){if(this.tokenRegex.lastIndex=t.length,this.settings.strict)throw new e("% comment has no terminating newline; LaTeX would fail because of commenting the end of math mode")}else this.tokenRegex.lastIndex=r+1;return this.lex()}return new er(o,new Qt(this,r,this.tokenRegex.lastIndex))}}class or{constructor(e={},t={}){this.current=t,this.builtins=e,this.undefStack=[]}beginGroup(){this.undefStack.push({})}endGroup(){if(0===this.undefStack.length)throw new e("Unbalanced namespace destruction: attempt to pop global namespace; please report this as a bug");const t=this.undefStack.pop();for(const e in t)Object.prototype.hasOwnProperty.call(t,e)&&(void 0===t[e]?delete this.current[e]:this.current[e]=t[e])}has(e){return Object.prototype.hasOwnProperty.call(this.current,e)||Object.prototype.hasOwnProperty.call(this.builtins,e)}get(e){return Object.prototype.hasOwnProperty.call(this.current,e)?this.current[e]:this.builtins[e]}set(e,t){const r=this.undefStack[this.undefStack.length-1];r&&!Object.prototype.hasOwnProperty.call(r,e)&&(r[e]=this.current[e]),this.current[e]=t}}const sr=At;vt("\\noexpand",(function(e){const t=e.popToken();return e.isExpandable(t.text)&&(t.noexpand=!0,t.treatAsRelax=!0),{tokens:[t],numArgs:0}})),vt("\\expandafter",(function(e){const t=e.popToken();return e.expandOnce(!0),{tokens:[t],numArgs:0}})),vt("\\@firstoftwo",(function(e){return{tokens:e.consumeArgs(2)[0],numArgs:0}})),vt("\\@secondoftwo",(function(e){return{tokens:e.consumeArgs(2)[1],numArgs:0}})),vt("\\@ifnextchar",(function(e){const t=e.consumeArgs(3);e.consumeSpaces();const r=e.future();return 1===t[0].length&&t[0][0].text===r.text?{tokens:t[1],numArgs:0}:{tokens:t[2],numArgs:0}})),vt("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}"),vt("\\TextOrMath",(function(e){const t=e.consumeArgs(2);return"text"===e.mode?{tokens:t[0],numArgs:0}:{tokens:t[1],numArgs:0}}));const ar={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,A:10,b:11,B:11,c:12,C:12,d:13,D:13,e:14,E:14,f:15,F:15},ir=e=>{const t=e.future().text;return"EOF"===t?[null,""]:[ar[t.charAt(0)],t]},lr=(e,t,r)=>{for(let n=1;n=r)throw new e(`Invalid base-${r} digit ${n.text}`);for(o=lr(o,a,r),[s,a]=ir(t);null!=s&&s":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcap":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"};vt("\\dots",(function(e){let t="\\dotso";const r=e.expandAfterFuture().text;return r in cr?t=cr[r]:("\\not"===r.slice(0,4)||r in M.math&&s.contains(["bin","rel"],M.math[r].group))&&(t="\\dotsb"),t}));const mr={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};vt("\\dotso",(function(e){return e.future().text in mr?"\\ldots\\,":"\\ldots"})),vt("\\dotsc",(function(e){const t=e.future().text;return t in mr&&","!==t?"\\ldots\\,":"\\ldots"})),vt("\\cdots",(function(e){return e.future().text in mr?"\\@cdots\\,":"\\@cdots"})),vt("\\dotsb","\\cdots"),vt("\\dotsm","\\cdots"),vt("\\dotsi","\\!\\cdots"),vt("\\idotsint","\\dotsi"),vt("\\dotsx","\\ldots\\,"),vt("\\DOTSI","\\relax"),vt("\\DOTSB","\\relax"),vt("\\DOTSX","\\relax"),vt("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"),vt("\\,","{\\tmspace+{3mu}{.1667em}}"),vt("\\thinspace","\\,"),vt("\\>","\\mskip{4mu}"),vt("\\:","{\\tmspace+{4mu}{.2222em}}"),vt("\\medspace","\\:"),vt("\\;","{\\tmspace+{5mu}{.2777em}}"),vt("\\thickspace","\\;"),vt("\\!","{\\tmspace-{3mu}{.1667em}}"),vt("\\negthinspace","\\!"),vt("\\negmedspace","{\\tmspace-{4mu}{.2222em}}"),vt("\\negthickspace","{\\tmspace-{5mu}{.277em}}"),vt("\\enspace","\\kern.5em "),vt("\\enskip","\\hskip.5em\\relax"),vt("\\quad","\\hskip1em\\relax"),vt("\\qquad","\\hskip2em\\relax"),vt("\\tag","\\@ifstar\\tag@literal\\tag@paren"),vt("\\tag@paren","\\tag@literal{({#1})}"),vt("\\tag@literal",(t=>{if(t.macros.get("\\df@tag"))throw new e("Multiple \\tag");return"\\def\\df@tag{\\text{#1}}"})),vt("\\bmod","\\mathbin{\\text{mod}}"),vt("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"),vt("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}"),vt("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1"),vt("\\newline","\\\\\\relax"),vt("\\TeX","\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"),vt("\\LaTeX","\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX"),vt("\\Temml","\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"),vt("\\hspace","\\@ifstar\\@hspacer\\@hspace"),vt("\\@hspace","\\hskip #1\\relax"),vt("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax"),vt("\\colon",'\\mathpunct{\\char"3a}'),vt("\\prescript","\\pres@cript{_{#1}^{#2}}{}{#3}"),vt("\\ordinarycolon",'\\char"3a'),vt("\\vcentcolon","\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}}"),vt("\\coloneq",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2212}'),vt("\\Coloneq",'\\mathrel{\\char"2237\\char"2212}'),vt("\\Eqqcolon",'\\mathrel{\\char"3d\\char"2237}'),vt("\\Eqcolon",'\\mathrel{\\char"2212\\char"2237}'),vt("\\colonapprox",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2248}'),vt("\\Colonapprox",'\\mathrel{\\char"2237\\char"2248}'),vt("\\colonsim",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'),vt("\\Colonsim",'\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'),vt("\\ratio","\\vcentcolon"),vt("\\coloncolon","\\dblcolon"),vt("\\colonequals","\\coloneqq"),vt("\\coloncolonequals","\\Coloneqq"),vt("\\equalscolon","\\eqqcolon"),vt("\\equalscoloncolon","\\Eqqcolon"),vt("\\colonminus","\\coloneq"),vt("\\coloncolonminus","\\Coloneq"),vt("\\minuscolon","\\eqcolon"),vt("\\minuscoloncolon","\\Eqcolon"),vt("\\coloncolonapprox","\\Colonapprox"),vt("\\coloncolonsim","\\Colonsim"),vt("\\notni","\\mathrel{\\char`∌}"),vt("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}"),vt("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}"),vt("\\injlim","\\DOTSB\\operatorname*{inj\\,lim}"),vt("\\projlim","\\DOTSB\\operatorname*{proj\\,lim}"),vt("\\varlimsup","\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"),vt("\\varliminf","\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"),vt("\\varinjlim","\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"),vt("\\varprojlim","\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"),vt("\\centerdot","{\\medspace\\rule{0.167em}{0.189em}\\medspace}"),vt("\\argmin","\\DOTSB\\operatorname*{arg\\,min}"),vt("\\argmax","\\DOTSB\\operatorname*{arg\\,max}"),vt("\\plim","\\DOTSB\\operatorname*{plim}"),vt("\\bra","\\mathinner{\\langle{#1}|}"),vt("\\ket","\\mathinner{|{#1}\\rangle}"),vt("\\braket","\\mathinner{\\langle{#1}\\rangle}"),vt("\\Bra","\\left\\langle#1\\right|"),vt("\\Ket","\\left|#1\\right\\rangle");const ur=e=>t=>{const r=t.consumeArg().tokens,n=t.consumeArg().tokens,o=t.consumeArg().tokens,s=t.consumeArg().tokens,a=t.macros.get("|"),i=t.macros.get("\\|");t.macros.beginGroup();const l=t=>r=>{e&&(r.macros.set("|",a),o.length&&r.macros.set("\\|",i));let s=t;if(!t&&o.length){"|"===r.future().text&&(r.popToken(),s=!0)}return{tokens:s?o:n,numArgs:0}};t.macros.set("|",l(!1)),o.length&&t.macros.set("\\|",l(!0));const c=t.consumeArg().tokens,m=t.expandTokens([...s,...c,...r]);return t.macros.endGroup(),{tokens:m.reverse(),numArgs:0}};vt("\\bra@ket",ur(!1)),vt("\\bra@set",ur(!0)),vt("\\Braket","\\bra@ket{\\left\\langle}{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"),vt("\\Set","\\bra@set{\\left\\{\\:}{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"),vt("\\set","\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"),vt("\\angln","{\\angl n}"),vt("\\odv","\\@ifstar\\odv@next\\odv@numerator"),vt("\\odv@numerator","\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}"),vt("\\odv@next","\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1"),vt("\\pdv","\\@ifstar\\pdv@next\\pdv@numerator");const pr=e=>{const t=e[0][0].text,r=(e=>{let t="";for(let r=e.length-1;r>-1;r--)t+=e[r].text;return t})(e[1]).split(","),n=String(r.length),o="1"===n?"\\partial":`\\partial^${n}`;let s="";return r.map((e=>{s+="\\partial "+e.trim()+"\\,"})),[t,o,s.replace(/\\,$/,"")]};vt("\\pdv@numerator",(function(e){const[t,r,n]=pr(e.consumeArgs(2));return`\\frac{${r} ${t}}{${n}}`})),vt("\\pdv@next",(function(e){const[t,r,n]=pr(e.consumeArgs(2));return`\\frac{${r}}{${n}} ${t}`})),vt("\\upalpha","\\up@greek{\\alpha}"),vt("\\upbeta","\\up@greek{\\beta}"),vt("\\upgamma","\\up@greek{\\gamma}"),vt("\\updelta","\\up@greek{\\delta}"),vt("\\upepsilon","\\up@greek{\\epsilon}"),vt("\\upzeta","\\up@greek{\\zeta}"),vt("\\upeta","\\up@greek{\\eta}"),vt("\\uptheta","\\up@greek{\\theta}"),vt("\\upiota","\\up@greek{\\iota}"),vt("\\upkappa","\\up@greek{\\kappa}"),vt("\\uplambda","\\up@greek{\\lambda}"),vt("\\upmu","\\up@greek{\\mu}"),vt("\\upnu","\\up@greek{\\nu}"),vt("\\upxi","\\up@greek{\\xi}"),vt("\\upomicron","\\up@greek{\\omicron}"),vt("\\uppi","\\up@greek{\\pi}"),vt("\\upalpha","\\up@greek{\\alpha}"),vt("\\uprho","\\up@greek{\\rho}"),vt("\\upsigma","\\up@greek{\\sigma}"),vt("\\uptau","\\up@greek{\\tau}"),vt("\\upupsilon","\\up@greek{\\upsilon}"),vt("\\upphi","\\up@greek{\\phi}"),vt("\\upchi","\\up@greek{\\chi}"),vt("\\uppsi","\\up@greek{\\psi}"),vt("\\upomega","\\up@greek{\\omega}"),vt("\\invamp",'\\mathbin{\\char"214b}'),vt("\\parr",'\\mathbin{\\char"214b}'),vt("\\with",'\\mathbin{\\char"26}'),vt("\\multimapinv",'\\mathrel{\\char"27dc}'),vt("\\multimapboth",'\\mathrel{\\char"29df}'),vt("\\scoh",'{\\mkern5mu\\char"2322\\mkern5mu}'),vt("\\sincoh",'{\\mkern5mu\\char"2323\\mkern5mu}'),vt("\\coh",'{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2322}}}\n{\\smash{\\lower4mu{\\char"2323}}}\\mkern5mu}'),vt("\\incoh",'{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2323}}}\n{\\smash{\\lower4mu{\\char"2322}}}\\mkern5mu}'),vt("\\standardstate","\\text{\\tiny\\char`⦵}");const dr={"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0};class hr{constructor(e,t,r){this.settings=t,this.expansionCount=0,this.feed(e),this.macros=new or(sr,t.macros),this.mode=r,this.stack=[]}feed(e){this.lexer=new nr(e,this.settings)}switchMode(e){this.mode=e}beginGroup(){this.macros.beginGroup()}endGroup(){this.macros.endGroup()}future(){return 0===this.stack.length&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]}popToken(){return this.future(),this.stack.pop()}pushToken(e){this.stack.push(e)}pushTokens(e){this.stack.push(...e)}scanArgument(e){let t,r,n;if(e){if(this.consumeSpaces(),"["!==this.future().text)return null;t=this.popToken(),({tokens:n,end:r}=this.consumeArg(["]"]))}else({tokens:n,start:t,end:r}=this.consumeArg());return this.pushToken(new er("EOF",r.loc)),this.pushTokens(n),t.range(r,"")}consumeSpaces(){for(;;){if(" "!==this.future().text)break;this.stack.pop()}}consumeArg(t){const r=[],n=t&&t.length>0;n||this.consumeSpaces();const o=this.future();let s,a=0,i=0;do{if(s=this.popToken(),r.push(s),"{"===s.text)++a;else if("}"===s.text){if(--a,-1===a)throw new e("Extra }",s)}else if("EOF"===s.text)throw new e("Unexpected end of input in a macro argument, expected '"+(t&&n?t[i]:"}")+"'",s);if(t&&n)if((0===a||1===a&&"{"===t[i])&&s.text===t[i]){if(++i,i===t.length){r.splice(-i,i);break}}else i=0}while(0!==a||n);return"{"===o.text&&"}"===r[r.length-1].text&&(r.pop(),r.shift()),r.reverse(),{tokens:r,start:o,end:s}}consumeArgs(t,r){if(r){if(r.length!==t+1)throw new e("The length of delimiters doesn't match the number of args!");const n=r[0];for(let t=0;tthis.settings.maxExpand)throw new e("Too many expansions: infinite loop or need to increase maxExpand setting");let s=o.tokens;const a=this.consumeArgs(o.numArgs,o.delimiters);if(o.numArgs){s=s.slice();for(let t=s.length-1;t>=0;--t){let r=s[t];if("#"===r.text){if(0===t)throw new e("Incomplete placeholder at end of macro body",r);if(r=s[--t],"#"===r.text)s.splice(t+1,1);else{if(!/^[1-9]$/.test(r.text))throw new e("Not a valid argument number",r);s.splice(t,2,...a[+r.text-1])}}}}return this.pushTokens(s),s}expandAfterFuture(){return this.expandOnce(),this.future()}expandNextToken(){for(;;){const e=this.expandOnce();if(e instanceof er)return e.treatAsRelax&&(e.text="\\relax"),this.stack.pop()}throw new Error}expandMacro(e){return this.macros.has(e)?this.expandTokens([new er(e)]):void 0}expandTokens(e){const t=[],r=this.stack.length;for(this.pushTokens(e);this.stack.length>r;){const e=this.expandOnce(!0);e instanceof er&&(e.treatAsRelax&&(e.noexpand=!1,e.treatAsRelax=!1),t.push(this.stack.pop()))}return t}expandMacroAsText(e){const t=this.expandMacro(e);return t?t.map((e=>e.text)).join(""):t}_getExpansion(e){const t=this.macros.get(e);if(null==t)return t;if(1===e.length){const t=this.lexer.catcodes[e];if(null!=t&&13!==t)return}const r="function"==typeof t?t(this):t;if("string"==typeof r){let e=0;if(-1!==r.indexOf("#")){const t=r.replace(/##/g,"");for(;-1!==t.indexOf("#"+(e+1));)++e}const t=new nr(r,this.settings),n=[];let o=t.lex();for(;"EOF"!==o.text;)n.push(o),o=t.lex();n.reverse();return{tokens:n,numArgs:e}}return r}isDefined(e){return this.macros.has(e)||Object.prototype.hasOwnProperty.call(Kt,e)||Object.prototype.hasOwnProperty.call(M.math,e)||Object.prototype.hasOwnProperty.call(M.text,e)||Object.prototype.hasOwnProperty.call(dr,e)}isExpandable(e){const t=this.macros.get(e);return null!=t?"string"==typeof t||"function"==typeof t||!t.unexpandable:Object.prototype.hasOwnProperty.call(Kt,e)&&!Kt[e].primitive}}const gr=[];[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"armenian",blocks:[[1328,1423]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}].forEach((e=>e.blocks.forEach((e=>gr.push(...e)))));const fr=/^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/,br=Object.freeze({"₊":"+","₋":"-","₌":"=","₍":"(","₎":")","₀":"0","₁":"1","₂":"2","₃":"3","₄":"4","₅":"5","₆":"6","₇":"7","₈":"8","₉":"9","ₐ":"a","ₑ":"e","ₕ":"h","ᵢ":"i","ⱼ":"j","ₖ":"k","ₗ":"l","ₘ":"m","ₙ":"n","ₒ":"o","ₚ":"p","ᵣ":"r","ₛ":"s","ₜ":"t","ᵤ":"u","ᵥ":"v","ₓ":"x","ᵦ":"β","ᵧ":"γ","ᵨ":"ρ","ᵩ":"ϕ","ᵪ":"χ","⁺":"+","⁻":"-","⁼":"=","⁽":"(","⁾":")","⁰":"0","¹":"1","²":"2","³":"3","⁴":"4","⁵":"5","⁶":"6","⁷":"7","⁸":"8","⁹":"9","ᴬ":"A","ᴮ":"B","ᴰ":"D","ᴱ":"E","ᴳ":"G","ᴴ":"H","ᴵ":"I","ᴶ":"J","ᴷ":"K","ᴸ":"L","ᴹ":"M","ᴺ":"N","ᴼ":"O","ᴾ":"P","ᴿ":"R","ᵀ":"T","ᵁ":"U","ⱽ":"V","ᵂ":"W","ᵃ":"a","ᵇ":"b","ᶜ":"c","ᵈ":"d","ᵉ":"e","ᶠ":"f","ᵍ":"g","ʰ":"h","ⁱ":"i","ʲ":"j","ᵏ":"k","ˡ":"l","ᵐ":"m","ⁿ":"n","ᵒ":"o","ᵖ":"p","ʳ":"r","ˢ":"s","ᵗ":"t","ᵘ":"u","ᵛ":"v","ʷ":"w","ˣ":"x","ʸ":"y","ᶻ":"z","ᵝ":"β","ᵞ":"γ","ᵟ":"δ","ᵠ":"ϕ","ᵡ":"χ","ᶿ":"θ"});var yr={"́":{text:"\\'",math:"\\acute"},"̀":{text:"\\`",math:"\\grave"},"̈":{text:'\\"',math:"\\ddot"},"̃":{text:"\\~",math:"\\tilde"},"̄":{text:"\\=",math:"\\bar"},"̆":{text:"\\u",math:"\\breve"},"̌":{text:"\\v",math:"\\check"},"̂":{text:"\\^",math:"\\hat"},"̇":{text:"\\.",math:"\\dot"},"̊":{text:"\\r",math:"\\mathring"},"̋":{text:"\\H"},"̧":{text:"\\c"}},wr={"á":"á","à":"à","ä":"ä","ǟ":"ǟ","ã":"ã","ā":"ā","ă":"ă","ắ":"ắ","ằ":"ằ","ẵ":"ẵ","ǎ":"ǎ","â":"â","ấ":"ấ","ầ":"ầ","ẫ":"ẫ","ȧ":"ȧ","ǡ":"ǡ","å":"å","ǻ":"ǻ","ḃ":"ḃ","ć":"ć","č":"č","ĉ":"ĉ","ċ":"ċ","ď":"ď","ḋ":"ḋ","é":"é","è":"è","ë":"ë","ẽ":"ẽ","ē":"ē","ḗ":"ḗ","ḕ":"ḕ","ĕ":"ĕ","ě":"ě","ê":"ê","ế":"ế","ề":"ề","ễ":"ễ","ė":"ė","ḟ":"ḟ","ǵ":"ǵ","ḡ":"ḡ","ğ":"ğ","ǧ":"ǧ","ĝ":"ĝ","ġ":"ġ","ḧ":"ḧ","ȟ":"ȟ","ĥ":"ĥ","ḣ":"ḣ","í":"í","ì":"ì","ï":"ï","ḯ":"ḯ","ĩ":"ĩ","ī":"ī","ĭ":"ĭ","ǐ":"ǐ","î":"î","ǰ":"ǰ","ĵ":"ĵ","ḱ":"ḱ","ǩ":"ǩ","ĺ":"ĺ","ľ":"ľ","ḿ":"ḿ","ṁ":"ṁ","ń":"ń","ǹ":"ǹ","ñ":"ñ","ň":"ň","ṅ":"ṅ","ó":"ó","ò":"ò","ö":"ö","ȫ":"ȫ","õ":"õ","ṍ":"ṍ","ṏ":"ṏ","ȭ":"ȭ","ō":"ō","ṓ":"ṓ","ṑ":"ṑ","ŏ":"ŏ","ǒ":"ǒ","ô":"ô","ố":"ố","ồ":"ồ","ỗ":"ỗ","ȯ":"ȯ","ȱ":"ȱ","ő":"ő","ṕ":"ṕ","ṗ":"ṗ","ŕ":"ŕ","ř":"ř","ṙ":"ṙ","ś":"ś","ṥ":"ṥ","š":"š","ṧ":"ṧ","ŝ":"ŝ","ṡ":"ṡ","ẗ":"ẗ","ť":"ť","ṫ":"ṫ","ú":"ú","ù":"ù","ü":"ü","ǘ":"ǘ","ǜ":"ǜ","ǖ":"ǖ","ǚ":"ǚ","ũ":"ũ","ṹ":"ṹ","ū":"ū","ṻ":"ṻ","ŭ":"ŭ","ǔ":"ǔ","û":"û","ů":"ů","ű":"ű","ṽ":"ṽ","ẃ":"ẃ","ẁ":"ẁ","ẅ":"ẅ","ŵ":"ŵ","ẇ":"ẇ","ẘ":"ẘ","ẍ":"ẍ","ẋ":"ẋ","ý":"ý","ỳ":"ỳ","ÿ":"ÿ","ỹ":"ỹ","ȳ":"ȳ","ŷ":"ŷ","ẏ":"ẏ","ẙ":"ẙ","ź":"ź","ž":"ž","ẑ":"ẑ","ż":"ż","Á":"Á","À":"À","Ä":"Ä","Ǟ":"Ǟ","Ã":"Ã","Ā":"Ā","Ă":"Ă","Ắ":"Ắ","Ằ":"Ằ","Ẵ":"Ẵ","Ǎ":"Ǎ","Â":"Â","Ấ":"Ấ","Ầ":"Ầ","Ẫ":"Ẫ","Ȧ":"Ȧ","Ǡ":"Ǡ","Å":"Å","Ǻ":"Ǻ","Ḃ":"Ḃ","Ć":"Ć","Č":"Č","Ĉ":"Ĉ","Ċ":"Ċ","Ď":"Ď","Ḋ":"Ḋ","É":"É","È":"È","Ë":"Ë","Ẽ":"Ẽ","Ē":"Ē","Ḗ":"Ḗ","Ḕ":"Ḕ","Ĕ":"Ĕ","Ě":"Ě","Ê":"Ê","Ế":"Ế","Ề":"Ề","Ễ":"Ễ","Ė":"Ė","Ḟ":"Ḟ","Ǵ":"Ǵ","Ḡ":"Ḡ","Ğ":"Ğ","Ǧ":"Ǧ","Ĝ":"Ĝ","Ġ":"Ġ","Ḧ":"Ḧ","Ȟ":"Ȟ","Ĥ":"Ĥ","Ḣ":"Ḣ","Í":"Í","Ì":"Ì","Ï":"Ï","Ḯ":"Ḯ","Ĩ":"Ĩ","Ī":"Ī","Ĭ":"Ĭ","Ǐ":"Ǐ","Î":"Î","İ":"İ","Ĵ":"Ĵ","Ḱ":"Ḱ","Ǩ":"Ǩ","Ĺ":"Ĺ","Ľ":"Ľ","Ḿ":"Ḿ","Ṁ":"Ṁ","Ń":"Ń","Ǹ":"Ǹ","Ñ":"Ñ","Ň":"Ň","Ṅ":"Ṅ","Ó":"Ó","Ò":"Ò","Ö":"Ö","Ȫ":"Ȫ","Õ":"Õ","Ṍ":"Ṍ","Ṏ":"Ṏ","Ȭ":"Ȭ","Ō":"Ō","Ṓ":"Ṓ","Ṑ":"Ṑ","Ŏ":"Ŏ","Ǒ":"Ǒ","Ô":"Ô","Ố":"Ố","Ồ":"Ồ","Ỗ":"Ỗ","Ȯ":"Ȯ","Ȱ":"Ȱ","Ő":"Ő","Ṕ":"Ṕ","Ṗ":"Ṗ","Ŕ":"Ŕ","Ř":"Ř","Ṙ":"Ṙ","Ś":"Ś","Ṥ":"Ṥ","Š":"Š","Ṧ":"Ṧ","Ŝ":"Ŝ","Ṡ":"Ṡ","Ť":"Ť","Ṫ":"Ṫ","Ú":"Ú","Ù":"Ù","Ü":"Ü","Ǘ":"Ǘ","Ǜ":"Ǜ","Ǖ":"Ǖ","Ǚ":"Ǚ","Ũ":"Ũ","Ṹ":"Ṹ","Ū":"Ū","Ṻ":"Ṻ","Ŭ":"Ŭ","Ǔ":"Ǔ","Û":"Û","Ů":"Ů","Ű":"Ű","Ṽ":"Ṽ","Ẃ":"Ẃ","Ẁ":"Ẁ","Ẅ":"Ẅ","Ŵ":"Ŵ","Ẇ":"Ẇ","Ẍ":"Ẍ","Ẋ":"Ẋ","Ý":"Ý","Ỳ":"Ỳ","Ÿ":"Ÿ","Ỹ":"Ỹ","Ȳ":"Ȳ","Ŷ":"Ŷ","Ẏ":"Ẏ","Ź":"Ź","Ž":"Ž","Ẑ":"Ẑ","Ż":"Ż","ά":"ά","ὰ":"ὰ","ᾱ":"ᾱ","ᾰ":"ᾰ","έ":"έ","ὲ":"ὲ","ή":"ή","ὴ":"ὴ","ί":"ί","ὶ":"ὶ","ϊ":"ϊ","ΐ":"ΐ","ῒ":"ῒ","ῑ":"ῑ","ῐ":"ῐ","ό":"ό","ὸ":"ὸ","ύ":"ύ","ὺ":"ὺ","ϋ":"ϋ","ΰ":"ΰ","ῢ":"ῢ","ῡ":"ῡ","ῠ":"ῠ","ώ":"ώ","ὼ":"ὼ","Ύ":"Ύ","Ὺ":"Ὺ","Ϋ":"Ϋ","Ῡ":"Ῡ","Ῠ":"Ῠ","Ώ":"Ώ","Ὼ":"Ὼ"};const xr=/^\d(?:[\d,.]*\d)?$/;class kr{constructor(e,t,r=!1){this.mode="math",this.gullet=new hr(e,t,this.mode),this.settings=t,this.isPreamble=r,this.leftrightDepth=0,this.prevAtomType=""}expect(t,r=!0){if(this.fetch().text!==t)throw new e(`Expected '${t}', got '${this.fetch().text}'`,this.fetch());r&&this.consume()}consume(){this.nextToken=null}fetch(){return null==this.nextToken&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken}switchMode(e){this.mode=e,this.gullet.switchMode(e)}parse(){this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");const e=this.parseExpression(!1);if(this.expect("EOF"),this.isPreamble){const e=Object.create(null);return Object.entries(this.gullet.macros.current).forEach((([t,r])=>{e[t]=r})),this.gullet.endGroup(),e}const t=this.gullet.macros.get("\\df@tag");return this.gullet.endGroup(),t&&(this.gullet.macros.current["\\df@tag"]=t),e}static get endOfExpression(){return["}","\\endgroup","\\end","\\right","\\endtoggle","&"]}parseExpression(e,t){const r=[];for(;;){"math"===this.mode&&this.consumeSpaces();const n=this.fetch();if(-1!==kr.endOfExpression.indexOf(n.text))break;if(t&&n.text===t)break;if(e&&Kt[n.text]&&Kt[n.text].infix)break;const o=this.parseAtom(t);if(!o)break;"internal"!==o.type&&(r.push(o),this.prevAtomType="atom"===o.type?o.family:o.type)}return"text"===this.mode&&this.formLigatures(r),this.handleInfixNodes(r)}handleInfixNodes(t){let r,n=-1;for(let o=0;o=128))return null;if(this.settings.strict){if(!function(e){for(let t=0;t=gr[t]&&e<=gr[t+1])return!0;return!1}(r.charCodeAt(0)))throw new e(`Unrecognized Unicode character "${r[0]}" (${r.charCodeAt(0)})`,t);if("math"===this.mode)throw new e(`Unicode text character "${r[0]}" used in math mode`,t)}o={type:"textord",mode:"text",loc:Qt.range(t),text:r}}if(this.consume(),n)for(let r=0;r0&&o[0].type&&"array"===o[0].type&&o[0].addEqnNum)&&n.gullet.macros.get("\\df@tag")){if(!r.displayMode)throw new e("\\tag works only in display mode");n.gullet.feed("\\df@tag"),o=[{type:"tag",mode:"text",body:o,tag:n.parse()}]}return o},vr=[2,2,3,3];class Tr{constructor(e){this.level=e.level,this.color=e.color,this.font=e.font||"",this.fontFamily=e.fontFamily||"",this.fontSize=e.fontSize||1,this.fontWeight=e.fontWeight||"",this.fontShape=e.fontShape||"",this.maxSize=e.maxSize}extend(e){const t={level:this.level,color:this.color,font:this.font,fontFamily:this.fontFamily,fontSize:this.fontSize,fontWeight:this.fontWeight,fontShape:this.fontShape,maxSize:this.maxSize};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return new Tr(t)}withLevel(e){return this.extend({level:e})}incrementLevel(){return this.extend({level:Math.min(this.level+1,3)})}inSubOrSup(){return this.extend({level:vr[this.level]})}withColor(e){return this.extend({color:e})}withFont(e){return this.extend({font:e})}withTextFontFamily(e){return this.extend({fontFamily:e,font:""})}withFontSize(e){return this.extend({fontSize:e})}withTextFontWeight(e){return this.extend({fontWeight:e,font:""})}withTextFontShape(e){return this.extend({fontShape:e,font:""})}getColor(){return this.color}}let Nr=function(e,t,r){t.textContent="";const n=Sr(e,r);r.elementIsMath?(t.textContent="",n.children.forEach((e=>{t.appendChild(e.toNode())}))):t.appendChild(n.toNode())};"undefined"!=typeof document&&"CSS1Compat"!==document.compatMode&&("undefined"!=typeof console&&console.warn("Warning: Temml doesn't work in quirks mode. Make sure your website has a suitable doctype."),Nr=function(){throw new e("Temml doesn't work in quirks mode.")});const Sr=function(t,r){const n=new a(r);try{const e=Ar(t,n);return oe(e,t,new Tr({level:n.displayMode?Re:je,maxSize:n.maxSize}),n)}catch(r){return function(t,r,n){if(n.throwOnError||!(t instanceof e))throw t;const o=new y(["temml-error"],[new w(r+"\n"+t.toString())]);return o.style.color=n.errorColor,o.style.whiteSpace="pre-line",o}(r,t,n)}};return{version:"0.6.9",render:Nr,renderToString:function(e,t){return Sr(e,t).toMarkup()},postProcess:function(e){const t={};let r=0;const n=e.getElementsByClassName("tml-tageqn");for(const e of n){const n=e.getElementsByClassName("tml-eqn");n.length>0&&(r+=1,n[0].id="tml-eqn-"+r);const o=e.getElementsByClassName("tml-label");if(0!==o.length)if(n.length>0)t[o[0].id]=String(r);else{const r=e.getElementsByClassName("tml-tag");r.length>0&&(t[o[0].id]=r[0].textContent)}}[...e.getElementsByClassName("tml-ref")].forEach((e=>{let r=t[e.getAttribute("href").slice(1)];-1===e.className.indexOf("tml-eqref")&&(r=r.replace(/^\(/,""),r=r.replace(/\($/,"")),"("!==r.charAt(0)&&(r="("+r),")"!==r.slice(-1)&&(r+=")"),e.textContent=r}))},ParseError:e,definePreamble:function(e,t){const r=new a(t);if(r.macros={},!("string"==typeof e||e instanceof String))throw new TypeError("Temml can only parse string typed expression");const n=new kr(e,r,!0);delete n.gullet.macros.current["\\df@tag"];return n.parse()},__parse:function(e,t){const r=new a(t);return Ar(e,r)},__renderToMathMLTree:Sr,__defineSymbol:O,__defineMacro:vt}}(); \ No newline at end of file diff --git a/site/assets/texvc.js b/site/assets/texvc.js deleted file mode 100644 index ddd5b1aa..00000000 --- a/site/assets/texvc.js +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable no-undef */ - -////////////////////////////////////////////////////////////////////// -// texvc.sty - -// The texvc package contains macros available in mediawiki pages. -// We omit the functions deprecated at -// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax - -// We also omit texvc's \O, which conflicts with \text{\O} - -temml.__defineMacro("\\darr", "\\downarrow"); -temml.__defineMacro("\\dArr", "\\Downarrow"); -temml.__defineMacro("\\Darr", "\\Downarrow"); -temml.__defineMacro("\\lang", "\\langle"); -temml.__defineMacro("\\rang", "\\rangle"); -temml.__defineMacro("\\uarr", "\\uparrow"); -temml.__defineMacro("\\uArr", "\\Uparrow"); -temml.__defineMacro("\\Uarr", "\\Uparrow"); -temml.__defineMacro("\\N", "\\mathbb{N}"); -temml.__defineMacro("\\R", "\\mathbb{R}"); -temml.__defineMacro("\\Z", "\\mathbb{Z}"); -temml.__defineMacro("\\alef", "\\aleph"); -temml.__defineMacro("\\alefsym", "\\aleph"); -temml.__defineMacro("\\bull", "\\bullet"); -temml.__defineMacro("\\clubs", "\\clubsuit"); -temml.__defineMacro("\\cnums", "\\mathbb{C}"); -temml.__defineMacro("\\Complex", "\\mathbb{C}"); -temml.__defineMacro("\\Dagger", "\\ddagger"); -temml.__defineMacro("\\diamonds", "\\diamondsuit"); -temml.__defineMacro("\\empty", "\\emptyset"); -temml.__defineMacro("\\exist", "\\exists"); -temml.__defineMacro("\\harr", "\\leftrightarrow"); -temml.__defineMacro("\\hArr", "\\Leftrightarrow"); -temml.__defineMacro("\\Harr", "\\Leftrightarrow"); -temml.__defineMacro("\\hearts", "\\heartsuit"); -temml.__defineMacro("\\image", "\\Im"); -temml.__defineMacro("\\infin", "\\infty"); -temml.__defineMacro("\\isin", "\\in"); -temml.__defineMacro("\\larr", "\\leftarrow"); -temml.__defineMacro("\\lArr", "\\Leftarrow"); -temml.__defineMacro("\\Larr", "\\Leftarrow"); -temml.__defineMacro("\\lrarr", "\\leftrightarrow"); -temml.__defineMacro("\\lrArr", "\\Leftrightarrow"); -temml.__defineMacro("\\Lrarr", "\\Leftrightarrow"); -temml.__defineMacro("\\natnums", "\\mathbb{N}"); -temml.__defineMacro("\\plusmn", "\\pm"); -temml.__defineMacro("\\rarr", "\\rightarrow"); -temml.__defineMacro("\\rArr", "\\Rightarrow"); -temml.__defineMacro("\\Rarr", "\\Rightarrow"); -temml.__defineMacro("\\real", "\\Re"); -temml.__defineMacro("\\reals", "\\mathbb{R}"); -temml.__defineMacro("\\Reals", "\\mathbb{R}"); -temml.__defineMacro("\\sdot", "\\cdot"); -temml.__defineMacro("\\sect", "\\S"); -temml.__defineMacro("\\spades", "\\spadesuit"); -temml.__defineMacro("\\sub", "\\subset"); -temml.__defineMacro("\\sube", "\\subseteq"); -temml.__defineMacro("\\supe", "\\supseteq"); -temml.__defineMacro("\\thetasym", "\\vartheta"); -temml.__defineMacro("\\weierp", "\\wp"); diff --git a/site/assets/xits-math.woff2 b/site/assets/xits-math.woff2 deleted file mode 100644 index 595e9263..00000000 Binary files a/site/assets/xits-math.woff2 and /dev/null differ diff --git a/site/assets/xits-mathbold.woff2 b/site/assets/xits-mathbold.woff2 deleted file mode 100644 index e7dabda1..00000000 Binary files a/site/assets/xits-mathbold.woff2 and /dev/null differ diff --git a/site/docs/docStyles.css b/site/docs/docStyles.css deleted file mode 100644 index b2c69fee..00000000 --- a/site/docs/docStyles.css +++ /dev/null @@ -1,375 +0,0 @@ -* { - margin: 0; -} /* reset */ - -body { - font-family: "Times New Roman", Cambria, "Cambria Math", Georgia, serif; -} - -body { - font-size: 18px; -} -@media (max-width: 830px) { - body { - font-size: 16px; - } -} -@media (max-width: 740px) { - body { - font-size: 16px; - } -} - -main { - position: absolute; - top: 0; - padding: 0px 2.5px 0px 2.5px; -} - -#sidebar { - position: fixed; - top: 0; - margin: 0px 2.5px 0px 2.5px; - overflow: fixed; -} - -#demo { - margin: 0px 2.5px 0px 2.5px; - overflow: fixed; -} - -@media all { - #sidebar { - left: 50px; - width: 245px; - } - #sidebar.narrow { - width: 100px; - } - main { - left: 330px; - width: 580px; - } - main.sptable { - left: 190px; - } - main.comp { - left: 200px; - } -} - -@media (max-width: 880px) { - #sidebar { - left: 0px; - width: 20%; - } - main { - left: 24%; - width: 75%; - } -} - -@media (max-width: 670px) { - #sidebar { - left: 0px; - width: 5%; - } - main { - left: 7%; - width: 90%; - } -} - - -h1, -h2, -h3 { - font-family: Verdana, sans-serif; - font-variant: small-caps; - letter-spacing: 0.05em; - margin-top: 3em; -} - -h1 { - font-size: 140%; - margin-top: 1em; -} -h2 { - font-size: 110%; - margin-bottom: 0.5em; -} -h3 { - font-size: 110%; - margin-bottom: 0.5em; - margin-top: 0.8em; -} -h4 { - margin-bottom: 0.5em; - margin-top: 0.8em; -} - -p { - margin-top: 1em; - line-height: 1.35; - text-align: justify; -} - -hr { - margin: 1em; -} - -/* Style subscripts and superscripts to avoid wide line spacing. */ -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} -sup { - top: -0.5em; -} -sub { - bottom: -0.25em; -} - -.direct { - font-family: "Cambria Math"; -} -.reduced { - font-size: 80%; -} -.dim { - color: gray; -} - -.indented { - margin-left: 2.5em; -} -p.indented { - margin-top: 0.25em; - text-align: left; -} -.indented p { - margin-top: 0.5em; - text-align: left; -} - -table { - font-size: inherit; - border-collapse: collapse; - width: auto; -} - -div > table { - margin-left: 0; -} - -table td { - padding: 0.3em 0.8em 0.3em 0.8em; - vertical-align: middle; - hyphens: none; - white-space: nowrap; - border: 1px solid #ddd; -} - -table th { - font-size: 95%; - padding: 0.3rem 0.5rem 0.3rem 0.5rem; - line-height: 1.05; - border-bottom: 1px solid #ccc; - white-space: nowrap; -} - -table tbody tr:nth-child(even) { - background-color: #f6f8fa; -} - -/* Column alignment. Apply these classes to the table node. */ -.c1r td:nth-child(1), .c1r th:nth-child(1), -.c2r td:nth-child(2), .c2r th:nth-child(2), -.c3r td:nth-child(3), .c3r th:nth-child(3), -.c4r td:nth-child(4), .c4r th:nth-child(4), -.c5r td:nth-child(5), .c5r th:nth-child(5), -.c6r td:nth-child(6), .c6r th:nth-child(6), -.c7r td:nth-child(7), .c7r th:nth-child(7), -.c8r td:nth-child(8), .c8r th:nth-child(8), -.c9r td:nth-child(9), .c9r th:nth-child(9) { text-align:right } - -.c1c td:nth-child(1), .c1c th:nth-child(1), -.c2c td:nth-child(2), .c2c th:nth-child(2), -.c3c td:nth-child(3), .c3c th:nth-child(3), -.c4c td:nth-child(4), .c4c th:nth-child(4), -.c5c td:nth-child(5), .c5c th:nth-child(5), -.c6c td:nth-child(6), .c6c th:nth-child(6), -.c7c td:nth-child(7), .c7c th:nth-child(7), -.c8c td:nth-child(8), .c8c th:nth-child(8), -.c9c td:nth-child(9), .c9c th:nth-child(9) { text-align:center } - -ul { - padding: 0; -} - -ol li { - position: relative; - left: 2.2em; - width: 88%; - line-height: 1.35; - margin-top: 0.5em; -} -ul li { - list-style-type: disc; - line-height: 1.35; - margin-top: 0.5em; - position: relative; - left: 1.8em; -} - -ul li p { - margin-top: 0; -} - -a { - text-decoration: underline; - color: black; -} - -pre { - margin: 0px; - padding: 12px 12px 12px 12px; - line-height: 1.5; - display: block; - overflow: visible; -} - -code { - font-family: Consolas, "Courier New", Courier, monospace; - font-size: 85%; - /*color: #404040;*/ - background-color: rgba(27, 31, 35, 0.05); -} -pre > code, -td code { - background-color: transparent; -} - -.no-sup { - color: dimgray; -} - -#input-container { - font-size: 0.9em; - width: 100%; - height: 3em; - border-radius: 4px; - border: 1px solid rgb(200, 200, 200); - display: inline-block; - padding: 0.5em 0.5em; - vertical-align: top; - resize: none; -} - -#demo-output { - font-size: 0.9em; - width: 100%; - height: 5em; - padding: 1em 1em; - vertical-align: top; -} - -summary { - outline: none; - cursor: pointer; -} - -.mobile-menu { - position: absolute; - background: #fff; - border: 1px solid #aaa; - padding-right: 3em; -} -.mobile-menu summary:after { - content: none; -} - -/* Table of Contents, sidebar version */ -#sidebar { - cursor: pointer; - font-family: Calibri, sans-serif; - padding-top: 0.5em; - background: #fff; -} - -#sidebar li { - list-style: none; - line-height: 1.35; - position: relative; - margin-top: 0em; - left: 0em; -} - -#sidebar ul li ul { - padding-left: 1.3em; -} - -#sidebar ul li ul li { - margin-top: 0em; - width: 88%; -} - -#sidebar a { - text-decoration: none; - color: black; -} - -/* Table of Contents, mobile version */ -#mobile-nav { - display: none; /* hidden on large screens */ - position: fixed; -} - -/* On small screens, switch from sidebar TOC to navicon and drop-down menu */ -@media screen and (max-width: 670px) { - #mobile-nav { - display: block; - } - #sidebar { - display: none; - } -} - -#mobile-nav ul { - position: absolute; - top: -9999px; - left: -9999px; - display: block; - background:#fff; - border:1px solid #aaa; - padding-right: 3em; - color: black; - display: block; -} - -#mobile-nav input[type="checkbox"]:checked ~ ul { - top: 26px; - left: 25px; -} - -input[type="checkbox"] { - display: none; -} - -#mobile-nav li { - list-style: none; - margin: 0; - padding: 0.2em; -} - -#mobile-nav li a { - width: 60px; -} - -#mobile-nav a { - text-decoration: none; - color: black; -} diff --git a/site/docs/en/administration.html b/site/docs/en/administration.html deleted file mode 100644 index 4f5dc224..00000000 --- a/site/docs/en/administration.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - Temml Administration - - - -
-

Temml Administration

-

Browser Support

-

Temml works in browsers that support MathML. This includes Firefox and Safari. It will soon include Chrome, Edge, Opera, Brave, and Vivaldi.
Temml will never work in Internet Explorer.

-

Installation

-

You can download a zip file of Temml from the releases page of the Temml repository and serve Temml files from your own site. The minimum browser installation needs the following files. The css file and font file must be in the same folder.

-
  • temml.min.js
  • -
  • Temml-Local.css
  • -
  • Temml.woff2
  • -
-

A server-side installation should include temml.cjs instead of temml.min.js.

-

Starter template

-
<!DOCTYPE html>
-<!-- Temml requires the use of the HTML5 doctype. -->
-<html>
-    <head>
-        ...
-        <link rel="stylesheet" href="./Temml-Local.css">
-        <script src="./temml.min.js"></script>
-    </head>
-    ...
-</html>

API

-

Overview

-

Say that you have an HTMLCollection of elements whose contents should be converted from TeX strings to math. And also say that you wish to define two macros and a color with document-wide scope. The code for such a conversion might look like this:

-
// Optional preamble.
-const macros = temml.definePreamble(
-    `\\newcommand\\d[0]{\\operatorname{d}\\!}
-    \\def\\foo{x^2}
-    \\definecolor{sortaGreen}{RGB}{128,128,0}`
-);
-// Render all the math.
-for (let aSpan of [...mathSpans]) {
-    const tex = aSpan.textContent;
-    const displayMode = aSpan.classList.contains("display");
-    temml.render(tex, aSpan, { macros, displayMode });
-}
-// Optional postProcess to render \ref{}
-temml.postProcess(document.body);

Below, we examine the parts of that code.

-

In-Browser

-

To render math in one DOM element, call temml.render with a TeX expression and a DOM element to render into:

-
temml.render("c = \\pm\\sqrt{a^2 + b^2}", element);

Server-Side

-

To generate MathML on the server or to generate an MathML string of the rendered math, you can use temml.renderToString:

-
const temml = require('./temml.cjs');  // if in Node.js
-const mathML = temml.renderToString("c = \\pm\\sqrt{a^2 + b^2}");

Preamble

-

To give document-wide scope to a set of macros or colors, define them in a preamble.

-
const macros = temml.definePreamble(
-    `\\newcommand\\d[0]{\\operatorname{d}\\!}
-    \\def\\foo{x^2}
-    \\definecolor{sortaGreen}{RGB}{128,128,0}`
-);

Any valid Temml macro or \definecolor may be written into a preamble. Then include the resulting macros in the Temml options.

-

Options

-

You can provide an object of options as the last argument to temml.render and temml.renderToString. For example:

-
temml.render(
-  "c = \\pm\\sqrt{a^2 + b^2}",
-  element, 
-  { displayMode: true,  macros }
-);

Available options are:

-
  • 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)

    -
  • -
  • macros: object. A collection of custom macros. The easy way to create them is via a preamble, noted just above. Alternatively, you can provide a set of key-value pairs in which each key is a new Temml function name and each value is the expansion of the macro. Example: macros: {"\\R": "\\mathbb{R}"}.

    -
  • -
  • annotate: boolean. If true, Temml will include an <annotation> element that contains the input TeX string. Note: this will defeat soft line breaks in Firefox. (default: false)

    -
  • -
  • elementIsMath: boolean. When you call the temml.render() function, you pass an element as an argument to the function. If that element is a span, then allow elementIsMath to remain false (the default), and Temml will create a new <math> element inside the span. It you pass a <math> element as the argument, then set elementIsMath to true. Then Temml will populate it with math contents.

    -
  • -
  • leqno: boolean. If true, display math has \tags rendered on the left instead of the right, like \usepackage[leqno]{amsmath} in LaTeX. (default: false)

    -
  • -
  • preventTagLap: boolean. This option affects the horizontal alignment of displayMode math and \tags. The default (false) acts in the LaTeX manner and centers the math. That’s good in a wide container, but if the container is narrow, the tag will overlap the math. The preventTagLap: true option acts differently. It will first place the tag and then center the math in the remainder of the container, with no overlap. If you are targeting mobile, preventTagLap: true is probably a good choice .

    -
  • -
  • colorIsTextColor: boolean. In LaTeX, \color is a switch, but in early versions of MathJax and KaTeX, \color applied its color to a second argument, the way that LaTeX \textcolor works. Set option colorIsTextColor to true if you want \color to work like early MathJax or KaTeX. (default: false)

    -
  • -
  • errorColor: string. A color string given in the format "#XXX" or "#XXXXXX". This option determines the color that unsupported commands and invalid LaTeX are rendered in. (default: #b22222)

    -
  • -
  • maxSize: [number, number]. This provides a way to cap all user-specified sizes, e.g. in \rule{500em}{500em}. The first number is the cap in em units, which will be applied to user-specified relative units. The second number is the cap in CSS pt units, which will be applied to user-specified absolute units. The default is [Infinity, Infinity], which allows users to make elements and spaces arbitrarily large.

    -
  • -
  • maxExpand: number. Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to Infinity, the macro expander will try to fully expand as in LaTeX. (default: 1000)

    -
  • -
  • strict: boolean. If false (similar to MathJax), allow features that make writing LaTeX convenient but are not actually supported by LaTeX. If true (LaTeX faithfulness mode), throw an error for any such transgressions. (default: false)

    -
  • -
  • xml: boolean. If true, Temml will write a namespace into the <math> element. That namespace is xmlns="http://www.w3.org/1998/Math/MathML". Such a namespace is unnecessary for modern browsers but may be helpful for other user agents. (default: false)

    -
  • -
  • trust: boolean or function (default: false). If false (do not trust input), prevent any commands like \includegraphics that could enable adverse behavior, rendering them instead in errorColor. If true (trust input), allow all such commands. Provide a custom function handler(context) to customize behavior depending on the context (command, arguments e.g. a URL, etc.). A list of possible contexts:

    -
    • {command: "\\url", url, protocol}
    • -
    • {command: "\\href", url, protocol}
    • -
    • {command: "\\includegraphics", url, protocol}
    • -
    • {command: "\\class", class}
    • -
    • {command: "\\id", id}
    • -
    • {command: "\\style", style}
    • -
    • {command: "\\data", attributes}
    • -
    -

    Here are some sample trust settings:

    -
    • Forbid specific command: trust: (context) => context.command !== '\\includegraphics'
    • -
    • Allow specific command: trust: (context) => context.command === '\\url'
    • -
    • Allow multiple specific commands: trust: (context) => ['\\url', '\\href'].includes(context.command)
    • -
    • Allow all commands with a specific protocol: trust: (context) => context.protocol === 'http'
    • -
    • Allow all commands with specific protocols: trust: (context) => ['http', 'https', '_relative'].includes(context.protocol)
    • -
    • Allow all commands but forbid specific protocol: trust: (context) => context.protocol !== 'file'
    • -
    • Allow certain commands with specific protocols: trust: (context) => ['\\url', '\\href'].includes(context.command) && ['http', 'https', '_relative'].includes(context.protocol)
    • -
    -
  • -
-

Post Process

-

The postProcess function implements the AMS functions \ref and \label. It should be called outside of any loop.

-

The main Temml functions, temml.render and temml.renderToString, each operate on only one element at a time. In contrast, the postProcess function makes two passes through the entire document. If you choose not to support \ref, postProcess can be omitted.

-

If Temml is used server-side, \ref and \label are still implemented at runtime with client-side JavaScript. A small file, temmlPostProcess.js, is provided to be installed in place of temml.min.js. It exposes one function:

-
temml.postProcess(document.body)

If you do not provide a runtime postProcess, everthing in Temml will work except \ref.

-

If you use the auto-render extension, it includes the post-processor nuances.

-

Fonts

-

Temml has several different pre-written CSS files. You should use only one and by that choice, you also choose a math font. There are several math fonts available and each has different advantages.

-

Cambria Math comes pre-installed in Windows, Macs, and iOS, so it is the light-weight option. Cambria Math lacks roundhand glyphs, so you still have to serve a small (12 kb) font, Temml.woff2, in order to support \mathscr{…}. Sadly, Cambria Math radicals are sometimes too tall for their content.

-
More… -

You can mitigate the radical problem. It occurs because the font expects a cramped subscript when under a radical and Firefox does not perform that cramp. You can create your own cramp with braces. The expression f{_c'} will render just fine when f_c' renders poorly.

-
-

Latin Modern is a clone of Computer Modern and so is very home-like for readers accustomed to LaTeX documents. Rendering is excellent except that some line thicknesses may be too thin for some screens. This option also needs that additional 12kb Temml.woff2 file in order to support \mathscr{…}.

-

Asana, STIX TWO, and XITS can be served without the Temml.woff2 file.

-

Several other math fonts exist and you can try them out at Frédéric Wang’s Mathematical OpenType Fonts.

-

Where to find font files:

- -

If you want a different math font size, you can add a rule to your own page's CSS, like this example:

-
math { font-size: 125%; }

Equation numbering

-

In order to place automatic equation numbering in certain AMS environments, Temml contains these CSS rules:

-
.tml-eqn::before {
-  counter-increment: tmlEqnNo;
-  content: "(" counter(tmlEqnNo) ")";
-}
-body { counter-reset: tmlEqnNo; }

You can overwrite the content rule to produce customized equation numbers. For instance, if chapter three of your book is in its own html file, that file’s <head> could contain:

-
<style>
-   .tml-eqn::before { content: "(3." counter(tmlEqnNo) ")"; }
-</style>

Then the automatic equation numbering in that chapter would look like: (3.1)

-

If your site does not render automatic numbering properly, check if your other CSS has overwritten the Temml counter-reset.

-

Extensions

-

More Temml functionality can be added via the following extensions:

-
  • auto-render: Find and render all math in a running HTML page.
  • -
  • mhchem: Write beautiful chemical equations easily.
  • -
  • physics: Implement much of the LaTeX physics package.
  • -
  • texvc: Provide functions used in wikimedia.
  • -
-

To install extensions for browser use, include the appropriate file from the contrib folder of the Temml repository. Then reference the file in the <head> of the HTML page. As in this mhchem example:

-
  <head>
-    ...
-    <link rel="stylesheet" href="./Temml-Local.css">
-    <script src="./temml.min.js"></script>
-    <script src="./mhchem.min.js"></script>
-  </head>

The extension reference must come after the reference to temml.min.js.

-

For server-side use, just use temml.cjs instead of temml.min.js. temml.cjs includes mhchem, physics, and texvc.

-

Security

-

Any HTML generated by Temml should be safe from <script> or other code injection attacks.

-

A variety of options give finer control over the security of Temml with untrusted inputs; refer to Options for more details.

-
  • maxSize can prevent large width/height visual affronts.
  • -
  • maxExpand can prevent infinite macro loop attacks.
  • -
  • trust can allow certain commands that may load external resources or change HTML attributes and thus are not always safe (e.g., \includegraphics or \class)
  • -
-

Of course, it’s never a bad idea to sanitize your HTML. If you so choose, there is a list of Temml tags and attributes below the fold.

-
More… -
allowedTags: [
-  'span', 'img', 'math', 'annotation', 'semantics',
-  'maction', 'menclose', 'mfrac', 'mi', 'mmultiscripts',
-  'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot',
-  'mrow', 'mspace', 'msub', 'msup', 'msubsup', 'msqrt', 'mstyle', 'mtable',
-  'mtd', 'mtext', 'mtr', 'munder', 'munderover'
-],
-allowedAttributes: {
-  span: ['style'],
-  img: ['src', 'alt', 'width', 'height'],
-  math: ['xmlns', 'display'],
-  annotation: ['encoding'],
-  maction: ['actiontype'],
-  menclose: ['notation', 'mathbackground'],
-  mfrac: ['linethickness'],
-  mi: ['mathvariant', 'style'],
-  mn: ['mathvariant', 'style'],
-  mo: ['accent', 'fence', 'form', 'height', 'largeop', 'mathvariant', 'mathcolor', 'movablelimits',
-       'separator', 'stretchy', 'linebreak', 'minsize', 'maxsize', 'lspace', 'rspace'],
-  mpadded: ['width', 'height', 'depth', 'lspace', 'rspace', 'voffset', 'mathbackground', 'style'],
-  mrow: ['data', 'href', 'id'], // See `trust` rendering option.
-  mspace: ['mathbackground', 'width', 'height'],
-  mstyle: ['displaystyle', 'mathcolor', 'mathsize', 'scriptlevel', 'style'],
-  mtable: ['columnalign', 'rowspacing', 'columnspacing', 'columnlines', 'rowlines',
-           'width', 'scriptlevel'],
-  mtd: ['columnalign', 'style'],
-  mtext: ['mathvariant'],
-  munder: ['accentunder'],
-  mover: ['accent']
-},
-allowedClasses: [
-  // Temml creates these classes:
-  'mathcal', 'mathscr', 'oldstylenums', 'temml-error', 'tml-eqn', 'tml-tageqn', 'tml-label', 'tml-tag'
-  // If the trust setting allows \class, then users can create their own classes.
-]
-// The \label function can create HTML ids. These ids can contain only the characters [A-Za-z_0-9-]
-// An \id function, if allowed by the trust settings, can create HTML ids with unrestricted contents.
-
-

Copyright © 2021, 2022 Ron Kok. Released under the MIT License

-
-
- -
- - - - -
- - diff --git a/site/docs/en/comparison.html b/site/docs/en/comparison.html deleted file mode 100644 index 7aa08487..00000000 --- a/site/docs/en/comparison.html +++ /dev/null @@ -1,9732 +0,0 @@ - - - - - Comparison of TeX Coverage - - - - - - - - - - -
- -

Foreword

- -

This page compares the MathML output from four TeX-to-MathML conversion libraries. You should use Firefox or Safari to view this page because they can render the MathML today. MathML will be viewable in Chrome and Edge soon.

- -

MathJax and KaTeX of course also render math in other formats. This comparison is limited to MathML.

- -

Versions used are: Temml 0.6.9, MathJax 2.7.5, KaTeX 0.13.9, and TeXZilla 1.0.2.0

- -

Symbols

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Symbol/FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
+a+b\(a+b\)a+ba+ba+ba+ba+b
-ab\(a-b\)aba-baba-ba-b
!n!\(n!\)n!n!n!n!n!
\!a!b\(a!b\)a!ba!ba!ba!ba\!b
#y2\(\def\bar#1{#1^2} \bar{y}\)y2\def\bar#1{#1^2} \bar{y}Not supported\def\bar#1{#1^2} \bar{y}
\##\(\#\)#\##\#
%\(%a comment\)%a commentNot supported%a comment
\%%\(\%\)%\%%\%
&abcd\(\begin{matrix} a & b\\ c & d \end{matrix}\)abcd\begin{matrix} a & b\\ c & d \end{matrix}abcd\begin{matrix} a & b\\ c & d \end{matrix}\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\&&\(\&\)&\&&\&
'\('\)'Not supported
\'aˊNot supportedaˊ\text{\'{a}}Not supported\text{\'{a}}
((\((\)((((
))\()\)))))
\a b\(a\ b\)a ba\ bNot supporteda\ b
\"a¨Not supporteda¨\text{\"{a}}Not supported\text{\"{a}}
\$$Not supported$\text{\textdollar}Not supported
\,ab\(a\,\,{b}\)aba\,\,{b}aba\,\,{b}a\,\,{b}
\.a˙Not supporteda˙\text{\.{a}}Not supported\text{\.{a}}
\:ab\(a\:\:{b}\)aba\:\:{b}aba\:\:{b}a\:\:{b}
\;ab\(a\;\;{b}\)a    ba\;\;{b}aba\;\;{b}aa\;\;{b}
_xi\(x_i\)xix_ixix_ix_i
\__\(\_\)_\_Not supported
\`aˊNot supportedaˊ\text{\'{a}}Not supported\text{\'{a}}
<<\(<\)<<<<
\=aˉNot supportedaˉ\text{\={a}}Not supported\text{\={a}}
>>\( > \)>>>>
\>ab\(a\>\>{b}\)aba\>\>{b}Not supporteda\>\>{b}
[[\([\)[[[[
]]\(]\)]]]]
{a\({a}\)a{a}a{a}{a}
}a\({a}\)a{a}a{a}{a}
\{{\(\{\){\{{\{
\}}\(\}\)}\}}\}
||\(|\)|||
\|\(\|\)\|\|
~no break\(\text{no~break}\)no break\text{no~break}Not supported\text{no~break}
\~a˜Not supporteda˜\text{\~{a}}Not supported\text{\~{a}}
\\abcd\(\begin{matrix} a & b\\ c & d\end{matrix}\)abcd\begin{matrix} a & b\\ c & d\end{matrix}abcd\begin{matrix} a & b\\ c & d\end{matrix}\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\\xy\(x \\ y\)xyx \\ yNot supportedx \\ y
^xi\(x^i\)xix^ixix^ix^i
\^aˆNot supportedaˆ\text{\^{a}}Not supported\text{\^{a}}
special fraction1³⁄₄\(1\kern2mu \text{³⁄₄}\)1³⁄₄1\kern2mu \text{³⁄₄}Not supported1\kern2mu \text{³⁄₄}
- -

A

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\AANot supportedA˚\text{\AA}Not supported\text{\AA}
\aaa˚Not supporteda˚\text{\aa}Not supported\text{\aa}
\aboveab+1\({a \above{2pt} b+1}\)ab+1{a \above{2pt} b+1}Not supported{a \above{2pt} b+1}
\abovewithdelimsNot supported\(a+1 \abovewithdelims [ ] 1pt b\)Not supportedNot supporteda+1 \abovewithdelims [ ] 1pt b
\acuteeˊ\(\acute e\)eˊ\acute eNot supported\acute e
\AEÆNot supportedÆ\text{\AE}Not supported\text{\AE}
\aeæNot supportedæ\text{\ae}Not supported\text{\ae}
\alef\(\alef\)\alefNot supported
\alefsym\(\alefsym\)\alefsymNot supported
\aleph\(\aleph\)\aleph\aleph
{align}a=b+cd+e=f\[\begin{align}a &=b+c\\d+e&=f\end{align}\]a=b+cd+e=f\begin{align}a &=b+c\\d+e&=f\end{align}Not supported\begin{align}
   a&=b+c \\
   d+e&=f
\end{align}
{align*}a=b+cd+e=f\[\begin{align*}a &=b+c\\d+e&=f\end{align*}\]a=b+cd+e=f\begin{align*}a &=b+c\\d+e&=f\end{align*}Not supported\begin{align*}
   a&=b+c \\
   d+e&=f
\end{align*}
{aligned}x=ya=b+cx=ya=b\(\begin{aligned}x&=y & a&=b+c\\x'&=y' & a'&=b'\end{aligned}\)x=ya=b+cx=ya=b\begin{aligned}x&=y & a&=b+c\\x'&=y' & a'&=b'\end{aligned}x=ya=b+cx=ya=b\begin{aligned}x&=y & a&=b+c\\x'&=y' & a'&=b'\end{aligned}\begin{aligned}
x&=y & a&=b+c\\
x'&=y' & a'&=b'
\end{aligned}
{alignat}10x+3y=23x+13y=4\[\begin{alignat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat}\]10x+3y=23x+13y=4\begin{alignat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat}Not supported
{alignat*}10x+3y=23x+13y=4\[\begin{alignat*}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat*}\]10x+3y=23x+13y=4\begin{alignat*}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignat*}Not supported
{alignedat}10x+3y=23x+13y=4\(\begin{alignedat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignedat}\)10x+3y=23x+13y=4\begin{alignedat}{2}10&x+&3&y=2\\3&x+&13&y=4\end{alignedat}Not supported\begin{alignedat}{2}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{alignedat}
\allowbreakSupportedNot supportedNot supportedNot supported
\AlphaΑ\(\Alpha\)A\AlphaΑ\Alpha
\alphaα\(\alpha\)α\alphaα\alpha
\amalg⨿\(\amalg\)⨿\amalg⨿\amalg
\And&\(\And\)&\AndNot supported
\andNot supported\(\and\)Not supportedNot supportedDeprecated
\angNot supported\(\ang\)Not supportedNot supportedDeprecated
\anglanNot supported
See \enclose
ana_{\angl n}Not supporteda_{\angl n}
\angle\(\angle\)\angle\angle
\anglnanNot supported
See \enclose
ana_\anglnNot supporteda_\angln
\approx\(\approx\)\approx\approx
\approxeq\(\approxeq\)\approxeq\approxeq
\arccosarccosx\(\arccos x\)arccosx\arccos xarccosx\arccos x
\arcctgarcctgxNot supportedarcctgx\arcctg xNot supported
\arcsinarcsinx\(\arcsin x\)arcsinx\arcsin xarcsinx\arcsin x
\arctanarctanx\(\arctan x\)arctanx\arctan xarctanx\arctan x
\arctgarctgxNot supportedarctgx\arctg xNot supported
\argarg\(\arg\)arg\argarg\arg
\argmaxargmaxxargmaxyxargmaxyxNot supportedarg maxxarg maxyxarg maxyx\begin{matrix}\argmax x \\ \argmax_y x \\\argmax\limits_y x\end{matrix}Not supported
\argminargminNot supportedarg min\argminNot supported
{array}abcd\(\begin{array}{cc}a&b\\c&d\end{array}\)abcd\begin{array}{cc}a&b\\c&d\end{array}abcd\begin{array}{cc}a&b\\c&d\end{array}\begin{array}{cc}
   a & b \\
   c & d
\end{array}
{array}
with lines
abcdefghi\(\begin{array}{c|c:c}a & b & c \\ \hline d & e & f \\ \hdashline g & h & i\end{array}\)abcdefghi\begin{array}{c|c:c}a & b & c \\ \hline d & e & f \\ \hdashline g & h & i\end{array}Not supported\begin{array}{c|c:c}
a & b & c \\ \hline
d & e & f\\
\hdashline g & h & i
\end{array}
\arrayNot supported\(\array{ a & b+1 \\ c+1 & d }\)Not supportedab+1c+1d\array{ a & b+1 \\ c+1 & d }\array{ a & b+1 \\ c+1 & d }
\arraystretchabcd\(\def\arraystretch{1.5}\begin{array}{cc}a&b\\c&d\end{array}\)abcd\def\arraystretch{1.5}\begin{array}{cc}a&b\\c&d\end{array}Not supported\def\arraystretch{1.5}
\begin{array}{cc}
   a & b \\
   c & d
\end{array}
\ArrowvertNot supported\(\Arrowvert\)Not supportedNot supported
\arrowvertNot supported\(\arrowvert\)Not supportedNot supported
\ast\(\ast\)\ast\ast
\asymp\(\asymp\)\asymp\asymp
\atopab\({a \atop b}\)ab{a \atop b}ab{a \atop b}{a \atop b}
\atopwithdelimsNot supported\(a \atopwithdelims [ ] b\)Not supportedNot supporteda \atopwithdelims [ ] b
- -

B

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\backepsilon\(\backepsilon\)\backepsilon϶\backepsilon
\backprime\(\backprime\)\backprimeNot supported
\backsim\(\backsim\)\backsim\backsim
\backsimeq\(\backsimeq\)\backsimeq\backsimeq
\backslash\\(\backslash\)\\backslash\\backslash
\ballotxNot supportedNot supportedNot supported
\bary\(\bar{y}\)y2\bar{y}y¯\bar{y}\bar{y}
\barwedge\(\barwedge\)\barwedge\barwedge
\Bbb𝔸𝔹\(\Bbb{ABC}\)ABC\Bbb{ABC}Not supported\Bbb{ABC}
\Bbbk𝕜\(\Bbbk\)k\BbbkNot supported
\bboxNot supportedRequires extensionNot supportedNot supported
\bcancel5\(\bcancel{5}\)5\bcancel{5}Not supported\bcancel{5}
\because\(\because\)\because\because
\beginabcd\(\begin{matrix} a & b\\ c & d\end{matrix}\)abcd\begin{matrix} a & b\\ c & d\end{matrix}abcd\begin{matrix} a & b\\ c & d\end{matrix}\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\begingroupa\(\begingroup a \endgroup\)a\begingroup a \endgroupNot supported\begingroup a\endgroup
\BetaΒ\(\Beta\)B\BetaΒ\Beta
\betaβ\(\beta\)β\betaβ\beta
\beth\(\beth\)\beth\beth
\between\(\between\)\between\between
\bf𝐀𝐚𝐁𝐛𝟏𝟐\(\bf AaBb12\)AaBb12\bf AaBb12Not supported\bf AaBb12
\big()\(\big(\big)\)()\big(\big)()\big(\big)\big(\big)
\Big()\(\Big(\Big)\)()\Big(\Big)()\Big(\Big)\Big(\Big)
\bigcap0nx0nx\(\bigcap_0^n x \; \displaystyle \bigcap_0^n x\)0nx  0nx\bigcap_0^n x \; \displaystyle \bigcap_0^n x\bigcap
\bigcirc\(\bigcirc\)\bigcirc\bigcirc
\bigcup0nx0nx\(\bigcup_0^n x \; \displaystyle \bigcup_0^n x\)0nx  0nx\bigcup_0^n x \; \displaystyle \bigcup_0^n x\bigcup
\bigg()\(\bigg(\bigg)\)()\bigg(\bigg)()\bigg(\bigg)\bigg(\bigg)
\Bigg()\(\Bigg(\Bigg)\)()\Bigg(\Bigg)()\Bigg(\Bigg)\Bigg(\Bigg)
\biggl(\(\biggl(\)(\biggl((\biggl(\biggl(
\Biggl(\(\Biggl(\)(\Biggl((\Biggl(\Biggl(
\biggm|\(\biggm\vert\)\biggm\vertNot supported\biggm\vert
\Biggm|\(\Biggm\vert\)\Biggm\vertNot supported\Biggm\vert
\biggr)\(\biggr)\))\biggr))\biggr)\biggr)
\Biggr)\(\Biggr)\))\Biggr))\Biggr)\Biggr)
\bigl(\(\bigl(\)(\bigl((\bigl(\bigl(
\Bigl(\(\Bigl(\)(\Bigl((\Bigl(\Bigl(
\bigm|\(\bigm\vert\)\bigm\vertNot supported\bigm\vert
\Bigm|\(\Bigm\vert\)\Bigm\vertNot supported\Bigm\vert
\bigodot0nx0nx\(\bigodot_0^n x \; \displaystyle \bigodot_0^n x\)0nx  0nx\bigodot_0^n x \; \displaystyle \bigodot_0^n x\bigodot
\bigominusNot supportedNot supportedNot supportedNot supported
\bigoplus0nx0nx\(\bigoplus_0^n x \; \displaystyle \bigoplus_0^n x\)0nx  0nx\bigoplus_0^n x \; \displaystyle \bigoplus_0^n x\bigoplus
\bigoslashNot supportedNot supportedNot supportedNot supported
\bigotimes0nx0nx\(\bigotimes_0^n x \; \displaystyle \bigotimes_0^n x\)0nx  0nx\bigotimes_0^n x \; \displaystyle \bigotimes_0^n x\bigotimes
\bigr)\(\bigr)\))\bigr))\bigr)\bigr)
\Bigr)\(\Bigr)\))\Bigr))\Bigr)\Bigr)
\bigsqcapNot supportedNot supportedNot supported\bigsqcap
\bigsqcup0nx0nx\(\bigsqcup_0^n x \; \displaystyle \bigsqcup_0^n x\)0nx  0nx\bigsqcup_0^n x \; \displaystyle \bigsqcup_0^n x\bigsqcup
\bigstar\(\bigstar\)\bigstar\bigstar
\bigtriangledown\(\bigtriangledown\)\bigtriangledown\bigtriangledown
\bigtriangleup\(\bigtriangleup\)\bigtriangleup\bigtriangleup
\biguplus0nx0nx\(\biguplus_0^n x \; \displaystyle \biguplus_0^n x\)0nx  0nx\biguplus_0^n x \; \displaystyle \biguplus_0^n x\biguplus
\bigvee0nx0nx\(\bigvee_0^n x \; \displaystyle \bigvee_0^n x\)0nx  0nx\bigvee_0^n x \; \displaystyle \bigvee_0^n x\bigvee
\bigwedge0nx0nx\(\bigwedge_0^n x \; \displaystyle \bigwedge_0^n x\)0nx  0nx\bigwedge_0^n x \; \displaystyle \bigwedge_0^n x\bigwedge
\binom(nk)\(\binom n k\)(nk)\binom n k(nk)\binom n k\binom n k
\blacklozenge\(\blacklozenge\)\blacklozenge\blacklozenge
\blacksquare\(\blacksquare\)\blacksquare\blacksquare
\blacktriangle\(\blacktriangle\)\blacktriangle\blacktriangle
\blacktriangledown\(\blacktriangledown\)\blacktriangledown\blacktriangledown
\blacktriangleleft\(\blacktriangleleft\)\blacktriangleleft\blacktriangleleft
\blacktriangleright\(\blacktriangleright\)\blacktriangleright\blacktriangleright
\bm𝑨𝒂𝑩𝒃Not supportedAaBb\bm{AaBb}Not supported\bm{AaBb}
{Bmatrix}{abcd}\(\begin{Bmatrix}a&b\\c&d\end{Bmatrix}\){abcd}\begin{Bmatrix}a&b\\c&d\end{Bmatrix}{abcd}\begin{Bmatrix}a&b\\c&d\end{Bmatrix}\begin{Bmatrix}
   a & b \\
   c & d
\end{Bmatrix}
{bmatrix}[abcd]\(\begin{bmatrix}a&b\\c&d\end{bmatrix}\)[abcd]\begin{bmatrix}a&b\\c&d\end{bmatrix}[abcd]\begin{bmatrix}a&b\\c&d\end{bmatrix}\begin{bmatrix}
   a & b \\
   c & d
\end{bmatrix}
\bmodamodb\(a \bmod b\)amodba \bmod bNot supporteda \bmod b
\bold𝐀𝐚𝐁𝐛𝟏𝟐𝟑\(\bold{AaBb123}\)AaBb123\bold{AaBb123}Not supported\bold{AaBb123}
\boldsymbol𝑨𝒂𝑩𝒃0\(\boldsymbol{AaBb0}\)AaBb0\boldsymbol{AaBb0}𝐀𝐚𝐁𝐛𝟎\boldsymbol{AaBb0}\boldsymbol{AaBb0}
\bot\(\bot\)\bot\bot
\BotNot supportedNot supportedNot supported
\bowtie\(\bowtie\)\bowtie\bowtie
\Box\(\Box\)\Box\Box
\boxdot\(\boxdot\)\boxdot\boxdot
\boxedab\(\boxed{ab}\)ab\boxed{ab}ab\boxed{ab}\boxed{ab}
\boxminus\(\boxminus\)\boxminus\boxminus
\boxplus\(\boxplus\)\boxplus\boxplus
\boxtimes\(\boxtimes\)\boxtimes\boxtimes
\Braψ|Requires extensionψ\Bra{\psi}Not supported\Bra{\psi}
\braψ|Requires extensionψ\bra{\psi}Not supported\bra{\psi}
\brace{nk}\({n\brace k}\){nk}{n\brace k}Not supported{n\brace k}
\brack[nk]\({n\brack k}\)[nk]{n\brack k}Not supported{n\brack k}
\braketϕ|ψNot supportedϕψ\braket{\phi|\psi}Not supported\braket{\phi|\psi}
\Braketϕ|2t2|ψRequires extenstionNot supportedNot supported\Braket{ϕ|\frac{∂^2}{∂ t^2}|ψ}
\breveeu˘\(\breve{eu}\)eu˘\breve{eu}Not supported\breve{eu}
\buildrelNot supported\(\buildrel \rm def \over {:=}\)Not supportedNot supported\buildrel \rm def \over {:=}
\bull\(\bull\)\bullNot supported
\bullet\(\bullet\)\bullet\bullet
\Bumpeq\(\Bumpeq\)\Bumpeq\Bumpeq
\bumpeq\(\bumpeq\)\bumpeq\bumpeq
- -

C

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\CNot supported\(\C\)Not supportedNot supportedDeprecated
\cc¸Not supportedNot supportedNot supported\text{\c{c}}
\cal𝒜𝒞Not supportedABC\cal ABCNot supported\cal ABC
\cancel5\(\cancel{5}\)5\cancel{5}Not supported\cancel{5}
\canceltox0Not supportedNot supportedNot supported
\Cap\(\Cap\)\Cap\Cap
\cap\(\cap\)\cap\cap
{cases}{aif bcif d\(\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}\){aif bcif d\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}{aif bcif d\begin{cases}a&\text{if }b\\c&\text{if }d\end{cases}\begin{cases}
   a &\text{if } b \\
   c &\text{if } d
\end{cases}
\casesNot supported\(\cases{ x & \text{if } x\ge 0\\ -x & \text{if } x\lt 0}\)Not supportedNot supported\cases{x & \text{if } x\ge 0\\
- -x & \text{if } x\lt 0} -
{CD}AaBbcC=D\(\begin{CD} A @>a>> B\\@VbVV @AAcA \\ C @= D\end{CD}\)AaBbcC=D\begin{CD} A @>a>> B\\@VbVV @AAcA \\ C @= D\end{CD}Not supported
\cdot\(\cdot\)\cdot\cdot
\cdotp·\(\cdotp\)\cdotp·\cdotp
\cdots\(\cdots\)\cdots\cdots
\ceABC\(\ce{A\bond{~}B\bond{~-}C}\)Not supportedNot supported\ce{A\bond{~}B\bond{~-}C}
Requires `mhchem` extension
\ceeNot supported\(\cee{C6H5-CHO}\)Not supportedNot supportedDeprecated by mhchem
\centerdotab\(a\centerdot b\)aba\centerdot bNot supportedIn LaTeX, \centerdot is a small
square on the baseline, not
a centered dot.
\cfNot supported\(\cf{C6H5-CHO}\)Not supportedNot supportedDeprecated by mhchem
\cfrac21+21+21\(\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}\)21+21+21\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}Not supported\cfrac{2}{1+\cfrac{2}{1+\cfrac{2}{1}}}
\charNot supported
See \unicode
\char"263aNot supported\char"263a
\checkoeˇ\(\check{oe}\)oeˇ\check{oe}oeˇ\check{oe}\check{oe}
\chchNot supportedch\chNot supported
\checkmark\(\checkmark\)\checkmarkNot supported
\ChiΧ\(\Chi\)X\ChiNot supported
\chiχ\(\chi\)χ\chiχ\chi
\choose(n+1k+2)\({n+1 \choose k+2}\)(n+1k+2){n+1 \choose k+2}(n+1k+2){n+1 \choose k+2}{n+1 \choose k+2}
\circ\(\circ\)\circ\circ
\circeq\(\circeq\)\circeq\circeq
\circlearrowleft\(\circlearrowleft\)\circlearrowleft\circlearrowleft
\circlearrowright\(\circlearrowright\)\circlearrowright\circlearrowright
\circledast\(\circledast\)\circledast\circledast
\circledcirc\(\circledcirc\)\circledcirc\circledcirc
\circleddash\(\circleddash\)\circleddash\circleddash
\circledR®\(\circledR\)®\circledRNot supported
\circledS\(\circledS\)\circledSNot supported
\classabcdefghNot supportedNot supportedNot supportedab\class{mathHighlight}{cdef}gh
\clineNot supportedNot supportedNot supportedNot supported
\clubs\(\clubs\)\clubsNot supported
\clubsuit\(\clubsuit\)\clubsuit\clubsuit
\cnums\(\cnums\)C\cnumsNot supported
\cohNot supportedNot supportedNot supported
\colon:\(\colon\) ⁣:\colon:\colon
\Colonapprox∷≈Not supported\Colonapprox∷≈\Colonapprox
\colonapprox:Not supported:\colonapprox∶≈\colonapprox
\Coloneq∷−Not supported\Coloneq∷−\Coloneq
\coloneq:Not supported:\coloneq\coloneq
\ColoneqqNot supported=\Coloneqq\Coloneqq
\coloneqqabNot supportedaba \coloneqq baba \coloneqq b
\Colonsim:Not supported\Colonsim∷∼\Colonsim
\colonsim:Not supported:\colonsim∶∼\colonsim
\colorAaBb123\(\color{#0000FF} AaBb123\)AaBb123\color{#0000FF} AaBb123AaBb123\color{#0000FF} AaBb123\color{#0000FF} AaBb123
\colorboxBlack on red\(\colorbox{red}{Black on red}\)Black on red\colorbox{red}{Black on red}Not supported\colorbox{red}{Black on red}
\complement\(\complement\)\complement\complement
\Complex\(\Complex\)C\ComplexNot supported
\cong\(\cong\)\cong\cong
\CoppaϘNot supportedNot supportedNot supported
\coppaϙNot supportedNot supportedNot supported
\coprod0nx0nx\(\coprod_0^n x \; \displaystyle \coprod_0^n x\)0nx  0nx\coprod_0^n x \; \displaystyle \coprod_0^n x\coprod
\copyright©Not supported©\copyrightNot supported
\coscosx\(\cos x\)cosx\cos xcosx\cos x
\coseccosecxNot supportedcosecx\cosec xNot supported
\coshcoshx\(\cosh x\)coshx\cosh xcoshx\cosh x
\cotcotx\(\cot x\)cotx\cot xcotx\cot x
\cotgcotgxNot supportedcotgx\cotg xNot supported
\cothcothx\(\coth x\)cothx\coth xcothx\coth x
\crabcd\(\begin{matrix} a & b\\ c & d \end{matrix}\)abcd\begin{matrix} a & b\\ c & d \end{matrix}abcd\begin{matrix} a & b\\ c & d \end{matrix}\begin{matrix}
   a & b \cr
   c & d
\end{matrix}
\csccscx\(\csc x\)cscx\csc xcscx\csc x
\cssIdNot supportedNot supportedNot supported
\ctgctgxNot supportedctgx\ctg xNot supported
\cthcthxNot supportedcthx\cth xNot supported
\Cup\(\Cup\)\Cup\Cup
\cup\(\cup\)\cup\cup
\curlyeqprec\(\curlyeqprec\)\curlyeqprec\curlyeqprec
\curlyeqsucc\(\curlyeqsucc\)\curlyeqsucc\curlyeqsucc
\curlyvee\(\curlyvee\)\curlyvee\curlyvee
\curlywedge\(\curlywedge\)\curlywedge\curlywedge
\curvearrowleft\(\curvearrowleft\)\curvearrowleft\curvearrowleft
\curvearrowright\(\curvearrowright\)\curvearrowright\curvearrowright
- -

D

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\dagNot supported\dagNot supported
\Dagger\(\Dagger\)\DaggerNot supported
\dagger\(\dagger\)\dagger\dagger
\daleth\(\daleth\)\daleth\daleth
\Darr\(\Darr\)\DarrNot supported
\dArr\(\dArr\)\dArrNot supported
\darr\(\darr\)\darr\darr
{darray}abcd\(\begin{array}{cc}a & b\\c & d\end{array}\)abcd\begin{array}{cc}a & b\\c & d\end{array}abcd\begin{array}{cc}a & b\\c & d\end{array}\begin{darray}{cc}
   a & b \\
   c & d
\end{darray}
\dashleftarrow\(\dashleftarrow\)\dashleftarrow\dashleftarrow
\dashrightarrow\(\dashrightarrow\)\dashrightarrow\dashrightarrow
\dashv\(\dashv\)\dashv\dashv
\dbinom(nk)\(\dbinom n k\)(nk)\dbinom n kNot supported\dbinom n k
\dblcolonNot supported\dblcolon\dblcolon
{dcases}{aif bcif dNot supported{aif bcif d\begin{dcases}a&\text{if }b\\c&\text{if }d\end{dcases}Not supported\begin{dcases}
   a &\text{if } b \\
   c &\text{if } d
\end{dcases}
\ddagNot supported\ddagNot supported
\ddagger\(\ddagger\)\ddagger\ddagger
\ddddotxNot supportedNot supportedx\ddddot x
\dddotxNot supportedNot supportedx\dddot x
\ddotx¨\(\ddot x\)x¨\ddot xẍ\ddot x\ddot x
\ddots\(\ddots\)\ddots\ddots
\DeclareMathOperatorNot supported\(\DeclareMathOperator - {\myOp}{myOp} - \myOp(x)\) - Not supportedNot supported
\defx2+x2\(\def\foo{x^2} \foo + \foo\)x2+x2\def\foo{x^2} \foo + \fooNot supported\def\foo{x^2} \foo + \foo
\definecolorF=maNot supportedNot supportedNot supported
\degdegx\(\deg x\)degx\deg xdegx\deg x
\degree°Not supported°\degree°\degree
\deltaδ\(\delta\)δ\deltaδ\delta
\DeltaΔ\(\Delta\)Δ\DeltaΔ\Delta
\detdetxdetyxdetyx\(\begin{matrix}\det x \\ \det_y x \\\det\limits_y x\end{matrix}\)detxdetyxdetyx\begin{matrix}\det x \\ \det_y x \\\det\limits_y x\end{matrix}det\det
\DigammaNot supported\(\Digamma\)Not supportedNot supported
\digammaϝ\(\digamma\)ϝ\digammaϝ\digamma
\dfraca1b1\(\dfrac{a-1}{b-1}\)a1b1\dfrac{a-1}{b-1}Not supported\dfrac{a-1}{b-1}
\diagdown\(\diagdown\)\diagdownNot supported
\diagup\(\diagup\)\diagupNot supported
\Diamond\(\Diamond\)\Diamond\Diamond
\diamond\(\diamond\)\diamond\diamond
\diamonds\(\diamonds\)\diamondsNot supported
\diamondsuit\(\diamondsuit\)\diamondsuit\diamondsuit
\dimdimx\(\dim x\)dimx\dim xdimx\dim x
\displaylinesNot supported\(\displaylines{a\\ a+b=c+d}\)Not supportedNot supported\displaylines{a\\ a+b=c+d}
\displaystyle0n\(\displaystyle\sum_0^n\)0n\displaystyle\sum_0^n0n\displaystyle\sum_0^n\displaystyle\sum_0^n
\div÷\(\div\)÷\div÷\div
\divideontimes\(\divideontimes\)\divideontimes\divideontimes
\dotx˙\(\dot x\)x˙\dot xx˙\dot x\dot x
\Doteq\(\Doteq\)\Doteq\Doteq
\doteq\(\doteq\)\doteq\doteq
\doteqdot\(\doteqdot\)\doteqdot\doteqdot
\dotplus\(\dotplus\)\dotplus\dotplus
\dotsx1++xn\(x_1 + \dots + x_n\)x1++xnx_1 + \dots + x_nx1++xnx_1 + \dots + x_nx_1 + \dots + x_n
\dotsbx1++xn\(x_1 +\dotsb + x_n\)x1++xnx_1 +\dotsb + x_nNot supportedx_1 +\dotsb + x_n
\dotscx,,y\(x,\dotsc,y\)x,,yx,\dotsc,yNot supportedx,\dotsc,y
\dotsiA1A2\(\int_{A_1}\int_{A_2}\dotsi\)A1A2 ⁣\int_{A_1}\int_{A_2}\dotsiNot supported\int_{A_1}\int_{A_2}\dotsi
\dotsmx1x2xn\(x_1 x_2 \dotsm x_n\)x1x2xnx_1 x_2 \dotsm x_nNot supportedx_1 x_2 \dotsm x_n
\dotso\(\dotso\)\dotsoNot supported
\doublebarwedge\(\doublebarwedge\)\doublebarwedge\doublebarwedge
\doublecap\(\doublecap\)\doublecapNot supported
\doublecup\(\doublecup\)\doublecupNot supported
\Downarrow\(\Downarrow\)\Downarrow\Downarrow
\downarrow\(\downarrow\)\downarrow\downarrow
\downdownarrows\(\downdownarrows\)\downdownarrows\downdownarrows
\downharpoonleft\(\downharpoonleft\)\downharpoonleft\downharpoonleft
\downharpoonright\(\downharpoonright\)\downharpoonright\downharpoonright
{drcases}aif bcif d}Not supportedaif bcif d}\begin{drcases}a&\text{if }b\\c&\text{if }d\end{drcases}Not supported\begin{drcases}
   a&\text{if }b\\
   c&\text{if }d
\end{drcases}
- -

E

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\ell\(\ell\)\ell\ell
\elseNot supportedNot supportedNot supportedNot supported
\empty\(\empty\)\empty\empty
\emptyset\(\emptyset\)\emptyset\emptyset
\encloseNot supported
See \longdiv,
\angl, \phase
\(\enclose{longdiv}{500}\)
\(\enclose{actuarial}{500}\)
\(\enclose{phasorangle}{500}\)
Not supportedNot supported\enclose{longdiv}{500}
\enclose{actuarial}{500}
\enclose{phasorangle}{500}
Non-standard
\endabcd\(\begin{matrix} a & b\\ c & d\end{matrix}\)abcd\begin{matrix} a & b\\ c & d\end{matrix}abcd\begin{matrix} a & b\\ c & d\end{matrix}\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\endgroupa\(\begingroup a \endgroup\)a\begingroup a \endgroupNot supported\begingroup a\endgroup
\enspaceab\(a\enspace b\)aba\enspace bNot supporteda\enspace b
\EpsilonΕ\(\Epsilon\)E\EpsilonNot supported
\epsilonϵ\(\epsilon\)ϵ\epsilonϵ\epsilon
\eqalignNot supported\(\eqalign{3x - 4y &= 5\\x + 7 &= -2y}\)Not supportedNot supported
\eqalignnoNot supported\(\eqalignno{3x - 4y &= 5 &(\dagger) \\ x + 7 &= -2y &(\ddagger)\\ z &= 2}\)Not supportedNot supported
\eqcirc\(\eqcirc\)\eqcirc\eqcirc
\Eqcolon−∷Not supported\Eqcolon−∷\Eqcolon
\eqcolonNot supported\eqcolon\eqcolon
{equation}·𝐃=ρv·𝐁=0\[\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}\]𝐃=ρv𝐁=0\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}Not supported\begin{equation}
\begin{split}
   ∇·𝐃&=ρ_v \\
   ∇·𝐁&=0
\end{split}
\end{equation}
{equation*}·𝐃=ρv·𝐁=0\[\begin{equation*}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation*}\]𝐃=ρv𝐁=0\begin{equation*}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation*}Not supported
{eqnarray}Not supported\(\begin{eqnarray} -y &=& (x-1)^2 \\ - &=& (x-1)(x-1) \\ - &=& x^2 - 2x + 1 -\end{eqnarray}\)Not supportedNot supported
{eqnarray*}Not supported\(\begin{eqnarray*} -y &=& (x-1)^2 \\ - &=& (x-1)(x-1) \\ - &=& x^2 - 2x + 1 -\end{eqnarray*}\)Not supportedNot supported
\Eqqcolon=∷Not supported=\Eqqcolon=∷\Eqqcolon
\eqqcolonNot supported\eqqcolon\eqqcolon
\eqrefNot supportedNot supportedNot supported
\eqsim\(\eqsim\)\eqsim\eqsim
\eqslantgtr\(\eqslantgtr\)\eqslantgtr\eqslantgtr
\eqslantless\(\eqslantless\)\eqslantless\eqslantless
\equiv\(\equiv\)\equiv\equiv
\EtaΗ\(\Eta\)H\EtaΗ\Eta
\etaη\(\eta\)η\etaη\eta
\ethð\(\eth\)ð\ethð\eth
\euro\(\euro\)Not supportedNot supported
\exist\(\exist\)\existNot supported
\exists\(\exists\)\exists\exists
\expexpx\(\exp x\)expx\exp xexpx\exp x
- -

F

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\fallingdotseq\(\fallingdotseq\)\fallingdotseq\fallingdotseq
\fboxHi there!\(\fbox{Hi there!}\)Hi there!\fbox{Hi there!}Not supported\fbox{Hi there!}
\fcolorboxA\(\fcolorbox{red}{aqua}{A}\)A\fcolorbox{red}{aqua}{A}Not supported\fcolorbox{red}{aqua}{A}
\femaleNot supportedNot supportedNot supported\female
\fiNot supportedNot supportedNot supportedNot supported
\Finv\(\Finv\)\FinvNot supported
\flat\(\flat\)\flat\flat
\footnotesizefootnotesizeNot supportedfootnotesize\footnotesize footnotesizeNot supported\footnotesize footnotesize
\forall\(\forall\)\forall\forall
\fraca+bc+d\(\frac{a+b}{c+d}\)a+bc+d\frac{a+b}{c+d}a+bc+d\frac{a+b}{c+d}\frac{a+b}{c+d}
\frak𝔄𝔞𝔅𝔟\(\frak{AaBb}\)AaBb\frak{AaBb}Not supported\frak{AaBb}
\frown\(\frown\)\frown\frown
- -

G

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\Game\(\Game\)\GameNot supported
\GammaΓ\(\Gamma\)Γ\GammaΓ\Gamma
\gammaγ\(\gamma\)γ\gammaγ\gamma
{gather}a=be=b+c\(\begin{gather}a=b\\e=b+c\end{gather}\)a=be=b+c\begin{gather}a=b\\e=b+c\end{gather}Not supported\begin{gather}
   a=b \\
   e=b+c
\end{gather}
{gather*}a=be=b+c\(\begin{gather*}a=b\\e=b+c\end{gather*}\)a=be=b+c\begin{gather*}a=b\\e=b+c\end{gather*}Not supported\begin{gather*}
   a=b \\
   e=b+c
\end{gather*}
{gathered}a=be=b+c\(\begin{gathered}a=b\\e=b+c\end{gathered}\)a=be=b+c\begin{gathered}a=b\\e=b+c\end{gathered}a=be=b+c\begin{gathered}a=b\\e=b+c\end{gathered}\begin{gathered}
   a=b \\
   e=b+c
\end{gathered}
\gcdgcdxgcdyxgcdyx\(\begin{matrix}\gcd x \\ \gcd_y x \\\gcd\limits_y x\end{matrix}\)gcdxgcdyxgcdyx\begin{matrix}\gcd x \\ \gcd_y x \\\gcd\limits_y x\end{matrix}gcdxgcdyxgcdlimitsyx\begin{matrix}\gcd x \\ \gcd_y x \\\gcd\limits_y x\end{matrix}
\gdefNot supportedNot supportedy2+y2\gdef\bar#1{#1^2} \bar{y} + \bar{y}Not supported\gdef\bar#1{#1^2} \bar{y} + \bar{y}
\ge\(\ge\)\ge\ge
\geneuroNot supported\(\geneuro\)Not supportedNot supported
\geneuronarrowNot supported\(\geneuronarrow\)Not supportedNot supported
\geneurowideNot supported\(\geneurowide\)Not supportedNot supported
\genfrac(aa+1]\(\genfrac ( ] {2pt}{0}a{a+1}\)(aa+1]\genfrac ( ] {2pt}{0}a{a+1}Not supported\genfrac ( ] {2pt}{0}a{a+1}
\geq\(\geq\)\geq\geq
\geqq\(\geqq\)\geqq\geqq
\geqslant\(\geqslant\)\geqslant\geqslant
\gets\(\gets\)\getsNot supported
\gg\(\gg\)\gg\gg
\ggg\(\ggg\)\ggg\ggg
\gggtr\(\gggtr\)\gggtrNot supported
\gimel\(\gimel\)\gimel\gimel
\globalNot supported\(\global\def\add#1#2{#1+#2} \add 2 3\)2+3\global\def\add#1#2{#1+#2} \add 2 3Not supported\global\def\add#1#2{#1+#2} \add 2 3
\gnapprox\(\gnapprox\)\gnapprox\gnapprox
\gneq\(\gneq\)\gneq\gneq
\gneqq\(\gneqq\)\gneqq\gneqq
\gnsim\(\gnsim\)\gnsim\gnsim
\graveeu`\(\grave{eu}\)euˋ\grave{eu}Not supported\grave{eu}
\gta>b\(a \gt b\)a>ba \gt ba>ba \gt ba \gt b
\gtrdot\(\gtrdot\)\gtrdot\gtrdot
\gtrapprox\(\gtrapprox\)\gtrapprox\gtrapprox
\gtreqless\(\gtreqless\)\gtreqless\gtreqless
\gtreqqless\(\gtreqqless\)\gtreqqless\gtreqqless
\gtrless\(\gtrless\)\gtrless\gtrless
\gtrsim\(\gtrsim\)\gtrsim\gtrsim
\gvertneqq≩︀\(\gvertneqq\)\gvertneqq≩︀\gvertneqq
- -

H

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\Ha˝Not supporteda˝\text{\H{a}}Not supported\text{\H{a}}
\Harr\(\Harr\)\HarrNot supported
\hArrNot supported\hArrNot supported
\harr\(\harr\)\harrNot supported
\hatθ^\(\hat{\theta}\)θ^\hat{\theta}θ^\hat{\theta}\hat{\theta}
\hbar\(\hbar\)\hbar\hbar
\hboxin a box\(\hbox{in a box}\)in a box\hbox{in a box}Not supported\hbox{in a box}
\hdashlineabcd\(\begin{matrix}a&b\\ \hdashline c &d\end{matrix}\)abcd\begin{matrix}a&b\\ \hdashline c &d\end{matrix}Not supported\begin{matrix}
   a & b \\
   \hdashline
   c & d
\end{matrix}
\hearts\(\hearts\)\heartsNot supported
\heartsuit\(\heartsuit\)\heartsuit\heartsuit
\hfilNot supportedSee \hfillNot supportedNot supported
\hfillNot supported\(\begin{matrix}xxxxxx & xxxxxx & xxxxxx \\ ab & \hfil ab & ab\hfil\\ \end{matrix}\)Not supportedNot supported
\hlineabcd\(\begin{matrix}a&b\\ \hline c &d\end{matrix}\)abcd\begin{matrix}a&b\\ \hline c &d\end{matrix}Not supported\begin{matrix}
   a & b \\ \hline
   c & d
\end{matrix}
\homhomx\(\hom x\)homx\hom xhomx\hom x
\hookleftarrow\(\hookleftarrow\)\hookleftarrow\hookleftarrow
\hookrightarrow\(\hookrightarrow\)\hookrightarrow\hookrightarrow
\hphantomabcd\(a\hphantom{bc}d\)abcda\hphantom{bc}dNot supporteda\hphantom{bc}d
\hrefMathJax\(\href{https://MathJax.org/}{\text{MathJax}}\)MathJax\href{https://MathJax.org/}{\text{MathJax}}Not supported\href{https://www.mathjax.org/}{\text{MathJax}}
\hskipwid\(w\hskip1em i\hskip2em d\)widw\hskip1em i\hskip2em dNot supportedw\hskip1em i\hskip2em d
\hslash\(\hslash\)\hslash\hslash
\hspaceNot supported\(s\hspace7ex k\)sks\hspace7ex kNot supporteds\hspace7ex k
\htmlClassNot supportedNot supportedNot supportedNot supported\htmlClass{foo}{x}
\htmlDataNot supportedNot supportedNot supportedNot supported\htmlData{foo=a, bar=b}{x}
\htmlIdNot supportedNot supportedNot supportedNot supported\htmlId{bar}{x}
\htmlStyleNot supportedNot supportedNot supportedNot supported\htmlStyle{color: red;}{x}}
\hugehuge\(\huge huge\)huge\huge hugeNot supported\huge huge
\HugeHuge\(\Huge Huge\)Huge\Huge HugeNot supported\Huge Huge
- -

I

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\iıNot supportedı\text{\i}Not supported\text{\i}
\idotsintNot supportedNot supportedNot supported
\iddotsNot supportedNot supportedNot supportedNot supported
\ifNot supportedNot supportedNot supportedNot supported
\iffAB\(A\iff B\)A    BA\iff BABA\iff BA\iff B
\ifmodeNot supportedNot supportedNot supportedNot supported
\ifxNot supportedNot supportedNot supportedNot supported
\iiiintNot supportedNot supportedNot supportedNot supported
\iiint0nx0nx\(\iiint_0^n x \; \displaystyle \iiint_0^n x\)0nx  0nx\iiint_0^n x \; \displaystyle \iiint_0^n x\iiint
\iint0nx0nx\(\iint_0^n x \; \displaystyle \iint_0^n x\)0nx  0nx\iint_0^n x \; \displaystyle \iint_0^n x\iint
\Im\(\Im\)\Im\Im
\image\(\image\)\imageNot supported
\imageofNot supported\imageofNot supported
\imathı\(\imath\)ı\imathı\imath
\impliedbyPQ\(P\impliedby Q\)P    QP\impliedby QPQP\impliedby QP\impliedby Q
\impliesPQ\(P\implies Q\)P    QP\implies QPQP\implies QP\implies Q
\in\(\in\)\in\in
\includegraphicsKA logoNot supported\includegraphics[height=0.8em, totalheight=0.9em, width=0.9em, alt=KA logo]{https://cdn.kastatic.org/images/apple-touch-icon-57x57-precomposed.new.png}Not supported
\incohNot supportedNot supportedNot supported
\infinfxinfyxinfyx\(\begin{matrix}\inf x \\ \inf_y x \\\inf\limits_y x\end{matrix}\)infxinfyxinfyx\begin{matrix}\inf x \\ \inf_y x \\\inf\limits_y x\end{matrix}inf\inf
\infin\(\infin\)\infinNot supported
\infty\(\infty\)\infty\infty
\injliminjlimxinjlimyxinjlimyx\(\begin{matrix}\injlim x \\ \injlim_y x \\\injlim\limits_y x\end{matrix}\)inj limxinj limyxinj limyx\begin{matrix}\injlim x \\ \injlim_y x \\\injlim\limits_y x\end{matrix}Not supported\injlim x
\injlim_y x
\injlim\limits_y x
\int0nx0nx\(\int_0^n x \; \displaystyle \int_0^n x\)0nx  0nx\int_0^n x \; \displaystyle \int_0^n x\int
\intercal\(\intercal\)\intercal\intercal
\intop0nx0nx\(\intop_0^n x \; \displaystyle \intop_0^n x\)0nx  0nx\intop_0^n x \; \displaystyle \intop_0^n xNot supported
\invampNot supportedNot supportedNot supported
\IotaΙ\(\Iota\)I\IotaΙ\Iota
\iotaι\(\iota\)ι\iotaι\iota
\isin\(\isin\)\isinNot supported
\itAaBb\({\it AaBb}\)AaBb{\it AaBb}Not supported{\it AaBb}
- -

JK

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\jȷNot supportedȷ\text{\j}Not supported\text{\j}
\jmathȷ\(\jmath\)ȷ\jmathȷ\jmath
\Join\(\Join\)\JoinNot supported
\KappaΚ\(\Kappa\)K\KappaΚ\Kappa
\kappaκ\(\kappa\)κ\kappaκ\kappa
\kerkerx\(\ker x\)kerx\ker xkerx\ker x
\kernIR\(I\kern-2.5pt R\)IRI\kern-2.5pt RNot supportedI\kern-2.5pt R
\Ket|ψRequires extensionψ\Ket{\psi}Not supported\Ket{\psi}
\ket|ψRequires extensionψ\ket{\psi}Not supported\ket{\psi}
\KoppaϞNot supportedNot supportedNot supported
\koppaϟNot supportedNot supportedNot supported
- -

L

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\LNot supportedNot supportedNot supportedNot supported
\lNot supportedNot supportedNot supportedNot supported
\LambdaΛ\(\Lambda\)Λ\LambdaΛ\Lambda
\lambdaλ\(\lambda\)λ\lambdaλ\lambda
\labelSee {equation}SupportedNot supported
\land\(\land\)\landNot supported
\langA\(\lang A\rangle\)A\lang A\rangleA\lang A\rangle\lang A\rangle
\langleA\(\langle A\rangle\)A\langle A\rangleA\langle A\rangle\langle A\rangle
\Larr\(\Larr\)\LarrNot supported
\lArr\(\lArr\)\lArrNot supported
\larr\(\larr\)\larrNot supported
\largelarge\(\large large\)large\large largeNot supported\large large
\LargeLarge\(\Large Large\)Large\Large LargeNot supported\Large Large
\LARGELARGE\(\LARGE LARGE\)LARGE\LARGE LARGENot supported\LARGE LARGE
\LaTeXLATEX\(\LaTeX\)LaTeX\LaTeXNot supported
\lBraceNot supported\lBraceNot supported
\lbrace{\(\lbrace\){\lbrace{\lbrace
\lbrack[\(\lbrack\)[\lbrack[\lbrack
\lceil\(\lceil\)\lceil\lceil
\lcroofNot supportedNot supportedNot supportedNot supportedSee \enclose
\ldotp.\(\ldotp\).\ldotpNot supported
\ldots\(\ldots\)\ldots\ldots
\le\(\le\)\le\le
\leadsto\(\leadsto\)\leadstoNot supported
\left{ab\(\left\lbrace \frac ab \right.\){ab\left\lbrace \frac ab \right.{ab\left\lbrace \frac ab \right.\left\lbrace \frac ab \right.
\leftarrow\(\leftarrow\)\leftarrow\leftarrow
\Leftarrow\(\Leftarrow\)\Leftarrow\Leftarrow
\leftarrowtail\(\leftarrowtail\)\leftarrowtail\leftarrowtail
\leftharpoondown\(\leftharpoondown\)\leftharpoondown\leftharpoondown
\leftharpoonup\(\leftharpoonup\)\leftharpoonup\leftharpoonup
\leftleftarrows\(\leftleftarrows\)\leftleftarrows\leftleftarrows
\Leftrightarrow\(\Leftrightarrow\)\Leftrightarrow\Leftrightarrow
\leftrightarrow\(\leftrightarrow\)\leftrightarrow\leftrightarrow
\leftrightarrows\(\leftrightarrows\)\leftrightarrows\leftrightarrows
\leftrightharpoons\(\leftrightharpoons\)\leftrightharpoons\leftrightharpoons
\leftrightsquigarrow\(\leftrightsquigarrow\)\leftrightsquigarrow\leftrightsquigarrow
\leftrootNot supported\(\sqrt[3\leftroot1]{x}\)Not supportedNot supported
\leftthreetimes\(\leftthreetimes\)\leftthreetimes\leftthreetimes
\leq\(\leq\)\leq\leq
\leqalignnoNot supportedNot supportedNot supported
\leqq\(\leqq\)\leqq\leqq
\leqslant\(\leqslant\)\leqslant\leqslant
\lessapprox\(\lessapprox\)\lessapprox\lessapprox
\lessdot\(\lessdot\)\lessdot\lessdot
\lesseqgtr\(\lesseqgtr\)\lesseqgtr\lesseqgtr
\lesseqqgtr\(\lesseqqgtr\)\lesseqqgtr\lesseqqgtr
\lessgtr\(\lessgtr\)\lessgtr\lessgtr
\lesssim\(\lesssim\)\lesssim\lesssim
\letNot supportedNot supportedNot supported
\lfloor\(\lfloor\)\lfloor\lfloor
\lglg\(\lg\)lg\lglg\lg
\lgroup\(\lgroup\)\lgroupNot supported
\lhd\(\lhd\)\lhd\lhd
\limlimxlimyxlimyx\(\begin{matrix}\lim x \\ \lim_y x \\\lim\limits_y x\end{matrix}\)limxlimyxlimyx\begin{matrix}\lim x \\ \lim_y x \\\lim\limits_y x\end{matrix}limyx\lim_y x\lim x
\lim_y x
\lim\limits_y x
\liminfliminfxliminfyxliminfyx\(\begin{matrix}\liminf x \\ \liminf_y x \\\liminf\limits_y x\end{matrix}\)lim infxlim infyxlim infyx\begin{matrix}\liminf x \\ \liminf_y x \\\liminf\limits_y x\end{matrix}liminf\liminf
\limitslimx\(\lim\limits_x\)limx\lim\limits_xNot supported\lim\limits_x
\limsuplimsupxlimsupyxlimsupyx\(\begin{matrix}\limsup x \\ \limsup_y x \\\limsup\limits_y x\end{matrix}\)lim supxlim supyxlim supyx\begin{matrix}\limsup x \\ \limsup_y x \\\limsup\limits_y x\end{matrix}limsup\limsup
\ll\(\ll\)\ll\ll
\llap=\({=}\llap{/\,}\)=/{=}\llap{/\,}Not supported{=}\llap{/\,}
\llbracketNot supported\llbracketNot supported
\llcornera\(\llcorner a \lrcorner\)a\llcorner a \lrcornerNot supported
\Lleftarrow\(\Lleftarrow\)\Lleftarrow\Lleftarrow
\lll\(\lll\)\lll\lll
\llless\(\llless\)\lllessNot supported
\lmoustache\(\lmoustache\)\lmoustache\lmoustache
\lnlnx\(\ln x\)lnx\ln xlnx\ln x
\lnapprox\(\lnapprox\)\lnapprox\lnapprox
\lneq\(\lneq\)\lneq\lneq
\lneqq\(\lneqq\)\lneqq\lneqq
\longdiv45.2Not supported
See \enclose
Not supportedNot supported\longdiv{45.2}
\lnot¬\(\lnot\)¬\lnotNot supported
\lnsim\(\lnsim\)\lnsim\lnsim
\loglogxlogyxlogyx\(\begin{matrix}\log x \\ \log_y x \\ \log\limits_y x\end{matrix}\)logxlogyxlogyx\begin{matrix}\log x \\ \log_y x \\ \log\limits_y x\end{matrix}logxlogyxloglimitsyx\begin{matrix}\log x \\ \log_y x \\ \log\limits_y x\end{matrix}\log x
\log_y x
\log\limits_y x
\Longleftarrow\(\Longleftarrow\)\Longleftarrow\Longleftarrow
\longleftarrow\(\longleftarrow\)\longleftarrow\longleftarrow
\Longleftrightarrow\(\Longleftrightarrow\)\Longleftrightarrow\Longleftrightarrow
\longleftrightarrow\(\longleftrightarrow\)\longleftrightarrow\longleftrightarrow
\longmapsto\(\longmapsto\)\longmapsto\longmapsto
\Longrightarrow\(\Longrightarrow\)\Longrightarrow\Longrightarrow
\longrightarrow\(\longrightarrow\)\longrightarrow\longrightarrow
\looparrowleft\(\looparrowleft\)\looparrowleft\looparrowleft
\looparrowright\(\looparrowright\)\looparrowright\looparrowright
\lor\(\lor\)\lorNot supported
\lowerlower\(l\lower 2pt{owe}r\)Not supportedNot supportedl\lower 2pt{owe}r
\lozenge\(\lozenge\)\lozenge\lozenge
\lparen(Not supported(\lparenNot supported
\Lrarr\(\Lrarr\)\LrarrNot supported
\lrArr\(\lrArr\)\lrArrNot supported
\lrarr\(\lrarr\)\lrarrNot supported
\lrcorner\(\lrcorner\)\lrcornerNot supported
\lqNot supported\lqNot supported
\Lsh\(\Lsh\)\Lsh\Lsh
\lt<\(\lt\)<\lt<\lt
\ltimes\(\ltimes\)\ltimes\ltimes
\lVert\(\lVert\)\lVertNot supported
\lvert|\(\lvert\)\lvertNot supported
\lvertneqq≨︀\(\lvertneqq\)\lvertneqq≨︀\lvertneqq
- -

M

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\maleNot supportedNot supportedNot supported\male
\maltese\(\maltese\)\malteseNot supported
\mapsto\(\mapsto\)\mapsto\mapsto
\mathbb𝔸𝔹\(\mathbb{AB}\)AB\mathbb{AB}𝔸𝔹\mathbb{AB}\mathbb{AB}
\mathbf𝐀𝐚𝐁𝐛𝟏𝟐𝟑\(\mathbf{AaBb123}\)AaBb123\mathbf{AaBb123}𝐀𝐚𝐁𝐛𝟏𝟐𝟑\mathbf{AaBb123}\mathbf{AaBb123}
\mathbina!b\(a\mathbin{!}b\)a!ba\mathbin{!}ba!ba\mathbin{!}ba\mathbin{!}b
\mathcal𝒜𝒶𝒷123\(\mathcal{AaBb123}\)AaBb123\mathcal{AaBb123}𝒜𝒶𝒷123\mathcal{AaBb123}\mathcal{AaBb123}
\mathchoiceab\(a\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b\)aba\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}bNot supporteda\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b
\mathclap1inxiNot supported1inxi\displaystyle\sum_{\mathclap{1\le i\le n}} x_{i}1inxi\displaystyle\sum_{\mathclap{1\le i\le n}} x_{i}\sum_{\mathclap{1\le i\le n}} x_{i}
\mathclosea+(b>+c\(a + (b\mathclose\gt + c\)a+(b>+ca + (b\mathclose\gt + cNot supporteda + (b\mathclose\gt + c
\mathellipsisNot supported\mathellipsisNot supported
\mathfrak𝔄𝔞𝔅𝔟\(\mathfrak{AaBb}\)AaBb\mathfrak{AaBb}𝔄𝔞𝔅𝔟\mathfrak{AaBb}\mathfrak{AaBb}
\mathinnerabinsidecd\(ab\mathinner{\text{inside}}cd\)abinsidecdab\mathinner{\text{inside}}cdNot supportedab\mathinner{\text{inside}}cd
\mathitAaBb\(\mathit{AaBb}\)AaBb\mathit{AaBb}𝐴𝑎𝐵𝑏\mathit{AaBb}\mathit{AaBb}
\mathllap=Not supported/={\mathrlap{\,/}{=}}/={\mathrlap{\,/}{=}}\mathrlap{\,/}{=}
\mathnormalAaBbθNot supportedAaBbθ\mathnormal{AaBb\theta}Not supported\mathnormal{AaBb\theta}
\mathopaxb\(a \mathop{x} b\)axba \mathop{x} baxba \mathop{x} ba \mathop{x} b
\mathopena+<b)+c\(a + \mathopen\lt b) + c\)a+<b)+ca + \mathopen\lt b) + cNot supporteda + \mathopen\lt b) + c
\mathord1,234,567\(1\mathord{,}234{,}567\)1,234,5671\mathord{,}234{,}567Not supported1\mathord{,}234{,}567
\mathpunctAB\(A\mathpunct{-}B\)ABA\mathpunct{-}BNot supportedA\mathpunct{-}B
\mathraiseboxNot supportedNot supportedNot supportedhigherh\mathraisebox{2pt}{ighe}r
\mathrela#b\(a \mathrel{\#} b\)a#ba \mathrel{\#} ba#ba \mathrel{#} ba \mathrel{\#} b
\mathrlap02πxdxNot supported02πxdx{\displaystyle \int_0^{\mathrlap{2\pi}} x \,\mathrm{d} x}02πxdx{\displaystyle \int_0^{\mathrlap{2\pi}} x \,\mathrm{d} x}\int_0^{\mathrlap{2\pi}} x\,\mathrm{d} x
\mathringa˚\(\mathring{a}\)a˚\mathring{a}Not supported\mathring{a}
\mathrmAaBb12θ\(\mathrm{AaBb12\theta}\)AaBb12θ\mathrm{AaBb12\theta}AaBb12θ\mathrm{AaBb12\theta}\mathrm{AaBb12\theta}
\mathscr𝒜\(\mathscr{AB}\)AB\mathscr{AB}𝒜\mathscr{AB}\mathscr{AaBb123}
\mathsf𝖠𝖺𝖡𝖻𝟣𝟤𝟥\(\mathsf{AaBb123}\)AaBb123\mathsf{AaBb123}𝖠𝖺𝖡𝖻𝟣𝟤𝟥\mathsf{AaBb123}\mathsf{AaBb123}
\mathsterling£Not supported£\mathsterlingNot supported
\mathstrut(α\(\sqrt{\mathstrut\alpha}\)(α\sqrt{\mathstrut\alpha}Not supported\sqrt{\mathstrut\alpha}
\mathtipa=bNot supportedNot supportedNot supported\mathtip{a=b}{tip}s
\mathtt𝙰𝚊𝙱𝚋𝟷𝟸𝟹\(\mathtt{AaBb123}\)AaBb123\mathtt{AaBb123}𝙰𝚊𝙱𝚋𝟷𝟸𝟹\mathtt{AaBb123}\mathtt{AaBb123}
\matrixNot supported\(\matrix{a & b \\ c & d}\)Not supportedNot supported\matrix{a & b \\ c & d}
{matrix}ABbABd\(\begin{matrix}\frac A B&b\\\frac A B&d\end{matrix}\)ABbABd\begin{matrix}\frac A B&b\\\frac A B&d\end{matrix}ABbABd\begin{matrix}\frac A B&b\\\frac A B&d\end{matrix}\begin{matrix}
   \frac A B & b \\
   \frac A B & d
\end{matrix}
\maxmaxxmaxyxmaxyx\(\begin{matrix}\max x \\ \max_y x \\\max\limits_y x\end{matrix}\)maxxmaxyxmaxyx\begin{matrix}\max x \\ \max_y x \\\max\limits_y x\end{matrix}max\max
\mboxNot supported\(\mbox{in a box}\)Not supportedNot supported\mbox{in a box}
\measuredangle\(\measuredangle\)\measuredangle\measuredangle
\medspaceabNot supportedaba\medspace baba\medspace ba\medspace b
\mho\(\mho\)\mho\mho
\mid{x|x>0}\(\{x∈ℝ\mid x>0\}\){xRx>0}\{x∈ℝ\mid x > 0\}{xx>0}\{x∈ℝ\mid x>0\}\{x∈ℝ\mid x>0\}
\middleP(A|B)\(P\left(A\middle\vert B\right)\)P(A|B)P\left(A\middle\vert B\right)Not supportedP\left(A\middle\vert B\right)
\minminxminyxminyx\(\begin{matrix}\min x \\ \min_y x \\\min\limits_y x\end{matrix}\)minxminyxminyx\begin{matrix}\min x \\ \min_y x \\\min\limits_y x\end{matrix}min\min
\minusoNot supported
See \standardstate
Not supported\minusoNot supported
\mitNot supported\(\mit{\Gamma\Theta}\)Not supportedNot supported\mit{\Gamma\Theta}
\mkernab\(a\mkern18mu b\)aba\mkern18mu bNot supporteda\mkern18mu b
\mmlToken?Not supportedNot supportedNot supported
\mod35mod2\(3\equiv 5 \mod 2\)35mod23\equiv 5 \mod 2Not supported3\equiv 5 \mod 2
\models\(\models\)\models\models
\moveleftNot supported\(O\moveleft3pt O\)Not supportedNot supportedO\moveleft3pt O
\moverightNot supported\(O\moveright3pt O\)Not supportedNot supportedO\moveright3pt O
\mp\(\mp\)\mp\mp
\mskipab\(a\mskip{10mu}b\)aba\mskip{10mu}bNot supporteda\mskip{10mu}b
\mspaceNot supported\(a\mspace18mu b\)Not supportedNot supporteda\mspace18mu b
\MuΜ\(\Mu\)M\MuΜ\Mu
\muμ\(\mu\)μ\muμ\mu
\multicolumnNot supportedNot supportedNot supportedNot supported
{multline}first linesecond linethird line\[\begin{multline} - \rm first\ line \\ - \rm second\ line \\ - \rm third\ line - \end{multline}\]Not supportedNot supported
{multline*}first linesecond linethird line\[\begin{multline*} - \rm first\ line \\ - \rm second\ line \\ - \rm third\ line - \end{multline*}\]Not supportedNot supported
\multimap\(\multimap\)\multimap\multimap
\multimapbothNot supportedNot supportedNot supported
\multimapinvNot supportedNot supportedNot supported
- -

N

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\N\(\N\)N\NNot supported
\nabla\(\nabla\)\nabla\nabla
\natnums\(\natnums\)N\natnumsNot supported
\natural\(\natural\)\natural\natural
\negmedspaceab\(a\negmedspace b\)a ⁣ba\negmedspace baba\negmedspace ba\negmedspace b
\ncong\(\ncong\)\ncong\ncong
\ne\(\ne\)\ne\ne
\nearrow\(\nearrow\)\nearrow\nearrow
\neg¬\(\neg\)¬\neg¬\neg
\negthickspaceab\(a\negthickspace b\)a ⁣ba\negthickspace bNot supporteda\negthickspace b
\negthinspaceab\(a\negthinspace b\)a ⁣ba\negthinspace bNot supporteda\negthinspace b
\neq\(\neq\)\neq\neq
\newcommand\(\newcommand\chk{\checkmark} \chk\)\newcommand\chk{\checkmark} \chkNot supported\newcommand\chk{\checkmark} \chk
\newenvironmentNot supported\(\newenvironment{tinyit}{\tiny\it}{\normalsize\rm}\begin{tinyit}Really small.\end{tinyit}\)Not supportedNot supported\newenvironment{tinyit}{\tiny\it}{\normalsize\rm}
\begin{tinyit}Really small.\end{tinyit}
\NewextarrowNot supported\(\Newextarrow{\xrightharpoonup}{5,10}{0x21C0} A \xrightharpoonup{\text{note}} B\)Not supportedNot supported\Newextarrow{\xrightharpoonup}{5,10}{0x21C0}
A \xrightharpoonup{\text{note}} B
\newextarrowNot supported<Not supportedNot supportedNot supportedSpelling per LaTeX.
\newlineabNot supportedaba\newline bNot supporteda\newline b
\nexists\(\nexists\)\nexists\nexists
\ngeq\(\ngeq\)\ngeq\ngeq
\ngeqq\(\ngeqq\)\ngeqq⩾̸\ngeqq
\ngeqslant\(\ngeqslant\)\ngeqslant⩾̸\ngeqslant
\ngtr\(\ngtr\)\ngtr\ngtr
\ni\(\ni\)\ni\ni
\nleftarrow\(\nleftarrow\)\nleftarrow\nleftarrow
\nLeftarrow\(\nLeftarrow\)\nLeftarrow\nLeftarrow
\nLeftrightarrow\(\nLeftrightarrow\)\nLeftrightarrow\nLeftrightarrow
\nleftrightarrow\(\nleftrightarrow\)\nleftrightarrow\nleftrightarrow
\nleq\(\nleq\)\nleq\nleq
\nleqq\(\nleqq\)\nleqq⩽̸\nleqq
\nleqslant\(\nleqslant\)\nleqslant⩽̸\nleqslant
\nless\(\nless\)\nless\nless
\nmid\(\nmid\)\nmid\nmid
\nobreakNot supportedNot supportedNot supportedNot supported
\nobreakspacea b\(a\nobreakspace b\)a ba\nobreakspace bNot supporteda\nobreakspace b
\nolimitslimx\(\lim\nolimits_x\)limx\lim\nolimits_xNot supported\lim\nolimits_x
\normalsizenormalsize\(\normalsize normalsize\)normalsize\normalsize normalsizeNot supported\normalsize normalsize
\not\(\not =\)\not =¬=\not =\not =
\notagNot supportedNot supportedNot supported
\notin\(\notin\)\notin\notin
\notniNot supported\notni\notni
\nparallel\(\nparallel\)\nparallel\nparallel
\nprec\(\nprec\)\nprec\nprec
\npreceq\(\npreceq\)\npreceq⪯̸\npreceq
\nRightarrow\(\nRightarrow\)\nRightarrow\nRightarrow
\nrightarrow\(\nrightarrow\)\nrightarrow\nrightarrow
\nshortmid\(\nshortmid\)\nshortmid\nshortmid
\nshortparallel\(\nshortparallel\)\nshortparallel\nshortparallel
\nsim\(\nsim\)\nsim\nsim
\nsubsetNot supportedNot supported\nsubset
\nsubseteq\(\nsubseteq\)\nsubseteq\nsubseteq
\nsubseteqq\(\nsubseteqq\)\nsubseteqq\nsubseteqq
\nsucc\(\nsucc\)\nsucc\nsucc
\nsucceq\(\nsucceq\)\nsucceq⪰̸\nsucceq
\nsupsetNot supportedNot supported\nsupset
\nsupseteq\(\nsupseteq\)\nsupseteq\nsupseteq
\nsupseteqq\(\nsupseteqq\)\nsupseteqqNot supported
\ntriangleleft\(\ntriangleleft\)\ntriangleleft\ntriangleleft
\ntrianglelefteq\(\ntrianglelefteq\)\ntrianglelefteq\ntrianglelefteq
\ntriangleright\(\ntriangleright\)\ntriangleright\ntriangleright
\ntrianglerighteq\(\ntrianglerighteq\)\ntrianglerighteq\ntrianglerighteq
\NuΝ\(\Nu\)N\NuΝ\Nu
\nuν\(\nu\)ν\nuν\nu
\nVDash\(\nVDash\)\nVDash\nVDash
\nVdash\(\nVdash\)\nVdash\nVdash
\nvDash\(\nvDash\)\nvDash\nvDash
\nvdash\(\nvdash\)\nvdash\nvdash
\nwarrow\(\nwarrow\)\nwarrow\nwarrow
- -

O

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\OØNot supportedØ\text{\O}Not supported\text{\O}
\oøNot supportedø\text{\o}Not supported\text{\o}
\oc!Not supportedNot supportedNot supported
\odvdfdxNot supportedNot supportedNot supported\odv{f}{x}
\odv*`ddxfNot supportedNot supportedNot supported\odv*{f}{x}
\odot\(\odot\)\odot\odot
\OEŒNot supportedŒ\text{\OE}Not supported\text{\OE}
\oeœNot supportedœ\text{\oe}Not supported\text{\oe}
\officialeuroNot supported
See \euro
\(\officialeuro\)Not supportedNot supported
\oiiint0nx0nx\(\oiiint_0^n x \; \displaystyle \oiiint_0^n x\)0nx  0nx\oiiint_0^n x \; \displaystyle \oiiint_0^n x\oiiint
\oiint0nx0nx\(\oiint_0^n x \; \displaystyle \oiint_0^n x\)0nx  0nx\oiint_0^n x \; \displaystyle \oiint_0^n x\oiint
\oint0nx0nx\(\oint_0^n x \; \displaystyle \oint_0^n x\)0nx  0nx\oint_0^n x \; \displaystyle \oint_0^n x\oint
\oldstyleNot supported
See \oldstylenums
\(\oldstyle 0123456\)Not supportedNot supported\oldstyle 0123456
\oldstylenums123Not supportedNot supportedNot supported\oldstylenums{123}
\omegaω\(\omega\)ω\omegaω\omega
\OmegaΩ\(\Omega\)Ω\OmegaΩ\Omega
\OmicronΟ\(\Omicron\)O\OmicronNot supported
\omicronο\(\omicron\)ο\omicron\omicron
\ominus\(\ominus\)\ominus\ominus
\operatornameasinx\(\operatorname{asin} x\)asinx\operatorname{asin} xasinx\operatorname{asin} x\operatorname{asin} x
\operatorname*asinxasinyxasinyx\(\begin{matrix}\operatorname*{asin} x \\ \operatorname*{asin}_y x \\ \operatorname*{asin}\limits_y x\end{matrix}\)asinxasinyxasinyx\begin{matrix}\operatorname*{asin} x \\ \operatorname*{asin}_y x \\ \operatorname*{asin}\limits_y x\end{matrix}Not supported\operatorname*{asin} x
\operatorname*{asin}_y x
\operatorname*{asin}\limits_y x\end
\oplus\(\oplus\)\oplus\oplus
\orNot supportedNot supportedNot supportedNot supported
\origofNot supported\origofNot supported
\oslash\(\oslash\)\oslash\oslash
\otimes\(\otimes\)\otimes\otimes
\overa+1b+2+c\({a+1 \over b+2}+c\)a+1b+2+c{a+1 \over b+2}+ca+1b+2+c{a+1 \over b+2}+c{a+1 \over b+2}+c
\overbracex++xn times\(\overbrace{x+⋯+x}^{n\text{ times}}\)x++xn times\overbrace{x+⋯+x}^{n\text{ times}}x++xn times\overbrace{x+⋯+x}^{n\text{ times}}\overbrace{x+⋯+x}^{n\text{ times}}
\overbracketNot supportedNot supportedNot supportedNot supported
\overgroupABNot supportedAB\overgroup{AB}Not supported\overgroup{AB}
\overleftarrowAB\(\overleftarrow{AB}\)AB\overleftarrow{AB}Not supported\overleftarrow{AB}
\overleftharpoonABNot supportedAB\overleftharpoon{AB}Not supported\overleftharpoon{AB}
\overleftrightarrowAB\(\overleftrightarrow{AB}\)AB\overleftrightarrow{AB}Not supported\overleftrightarrow{AB}
\overlinea long argument_\(\overline{\text{a long argument}}\)a long argument\overline{\text{a long argument}}a long argument¯\overline{\text{a long argument}}\overline{\text{a long argument}}
\overlinesegmentNot supportedNot supportedNot supportedNot supported
\overparenAB\(\overparen{AB}\)Not supportedNot supportedSee \overgroup
\OverrightarrowABNot supportedAB\Overrightarrow{AB}Not supported\Overrightarrow{AB}
\overrightarrowAB\(\overrightarrow{AB}\)AB\overrightarrow{AB}Not supported\overrightarrow{AB}
\overrightharpoonacNot supportedac\overrightharpoon{ac}Not supported\overrightharpoon{ac}
\overset=!\(\overset{!}{=}\)=!\overset{!}{=}=!\overset{!}{=}\overset{!}{=}
\overwithdelimsNot supported\(a \overwithdelims [ ] b\)Not supportedNot supported
\owns\(\owns\)\ownsNot supported
- -

P

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\PNot supported\text{\P}Not supported\text{\P}
\pagecolor?Not supportedNot supportedNot supportedDeprecated
\parallel\(\parallel\)\parallel\parallel
\parrNot supportedNot supportedNot supported
\part??Not supportedNot supportedNot supportedDeprecated
\partial\(\partial\)\partial\partial
\permilNot supportedNot supportedNot supported
\pdv2fxyNot supportedNot supportedNot supported\pdv{f}{x,y}
\pdv*2xyfNot supportedNot supportedNot supported\pdv*{f}{x,y}
\perp\(\perp\)\perp\perp
\phantomΓijkij\(\Gamma^{\phantom{i}j}_{i\phantom{j}k}\)Γijkij\Gamma^{\phantom{i}j}_{i\phantom{j}k}Γijkij\Gamma^{\phantom{i}j}_{i\phantom{j}k}\Gamma^{\phantom{i}j}_{i\phantom{j}k}
\phase120V78.2°Not supported
See \enclose
120V78.2°120\text{V}\phase{78.2\degree}Not supported120\text{V}\phase{78.2\degree}
\PhiΦ\(\Phi\)Φ\PhiΦ\Phi
\phiϕ\(\phi\)ϕ\phiϕ\phi
\PiΠ\(\Pi\)Π\PiΠ\Pi
\piπ\(\pi\)π\piπ\pi
{picture}Not supportedNot supportedNot supportedNot supported
\pitchfork\(\pitchfork\)\pitchfork\pitchfork
\plimplimNot supportedplim\plimNot supported
\plusmn±\(\plusmn\)±\plusmnNot supported
\pm±\(\pm\)±\pm±\pm
\pmatrixNot supported\(\pmatrix{a&b\\c&d}\)Not supportedNot supportedSee {pmatrix}
{pmatrix}(abcd)\(\begin{pmatrix}a&b\\c&d\end{pmatrix}\)(abcd)\begin{pmatrix}a&b\\c&d\end{pmatrix}(abcd)\begin{pmatrix}a&b\\c&d\end{pmatrix}\begin{pmatrix}
   a & b \\
   c & d
\end{pmatrix}
\pmbμ\(\pmb{\mu}\)μ\pmb{\mu}Not supported\pmb{\mu}
\pmodx(moda)\(x\pmod a\)x(moda)x\pmod aNot supportedx\pmod a
\podx(a)\(x \pod a\)x(a)x \pod aNot supportedx \pod a
\pounds£Not supported£\poundsNot supported
\PrPrxPryxPryx\(\begin{matrix}\Pr x \\ \Pr_y x \\\Pr\limits_y x\end{matrix}\)PrxPryxPryx\begin{matrix}\Pr x \\ \Pr_y x \\\Pr\limits_y x\end{matrix}Pr\Pr
\prec\(\prec\)\prec\prec
\precapprox\(\precapprox\)\precapprox\precapprox
\preccurlyeq\(\preccurlyeq\)\preccurlyeq\preccurlyeq
\preceq\(\preceq\)\preceq\preceq
\precnapprox\(\precnapprox\)\precnapprox\precnapprox
\precneqq\(\precneqq\)\precneqq\precneqq
\precnsim\(\precnsim\)\precnsim\precnsim
\precsim\(\precsim\)\precsim\precsim
\prescript𝐂25+a2Not supportedNot supportedNot supported\prescript{a}{2}{\mathbf{C}}^{5+}_{2}
\prime\(\prime\)\primeNot supported
\prod0nx0nx\(\prod_0^n x \; \displaystyle \prod_0^n x\)0nx  0nx\prod_0^n x \; \displaystyle \prod_0^n x\prod
\projlimprojlimnx\(\projlim_n x\)proj limnx\projlim_n xNot supported\projlim_n x
\propto\(\propto\)\propto\propto
\providecommandHelloNot supportedHello\providecommand\greet{\text{Hello}} \greetNot supported\providecommand\greet{\text{Hello}} \greet
\psiψ\(\psi\)ψ\psiψ\psi
\PsiΨ\(\Psi\)Ψ\PsiΨ\Psi
\pu123 kJmol\({123~\mathchoice{\textstyle\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}}\)123 kJmol{123~\mathchoice{\textstyle\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}{\frac{\mathrm{kJ}}{\mathrm{mol}}}}Not supported\pu{123 kJ//mol}
- -

QR

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\QNot supported\(\Q\)Not supportedNot supportedSee \Bbb{Q}
\qquadab\(a\qquad\qquad{b}\)aba\qquad\qquad{b}aba\qquad\qquad{b}a\qquad\qquad{b}
\quadab\(a\quad\quad{b}\)aba\quad\quad{b}aba\quad\quad{b}a\quad\quad{b}
\R\(\R\)R\RNot supported
\ra˚\(\text{\r{a}}\)a˚\text{\r{a}}Not supported\text{\r{a}}
\raisehigher\(h\raise{2pt}{ighe}r\)Not supportedNot supportedh\raise{2pt}{ighe}r
\raiseboxhigherNot supportedhigherh\raisebox{2pt}{ighe}rNot supportedh\raisebox{2pt}{ighe}r
\rangA\(\langle A\rang\)A\langle A\rangA\langle A\rang\langle A\rang
\rangleA\(\langle A\rangle\)A\langle A\rangleA\langle A\rangle\langle A\rangle
\Rarr\(\Rarr\)\RarrNot supported
\rArr\(\rArr\)\rArrNot supported
\rarr\(\rarr\)\rarrNot supported
\rBraceNot supported\rBraceNot supported
\rbrace}\(\rbrace\)}\rbrace}\rbrace
\rbrack]\(\rbrack\)]\rbrack]\rbrack
{rcases}aif bcif d}Not supportedaif bcif d}\begin{rcases}a&\text{if }b\\c&\text{if }d\end{rcases}Not supported\begin{rcases}
   a&\text{if }b\\
   c&\text{if }d
\end{rcases}
\rceil\(\rceil\)\rceil\rceil
\Re\(\Re\)\Re\Re
\real\(\real\)\realNot supported
\Reals\(\Reals\)R\RealsNot supported
\reals\(\reals\)R\realsNot supported
\refSupportedNot supportedNot supported\ref{maxwell}
\relaxNot supportedNot supported
\renewcommandAhoy!\(\def\hail{Hi!}\renewcommand\hail{\text{Ahoy!}} \hail\)Ahoy!\def\hail{Hi!}\renewcommand\hail{\text{Ahoy!}} \hailNot supported\def\hail{Hi!}
\renewcommand\hail{\text{Ahoy!}}
\hail
\renewenvironmentNot supportedNot supportedNot supported
\requireNot supportedNot supportedNot supported
\restriction\(\restriction\)\restrictionNot supported
\rfloor\(\rfloor\)\rfloor\rfloor
\rgroup\(\rgroup\)\rgroupNot supported
\rhd\(\rhd\)\rhd\rhd
\RhoΡ\(\Rho\)P\RhoΡ\Rho
\rhoρ\(\rho\)ρ\rhoρ\rho
\rightab)\(\left.\frac a b\right)\)ab)\left.\frac a b\right)ab)\left.\frac a b\right)\left.\frac a b\right)
\Rightarrow\(\Rightarrow\)\Rightarrow\Rightarrow
\rightarrow\(\rightarrow\)\rightarrow\rightarrow
\rightarrowtail\(\rightarrowtail\)\rightarrowtail\rightarrowtail
\rightharpoondown\(\rightharpoondown\)\rightharpoondown\rightharpoondown
\rightharpoonup\(\rightharpoonup\)\rightharpoonup\rightharpoonup
\rightleftarrows\(\rightleftarrows\)\rightleftarrows\rightleftarrows
\rightleftharpoons\(\rightleftharpoons\)\rightleftharpoons\rightleftharpoons
\rightrightarrows\(\rightrightarrows\)\rightrightarrows\rightrightarrows
\rightsquigarrow\(\rightsquigarrow\)\rightsquigarrow\rightsquigarrow
\rightthreetimes\(\rightthreetimes\)\rightthreetimes\rightthreetimes
\risingdotseq\(\risingdotseq\)\risingdotseq\risingdotseq
\rlap=\(\rlap{\,/}{=}\)/=\rlap{\,/}{=}Not supported\rlap{\,/}{=}
\rmAaBb12θ\(\rm AaBb12\theta\)AaBb12θ\rm AaBb12\thetaNot supported\rm AaBb12\theta
\rmoustache\(\rmoustache\)\rmoustache\rmoustache
\rootNot supported\(\root 3 \of x\)Not supportedx3\root{3}{x}MathJax and TeXZilla differ in syntax:
\root 3 \of x vs. \root{3}{x}
\rotateboxNot supportedNot supportedNot supportedNot supported
\rparen)Not supported)\rparenNot supported
\rqNot supported\rqNot supported
\Rrightarrow\(\Rrightarrow\)\Rrightarrow\Rrightarrow
\rrbracketNot supported\rrbracketNot supported
\Rsh\(\Rsh\)\Rsh\Rsh
\rtimes\(\rtimes\)\rtimes\rtimes
\RuleNot supported\(x\Rule{3px}{0.5ex}{2ex}x\)Not supportedNot supportedNon-standard
\rulexx\(x\color{blue}\rule[6pt]{2ex}{1ex}x\)xxx\color{blue}\rule[6pt]{2ex}{1ex}xNot supportedx\color{blue}\rule[6pt]{2ex}{1ex}x
\rVert\(\rVert\)\rVertNot supported
\rvert|\(\rvert\)\rvertNot supported
- -

S

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\S§Not supported§\text{\S}Not supported\text{\S}
\SampiϠNot supportedNot supportedNot supported
\sampiϡNot supportedNot supportedNot supported
\scaleboxNot supportedNot supportedNot supportedNot supported
\scohNot supportedNot supportedNot supported
\scrNot supported\(\scr M\)Not supportedNot supported\scr M
\scriptscriptstylecd\(\scriptscriptstyle \frac cd\)cd\scriptscriptstyle \frac cdNot supported\scriptscriptstyle \frac cd
\scriptsizescriptsize\(\scriptsize scriptsize\)scriptsize\scriptsize scriptsizescriptsize\scriptsize scriptsize\scriptsize scriptsize
\scriptstyleab+cd\(\frac ab + {\scriptstyle \frac cd}\)ab+cd\frac ab + {\scriptstyle \frac cd}Not supported\frac ab + {\scriptstyle \frac cd}
\sdot\(\sdot\)\sdotNot supported
\searrow\(\searrow\)\searrow\searrow
\secsec\(\sec\)sec\secsec\sec
\sect§Not supported§\text{\sect}Not supported\text{\sect}
\set{x|x<5}Requires extensionNot supportedNot supported\Set{x|x<5}
\Set{x|x<12}Requires extensionNot supportedNot supported\Set{ x | x<\frac 1 2 }
\setlengthNot supportedNot supportedNot supportedNot supported
\setminus\(\setminus\)\setminus\setminus
\sf𝖠𝖺𝖡𝖻𝟣𝟤𝟥\(\sf AaBb123\)AaBb123\sf AaBb123Not supported\sf AaBb123
\sgnsgnNot supportedNot supportedNot supported
\sharp\(\sharp\)\sharp\sharp
\shiftNot supportedNot supportedNot supported
\shnegNot supportedNot supportedNot supported
\shortmid\(\shortmid\)\shortmid\shortmid
\shortparallel\(\shortparallel\)\shortparallel\shortparallel
\shoveleftNot supported\(\begin{multline*} -\rm first\ line \\ -\shoveleft{\rm 2nd} \\ -\rm third\ line -\end{multline*}\)Not supportedNot supported
\shoverightNot supported\(\begin{multline*} -\rm first\ line \\ -\shoveright{\rm 2nd} \\ -\rm third\ line -\end{multline*}\)Not supportedNot supported
\shposNot supportedNot supportedNot supported
\sideset3412Not supportedNot supportedNot supported
\SigmaΣ\(\Sigma\)Σ\SigmaΣ\Sigma
\sigmaσ\(\sigma\)σ\sigmaσ\sigma
\sim\(\sim\)\sim\sim
\simeq\(\simeq\)\simeq\simeq
\sinsinx\(\sin x\)sinx\sin xsinx\sin x
\sincohNot supportedNot supportedNot supported
\sinhsinhx\(\sinh x\)sinhx\sinh xsinhx\sinh x
\sixptsizesixptsizeNot supportedsixptsize\sixptsize sixptsizeNot supported\sixptsize sixptsize
\shshNot supportedsh\shNot supported
\skewNot supported\(\hat A\skew9\hat A\)Not supportedNot supported\hat A\skew9\hat A
\skipNot supportedNot supportedNot supportedNot supported
\smallsmall\(\small small\)small\small smallNot supported\small small
\smallfrown\(\smallfrown\)\smallfrown\smallfrown
\smallint0nx0nx0nx\(\smallint_0^n x \; \smallint\limits_0^n x \; \displaystyle \smallint_0^n x\)0nx  0nx  0nx\smallint_0^n x \; \smallint\limits_0^n x \; \displaystyle \smallint_0^n xNot supported - \smallint_0^n x
\smallint\limits_0^n x
\displaystyle \smallint_0^n x -
{smallmatrix}abcd\(\begin{smallmatrix}a & b\\c & d\end{smallmatrix}\)abcd\begin{smallmatrix}a & b\\c & d\end{smallmatrix}abcd\begin{smallmatrix}a & b\\c & d\end{smallmatrix}\begin{smallmatrix}a & b\\
c & d\end{smallmatrix}
\smallsetminus\(\smallsetminus\)\smallsetminus\smallsetminus
\smallsmile\(\smallsmile\)\smallsmile\smallsmile
\smash(x2)\(\left(x^{\smash{2}}\right)\)(x2)\left(x^{\smash{2}}\right)Not supported\left(x^{\smash{2}}\right)
\smile\(\smile\)\smile\smile
\smileyNot supportedNot supportedNot supportedwasysym
\soutabcNot supportedabc\sout{abc}Not supported\sout{abc}
\SpaceNot supported\(a\Space{5px}{4ex}{2ex}^b_c d\)Not supportedNot supporteda\Space{5px}{4ex}{2ex}^b_c d
\spacea b\(a\space{b}\)a ba\space{b}Not supporteda\space{b}
\spades\(\spades\)\spadesNot supported
\spadesuit\(\spadesuit\)\spadesuit\spadesuit
\sphericalangle\(\sphericalangle\)\sphericalangle\sphericalangle
{split}·𝐃=ρv·𝐁=0\[\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}\]𝐃=ρv𝐁=0\begin{equation}\begin{split}∇·𝐃&=ρ_v \\∇·𝐁&=0\end{split}\end{equation}Not supported\begin{equation}
\begin{split}
   ∇·𝐃&=ρ_v \\
   ∇·𝐁&=0
\end{split}
\end{equation}
\sqcap\(\sqcap\)\sqcap\sqcap
\sqcup\(\sqcup\)\sqcup\sqcup
\square\(\square\)\square\square
\sqrtx3\(\sqrt[3]{x}\)x3\sqrt[3]{x}x3\sqrt[3]{x}\sqrt[3]{x}
\sqsubset\(\sqsubset\)\sqsubset\sqsubset
\sqsubseteq\(\sqsubseteq\)\sqsubseteq\sqsubseteq
\sqsupset\(\sqsupset\)\sqsupset\sqsupset
\sqsupseteq\(\sqsupseteq\)\sqsupseteq\sqsupseteq
\ssßNot supportedß\text{\ss}Not supported\text{\ss}
\stackrel=!\(\stackrel{!}{=}\)=!\stackrel{!}{=}=!\stackrel{!}{=}\stackrel{!}{=}
\star\(\star\)\star\star
\StigmaϚNot supportedNot supportedNot supported
\stigmaϛNot supportedNot supportedNot supported
\strictifNot supportedNot supportedNot supported
\strictfiNot supportedNot supportedNot supported
\strutNot supported\(\boxed{ab\strut}\)Not supportedNot supported\boxed{ab\strut}
\styleNot supported\(\frac{\style{color:red}{x+1}}{y+2}\)Not supportedNot supported\frac{\style{color:red}{x+1}}{y+2}
Non standard
\sub\(\sub\)\subNot supported
{subarray}ac\(\begin{subarray}{c} a \\ c \end{subarray}\)ac\begin{subarray}{c} a \\ c \end{subarray}Not supported\sum_{\begin{subarray}
   {c} a \\
   c
\end{subarray}}
\sube\(\sube\)\subeNot supported
\Subset\(\Subset\)\Subset\Subset
\subset\(\subset\)\subset\subset
\subseteq\(\subseteq\)\subseteq\subseteq
\subseteqq\(\subseteqq\)\subseteqq\subseteqq
\subsetneq\(\subsetneq\)\subsetneq\subsetneq
\subsetneqq\(\subsetneqq\)\subsetneqq\subsetneqq
\substack1<i<31j<5aij\(\displaystyle\sum_{\substack{1\lt i\lt 3 \\ 1\le j\lt 5}}a_{ij}\)1<i<31j<5aij\displaystyle\sum_{\substack{1\lt i\lt 3 \\ 1\le j\lt 5}}a_{ij}1<i<31j<5aij\displaystyle\sum_{\substack{1\lt i\lt 3 \\ 1\le j\lt 5}}a_{ij}\sum_{\substack{1\lt i\lt 3 \\
1\le j\lt 5}}a_{ij}
\succ\(\succ\)\succ\succ
\succapprox\(\succapprox\)\succapprox\succapprox
\succcurlyeq\(\succcurlyeq\)\succcurlyeq\succcurlyeq
\succeq\(\succeq\)\succeq\succeq
\succnapprox\(\succnapprox\)\succnapprox\succnapprox
\succneqq\(\succneqq\)\succneqq\succneqq
\succnsim\(\succnsim\)\succnsim\succnsim
\succsim\(\succsim\)\succsim\succsim
\sum0nx0nx\(\sum_0^n x \; \displaystyle \sum_0^n x\)0nx  0nx\sum_0^n x \; \displaystyle \sum_0^n x0nx\sum_0^n x
\supsupxsupyxsupyx\(\begin{matrix}\sup x \\ \sup_y x \\\sup\limits_y x\end{matrix}\)supxsupyxsupyx\begin{matrix}\sup x \\ \sup_y x \\\sup\limits_y x\end{matrix}supxsupyxsuplimitsyx\begin{matrix}\sup x \\ \sup_y x \\\sup\limits_y x\end{matrix}
\supe\(\supe\)\supesupe\supe
\Supset\(\Supset\)\Supset\Supset
\supset\(\supset\)\supset\supset
\supseteq\(\supseteq\)\supseteq\supseteq
\supseteqq\(\supseteqq\)\supseteqq\supseteqq
\supsetneq\(\supsetneq\)\supsetneq\supsetneq
\supsetneqq\(\supsetneqq\)\supsetneqq\supsetneqq
\surd\(\surd\)\surd\surd
\swarrow\(\swarrow\)\swarrow\swarrow
- -

T

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\taga2+b2=c2(3.1c)\(\tag{3.1c} a^2+b^2=c^2\)a2+b2=c2(3.1c)\tag{3.1c} a^2+b^2=c^2Not supported\tag{3.1c} a^2+b^2=c^2
\tag*a2+b2=c23.1c\(\tag*{3.1c} a^2+b^2=c^2\)a2+b2=c23.1c\tag*{3.1c} a^2+b^2=c^2Not supported\tag*{3.1c} a^2+b^2=c^2
\tantanx\(\tan x\)tanx\tan xtanx\tan x
\tanhtanhx\(\tanh x\)tanhx\tanh xtanhx\tanh x
\TauΤ\(\Tau\)T\TauΤ\Tau
\tauτ\(\tau\)τ\tauτ\tau
\tbinom(nk)\(\tbinom n k\)(nk)\tbinom n k(nk)\tbinom n k\tbinom n k
\TeXTEX\(\TeX\)TeX\TeXNot supported
\text yes & no \(\text{ yes }\&\text{ no }\) yes & no \text{ yes }\&\text{ no } yes & no \text{ yes }\&\text{ no }\text{ yes }\&\text{ no }
\textMMMMMMMM\(\text{MMM$M\mkern2mu M$M}\)MMMMMM\text{MMM$M\mkern2mu M$M}Not supported\text{MMM$M\mkern2mu M$M}
\textasciitilde~Not supported~\text{\textasciitilde}Not supported\text{\textasciitilde}
\textasciicircum^Not supported^\text{\textasciicircum}Not supported\text{\textasciicircum}
\textbackslash\Not supported\\text{\textbackslash}Not supported\text{\textbackslash}
\textbar|Not supported|\text{\textbar}Not supported\text{\textbar}
\textbardblNot supported\text{\textbardbl}Not supported\text{\textbardbl}
\textbf𝐀𝐚𝐁𝐛𝟏\(\textbf{AaBb123}\)AaBb123\textbf{AaBb123}Not supported\textbf{AaBb123}
\textbraceleft{Not supported{\text{\textbraceleft}Not supported\text{\textbraceleft}
\textbraceright}Not supported}\text{\textbraceright}Not supported\text{\textbraceright}
\textcircledNot supportedNot supportedNot supportedNot supported\text{\textcircled a}
\textcolorF=ma\(\textcolor{blue}{F=ma}\)F=ma\textcolor{blue}{F=ma}Not supported\textcolor{blue}{F=ma}
\textdaggerNot supported\text{\textdagger}Not supported\text{\textdagger}
\textdaggerdblNot supported\text{\textdaggerdbl}Not supported\text{\textdaggerdbl}
\textdegree°Not supported°\text{\textdegree}Not supported\text{\textdegree}
\textdollar$Not supported$\text{\textdollar}Not supported\text{\textdollar}
\textellipsisNot supported\text{\textellipsis}Not supported\text{\textellipsis}
\textemdashNot supported\text{\textemdash}Not supported\text{\textemdash}
\textendashNot supported\text{\textendash}Not supported\text{\textendash}
\textgreater>Not supported>\text{\textgreater}Not supported\text{\textgreater}
\textit𝐴𝑎𝐵𝑏\(\textit{AaBb}\)AaBb\textit{AaBb}Not supported\textit{AaBb}
\textless<Not supported<\text{\textless}Not supported\text{\textless}
\textnormalABNot supportedAB\textnormal{AB}Not supported\textnormal{AB}
\textquotedblleftNot supported\text{\textquotedblleft}Not supported\text{\textquotedblleft}
\textquotedblrightNot supported\text{\textquotedblright}Not supported\text{\textquotedblright}
\textquoteleftNot supported\text{\textquoteleft}Not supported\text{\textquoteleft}
\textquoterightNot supported\text{\textquoteright}Not supported\text{\textquoteright}
\textregistered®Not supported®\text{\textregistered}Not supported\text{\textregistered}
\textrmAaBb123\(\textrm{AaBb123}\)AaBb123\textrm{AaBb123}Not supported\textrm{AaBb123}
\textscNot supportedNot supportedNot supportedNot supported
\textsf𝖠𝖺𝖡𝖻𝟣\(\textsf{AaBb123}\)AaBb123\textsf{AaBb123}Not supported\textsf{AaBb123}
\textsterling£Not supported£\text{\textsterling}Not supported\text{\textsterling}
\textstyle0n\(\textstyle\sum_0^n\)0n\textstyle\sum_0^n0n\textstyle\sum_0^n\textstyle\sum_0^n
\texttiphover hereNot supportedNot supportedNot supported\texttip{\text{hover here}}{tip}
\texttt𝙰𝚊𝙱𝚋𝟷\(\texttt{AaBb123}\)AaBb123\texttt{AaBb123}Not supported\texttt{AaBb123}
\textunderscore_Not supported_\text{\textunderscore}Not supported\text{\textunderscore}
\textvisiblespaceNot supported\(a\textvisiblespace b\)Not supportedNot supported
\tfracab\(\displaystyle \tfrac a b\)ab\displaystyle \tfrac a bab\displaystyle \tfrac a b\displaystyle \tfrac a b
\tgtgNot supportedtg\tgNot supported
\ththNot supportedth\thNot supported
\therefore\(\therefore\)\therefore\therefore
\ThetaΘ\(\Theta\)Θ\ThetaΘ\Theta
\thetaθ\(\theta\)θ\thetaθ\theta
\thetasymϑ\(\thetasym\)ϑ\thetasymθsym\thetasym
\thickapprox\(\thickapprox\)\thickapprox\thickapprox
\thicksim\(\thicksim\)\thicksim\thicksim
\thickspaceabNot supporteda  ba\thickspace baba\thickspace ba\thickspace b
\thinspaceab\(a\thinspace b\)aba\thinspace baba\thinspace ba\thinspace b
\tildeM~\(\tilde M\)M~\tilde MM˜\tilde M\tilde M
\times×\(\times\)×\times×\times
\TinyABNot supportedNot supportedNot supportedNon standard
\tinytiny\(\tiny tiny\)tiny\tiny tinyNot supported\tiny tiny
\to\(\to\)\to\to
\toggleClick HereOuchNot supportedNot supportedHey!Click Here\toggle{\text{Hey!}}{\text{Click Here}}
\top\(\top\)\top\top
\triangle\(\triangle\)\triangle\triangle
\triangledown\(\triangledown\)\triangledown\triangledown
\triangleleft\(\triangleleft\)\triangleleft\triangleleft
\trianglelefteq\(\trianglelefteq\)\trianglelefteq\trianglelefteq
\triangleq\(\triangleq\)\triangleq\triangleq
\triangleright\(\triangleright\)\triangleright\triangleright
\trianglerighteq\(\trianglerighteq\)\trianglerighteq\trianglerighteq
\tt𝙰𝚊𝙱𝚋𝟷𝟸𝟹\({\tt AaBb123}\)AaBb123{\tt AaBb123}Not supported{\tt AaBb123}
\twoheadleftarrow\(\twoheadleftarrow\)\twoheadleftarrow\twoheadleftarrow
\twoheadrightarrow\(\twoheadrightarrow\)\twoheadrightarrow\twoheadrightarrow
- -

U

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\ua˘Not supporteda˘\text{\u{a}}Not supported\text{\u{a}}
\Uarr\(\Uarr\)\UarrNot supported
\uArr\(\uArr\)\uArrNot supported
\uarr\(\uarr\)\uarrNot supported
\ulcorner\(\ulcorner\)\ulcornerNot supported
\underbracex++xn times\(\underbrace{x+⋯+x}_{n\text{ times}}\)x++xn times\underbrace{x+⋯+x}_{n\text{ times}}x++xn times\underbrace{x+⋯+x}_{n\text{ times}}\underbrace{x+⋯+x}_{n\text{ times}}
\underbracketNot supportedNot supportedNot supportedNot supported
\undergroupABNot supportedAB\undergroup{AB}Not supported\undergroup{AB}
\underleftarrowAB\(\underleftarrow{AB}\)AB\underleftarrow{AB}Not supported\underleftarrow{AB}
\underleftrightarrowAB\(\underleftrightarrow{AB}\)AB\underleftrightarrow{AB}Not supported\underleftrightarrow{AB}
\underrightarrowAB\(\underrightarrow{AB}\)AB\underrightarrow{AB}Not supported\underrightarrow{AB}
\underlinea long argument_\(\underline{\text{a long argument}}\)a long argument\underline{\text{a long argument}}a long argument_\underline{\text{a long argument}}\underline{\text{a long argument}}
\underlinesegmentNot supportedNot supportedNot supportedNot supported
\underparenabcNot supportedNot supportedNot supported\underparen{abc}
\underrightarrowAB\(\underrightarrow{AB}\)AB\underrightarrow{AB}Not supported\underrightarrow{AB}
\underset=!\(\underset{!}{=}\)=!\underset{!}{=}=!\underset{!}{=}\underset{!}{=}
\unicodeNot supported
See \char
\(\unicode{x263a}\)Not supportedNot supported\unicode{x263a}
See \char for alternate.
\unlhd\(\unlhd\)\unlhd\unlhd
\unrhd\(\unrhd\)\unrhd\unrhd
\upalphaαNot supportedNot supportedNot supported
\Uparrow\(\Uparrow\)\Uparrow\Uparrow
\uparrow\(\uparrow\)\uparrow\uparrow
\upbetaβNot supportedNot supportedNot supported
\upchiχNot supportedNot supportedNot supported
\updeltaδNot supportedNot supportedNot supported
\Updownarrow\(\Updownarrow\)\Updownarrow\Updownarrow
\updownarrow\(\updownarrow\)\updownarrow\updownarrow
\upetaηNot supportedNot supportedNot supported
\upepsilonϵNot supportedNot supportedNot supported
\upgammaγNot supportedNot supportedNot supported
\upharpoonleft\(\upharpoonleft\)\upharpoonleft\upharpoonleft
\upharpoonright\(\upharpoonright\)\upharpoonright\upharpoonright
\upiotaιNot supportedNot supportedNot supported
\upkappaκNot supportedNot supportedNot supported
\uplambdaλNot supportedNot supportedNot supported
\uplus\(\uplus\)\uplus\uplus
\upmuμNot supportedNot supportedNot supported
\upnuνNot supportedNot supportedNot supported
\upomegaωNot supportedNot supportedNot supported
\upomicronοNot supportedNot supportedNot supported
\upphiϕNot supportedNot supportedNot supported
\uppiπNot supportedNot supportedNot supported
\uppsiψNot supportedNot supportedNot supported
\uprhoρNot supportedNot supportedNot supported
\uprootNot supported\(\sqrt[3\uproot2]{x}\)Not supportedNot supported\sqrt[3\uproot2]{x}
\upsigmaσNot supportedNot supportedNot supported
\UpsilonΥ\(\Upsilon\)Υ\Upsilonϒ\Upsilon
\upsilonυ\(\upsilon\)υ\upsilonυ\upsilon
\uptauτNot supportedNot supportedNot supported
\upthetaθNot supportedNot supportedNot supported
\upuparrows\(\upuparrows\)\upuparrows\upuparrows
\upupsilonυNot supportedNot supportedNot supported
\upxiξNot supportedNot supportedNot supported
\upzetaζNot supportedNot supportedNot supported
\urcorner\(\urcorner\)\urcornerNot supported
\url𝚑𝚝𝚝𝚙𝚜://𝚝𝚎𝚖𝚖𝚕.𝚘𝚛𝚐/Not supportedhttps://temml.org/\url{https://temml.org/}Not supported\url{https://temml.org/}
\utildeAB~Not supportedAB~\utilde{AB}Not supported\utilde{AB}
- -

V

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\vaˇNot supportedaˇ\text{\v{a}}Not supported\text{\v{a}}
\varcoppaϙNot supportedNot supportedNot supported
\varDelta𝛥\(\varDelta\)Δ\varDeltaNot supported
\varepsilonε\(\varepsilon\)ε\varepsilonε\varepsilon
\varGamma𝛤\(\varGamma\)Γ\varGammaNot supported
\varinjlimlimnx\(\varinjlim\limits_n x\)limnx\varinjlim\limits_n xNot supported\varinjlim\limits_n x
\varkappaϰ\(\varkappa\)ϰ\varkappaϰ\varkappa
\varLambda𝛬\(\varLambda\)Λ\varLambdaNot supported
\varliminflim_nx\(\varliminf\limits_n x\)limnx\varliminf\limits_n xNot supported\varliminf\limits_n x
\varlimsuplim_nx\(\varlimsup\limits_n x\)limnx\varlimsup\limits_n xNot supported\varlimsup\limits_n x
\varnothingø\(\varnothing\)\varnothing\varnothing
\varOmega𝛺\(\varOmega\)Ω\varOmegaNot supported
\varPhi𝛷\(\varPhi\)Φ\varPhiNot supported
\varphiφ\(\varphi\)φ\varphiφ\varphi
\varPi𝛱\(\varPi\)Π\varPiNot supported
\varpiϖ\(\varpi\)ϖ\varpiϖ\varpi
\varprojlimlimnx\(\varprojlim\limits_n x\)limnx\varprojlim\limits_n xNot supported\varprojlim\limits_n x
\varpropto\(\varpropto\)\varpropto\varpropto
\varPsi𝛹\(\varPsi\)Ψ\varPsiNot supported
\varrhoϱ\(\varrho\)ϱ\varrhoϱ\varrho
\varSigma𝛴\(\varSigma\)Σ\varSigmaNot supported
\varsigmaς\(\varsigma\)ς\varsigmaς\varsigma
\varstigmaNot supported\(\varstigma\)Not supportedNot supported
\varsubsetneq⊊︀\(\varsubsetneq\)\varsubsetneq⊊︀\varsubsetneq
\varsubsetneqq⫋︀\(\varsubsetneqq\)\varsubsetneqq⫋︀\varsubsetneqq
\varsupsetneq\(\varsupsetneq\)\varsupsetneq⊋︀\varsupsetneq
\varsupsetneqq⫌︀\(\varsupsetneqq\)\varsupsetneqq⫌︀\varsupsetneqq
\varTheta𝛩\(\varTheta\)Θ\varThetaNot supported
\varthetaϑ\(\vartheta\)ϑ\varthetaϑ\vartheta
\vartriangle\(\vartriangle\)\vartriangle\vartriangle
\vartriangleleft\(\vartriangleleft\)\vartriangleleft\vartriangleleft
\vartriangleright\(\vartriangleright\)\vartriangleright\vartriangleright
\varUpsilon𝛶\(\varUpsilon\)Υ\varUpsilonNot supported
\varXi𝛯\(\varXi\)Ξ\varXiNot supported
\vcentcolon:=Not supported:=\mathrel{\vcentcolon =}Not supported\mathrel{\vcentcolon =}
\vcenterNot supportedNot supportedNot supportedNot supported
\Vdash\(\Vdash\)\Vdash\Vdash
\vDash\(\vDash\)\vDash\vDash
\vdash\(\vdash\)\vdash\vdash
\vdots\(\vdots\)\vdots\vdots
\vecF\(\vec{F}\)F\vec{F}F\vec{F}\vec{F}
\vee\(\vee\)\vee\vee
\veebar\(\veebar\)\veebar\veebar
\verb\frac a b\(\verb!\frac a b!\)\frac a b\verb!\frac a b!Not supported\verb!\frac a b!
\Vert\(\Vert\)\Vert\Vert
\vert|\(\vert\)\vert|\vert
\vfilNot supportedNot supportedNot supportedNot supported
\vfillNot supportedNot supportedNot supportedNot supported
\vlineNot supportedNot supportedNot supportedNot supported
{Vmatrix}abcd\(\begin{Vmatrix}a&b\\c&d\end{Vmatrix}\)abcd\begin{Vmatrix}a&b\\c&d\end{Vmatrix}abcd\begin{Vmatrix}a&b\\c&d\end{Vmatrix}\begin{Vmatrix}
   a & b \\
   c & d
\end{Vmatrix}
{vmatrix}|abcd|\(\begin{vmatrix}a&b\\c&d\end{vmatrix}\)abcd\begin{vmatrix}a&b\\c&d\end{vmatrix}|abcd|\begin{vmatrix}a&b\\c&d\end{vmatrix}\begin{vmatrix}
   a & b \\
   c & d
\end{vmatrix}
\vphantomMa_\(\overline{\vphantom{M}a}\)Ma\overline{\vphantom{M}a}Not supported\overline{\vphantom{M}a}
\Vvdash\(\Vvdash\)\Vvdash\Vvdash
- -

W

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\wedge\(\wedge\)\wedge\wedge
\weierp\(\weierp\)\weierpNot supported
\widecheckABˇNot supportedABˇ\widecheck{AB}ABˇ\widecheck{AB}\widecheck{AB}
\widehatAB^\(\widehat{AB}\)AB^\widehat{AB}AB^\widehat{AB}\widehat{AB}
\wideparenABNot supportedNot supportedNot supported -
\widetildeAB~\(\widetilde{AB}\)AB~\widetilde{AB}AB˜\widetilde{AB}\widetilde{AB}
\with&Not supportedNot supportedNot supported -
\wn?Not supportedNot supportedNot supported
\wp\(\wp\)\wp\wp
\wr\(\wr\)\wr\wr
- -

X

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\xcancelABC\(\xcancel{ABC}\)ABC\xcancel{ABC}Not supported\xcancel{ABC}
\XiΞ\(\Xi\)Ξ\XiΞ\Xi
\xiξ\(\xi\)ξ\xiξ\xi
\xhookleftarrowabcNot supportedabc\xhookleftarrow{abc}abc\xhookleftarrow{abc}\xhookleftarrow{abc}
\xhookrightarrowabcNot supportedabc\xhookrightarrow{abc}abc\xhookrightarrow{abc}\xhookrightarrow{abc}
\xLeftarrowabcNot supportedabc\xLeftarrow{abc}abc\xLeftarrow{abc}\xLeftarrow{abc}
\xleftarrowabc\(\xleftarrow{abc}\)abc\xleftarrow{abc}abc\xleftarrow{abc}\xleftarrow{abc}
\xleftharpoondownabcNot supportedabc\xleftharpoondown{abc}Not supported\xleftharpoondown{abc}
\xleftharpoonupabcNot supportedabc\xleftharpoonup{abc}Not supported\xleftharpoonup{abc}
\xLeftrightarrowabcNot supportedabc\xLeftrightarrow{abc}abc\xLeftrightarrow{abc}\xLeftrightarrow{abc}
\xleftrightarrowabc\(\xleftrightarrow{abc}\)abc\xleftrightarrow{abc}abc\xleftrightarrow{abc}\xleftrightarrow{abc}
\xleftrightharpoonsabcabcNot supportedabc\xleftrightharpoons{abc}abc\xleftrightharpoons{abc}\xleftrightharpoons{abc}
\xlongequal=abc\(\xlongequal{abc}\)=abc\xlongequal{abc}Not supported\xlongequal{abc}
\xmapstoabc\(\xmapsto{abc}\)abc\xmapsto{abc}abc\xmapsto{abc}\xmapsto{abc}
\xRightarrowabcNot supportedabc\xRightarrow{abc}abc\xRightarrow{abc}\xRightarrow{abc}
\xrightarrowAabcBAghiabcdefB\(\begin{matrix}A \xrightarrow{abc} B\\ A \xrightarrow[ghi]{abcdef} B \end{matrix}\)AabcBAghiabcdefB\begin{matrix}A \xrightarrow{abc} B\\ A \xrightarrow[ghi]{abcdef} B \end{matrix}AabcBAghiabcdefB\begin{matrix}A \xrightarrow{abc} B\\ A \xrightarrow[ghi]{abcdef} B \end{matrix}A \xrightarrow{abc} B
A \xrightarrow[ghi]{abcdef} B
\xrightharpoondownabcNot supportedabc\xrightharpoondown{abc}Not supported\xrightharpoondown{abc}
\xrightharpoonupabcNot supportedabc\xrightharpoonup{abc}Not supported\xrightharpoonup{abc}
\xrightleftharpoonsabcabc\(\xrightleftharpoons{abc}\)abc\xrightleftharpoons{abc}abc\xrightleftharpoons{abc}\xrightleftharpoons{abc}
\xtofromabcabc\(\xtofrom{abc}\)abc\xtofrom{abc}Not supported\xtofrom{abc}
\xtwoheadleftarrowabc\(\xtwoheadleftarrow{abc}\)abc\xtwoheadleftarrow{abc}Not supported\xtwoheadleftarrow{abc}
\xtwoheadrightarrowabc\(\xtwoheadrightarrow{abc}\)abc\xtwoheadrightarrow{abc}Not supported\xtwoheadrightarrow{abc}
- -

YZ

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTemmlMathJaxKaTeXTeXZillaSource or Comment
\yen¥\(\yen\)¥\yenNot supported
\Z\(\Z\)Z\ZNot supported
\ZetaΖ\(\Zeta\)Z\ZetaΖ\Zeta
\zetaζ\(\zeta\)ζ\zetaζ\zeta
- -
- -

Copyright © 2021, 2022 Ron Kok. Released under the MIT License

- -
- -
- - - - - - - - - \ No newline at end of file diff --git a/site/docs/en/support_table.html b/site/docs/en/support_table.html deleted file mode 100644 index 6066ab1c..00000000 --- a/site/docs/en/support_table.html +++ /dev/null @@ -1,1587 +0,0 @@ - - - - - - Temml Support Table - - - - - - -
-

Support Table

-

Temml is a JavaScript library that converts TeX math-mode functions to MathML. This page provides an alphabetically sorted list of TeX functions that Temml supports and some functions that it does not support. There is a similar page, with functions sorted by type.

-

To read this page, use a browser that supports MathML, such as Firefox or Safari. Chrome and Edge will support MathML soon.

-

Some functions are provided by an extension and are listed as such. They will be available only in pages that include the extension.

-

If you know the shape of a character, but not its name, Detexify can help.

-

Symbols

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
!n!n!
\!aba\!b
#y2\def\bar#1{#1^2} \bar{y}
\##
%%this is a comment
\%%
&abcd\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\&&
'
\'aˊ\text{\'{a}}
((
))
\a ba\ b
\"a¨\text{\"{a}}
\$ $
\,aba\,\,{b}
\.a˙\text{\.{a}}
\:aba\:\:{b}
\;aba\;\;{b}
_xix_i
\__
\`aˋ\text{\'{a}}
<<
\=aˉ\text{\={a}}
>>
\>aba\>\>{b}
[[
]]
{a{a}
}a{a}
\{{
\}}
||
\|
~no no no breaks\text{no~no~no~breaks}
\~a˜\text{\~{a}}
\\abcd\begin{matrix}
   a & b \\
   c & d
\end{matrix}
^xix^i
\^aˆ\text{\^{a}}
-

A

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or CommentPackage
\AA\text{\AA}
\aaa˚\text{\aa}
\aboveab+1{a \above{2pt} b+1}
\abovewithdelimsNot supported
\abs|x|\abs{x}physics extension
\absolutevalue|x|\absolutevalue{x}physics extension
\acomm{A,B}\acomm{A}{B}physics extension
\acuteeˊ\acute e
\AEÆ\text{\AE}
\aeæ\text{\ae}
\aleftexvc extension
\alefsymtexvc extension
\aleph
{align}a=b+cd+e=f\begin{align}
   a&=b+c \\
   d+e&=f
\end{align}
ams
{align*}a=b+cd+e=f\begin{align*}
   a&=b+c \\
   d+e&=f
\end{align*}
ams
{aligned}a=b+cd+e=f\begin{aligned}
   a&=b+c \\
   d+e&=f
\end{aligned}
ams
{alignat}10x+3y=23x+13y=4\begin{alignat}{2}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{alignat}
ams
{alignat*}10x+3y=23x+13y=4\begin{alignat*}{2}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{alignat*}
ams
{alignedat}10x+3y=23x+13y=4\begin{alignedat}{2}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{alignedat}
ams
\allowbreak
\AlphaΑ
\alphaα
\amalg⨿
\And&
\andNot supportedDeprecatedtexvc
\angNot supportedDeprecatedtexvc
\anglana_{\angl n}actuarialangle
\anglnana_\anglnactuarialangle
\angle
\anticommutator{A,B}\anticommutator{A}{B}physics extension
\approx
\approxeq
\arccosarccos
\arcctgarcctg
\arceqstix
\arcsinarcsin
\arctanarctan
\arctgarctg
\argarg
\argmaxargmaxstatmath
\argminargminstatmath
{array}abcd\begin{array}{cc}
   a & b \\
   c & d
\end{array}
LaTeX2ε
\arrayNot supportedSee {array}
\arraystretchabcd\def\arraystretch{1.5}
\begin{array}{cc}
   a & b \\
   c & d
\end{array}
\ArrowvertNot supportedsee \Vert
\arrowvertNot supportedsee \vert
\ast
\asymp
\atopab{a \atop b}
\atopwithdelimsNot supported
-

B

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or CommentPackage
\backcongMnSymbol
\backepsilonams
\backprimeams
\backsimams
\backsimeqams
\backslash\
\bary\bar{y}
\barwedgeams
\ballotxarev
\Bbb𝔸𝔹\Bbb{ABC}
\Bbbk𝕜
\bboxNot supported
\bcancel5\bcancel{5}cancel
\becauseams
\beginabcd\begin{matrix}
   a & b \\
   c & d
\end{matrix}
ams
\begingroupa\begingroup a\endgroup
\BetaΒ
\betaβ
\bethams
\betweenams
\bf𝐀𝐚𝐁𝐛𝟏𝟐{\bf AaBb12}
\bfseriesNot supported
\big()\big(\big)
\Big()\Big(\Big)
\bigcap
\bigcirc
\bigcup
\bigg()\bigg(\bigg)
\Bigg()\Bigg(\Bigg)
\biggl(\biggl(
\Biggl(\Biggl(
\biggm|\biggm\vert
\Biggm|\Biggm\vert
\biggr)\biggr)
\Biggr)\Biggr)
\bigl(\bigl(
\Bigl(\Bigl(
\bigm|\bigm\vert
\Bigm|\Bigm\vert
\bigodot
\bigominusNot supported
\bigoplus
\bigoslashNot supported
\bigotimes
\bigr)\bigr)
\Bigr)\Bigr)
\bigsqcap
\bigsqcup
\bigstarams
\bigtriangledown
\bigtriangleup
\biguplus
\bigvee
\bigwedge
\binom(nk)\binom n kams
\blacklozengeams
\blacksquareams
\blacktriangleams
\blacktriangledownams
\blacktriangleleftams
\blacktrianglerightams
\bm𝑨𝒂𝑩𝒃\bm{AaBb}bm
{Bmatrix}{abcd}\begin{Bmatrix}
   a & b \\
   c & d
\end{Bmatrix}
ams
{Bmatrix*}{1324}\begin{Bmatrix*}[r]
   -1 & 3 \\
   2 & -4
\end{Bmatrix*}
mathtools
{bmatrix}[abcd]\begin{bmatrix}
   a & b \\
   c & d
\end{bmatrix}
ams
{bmatrix*}[1324]\begin{bmatrix*}[r]
   -1 & 3 \\
   2 & -4
\end{bmatrix*}
mathtools
\bmodamodba \bmod b
\bold𝐀𝐚𝐁𝐛𝟏𝟐𝟑\bold{AaBb123}
\boldsymbol𝑨𝒂𝑩𝒃\boldsymbol{AaBb}ams
\bot
\Botcmll
\bowtie
\Boxams
\boxdotams
\boxedab\boxed{ab}ams
\boxminusams
\boxplusams
\boxtimesams
\Bqty{5mm}\Bqty{5 \text{mm}}physics extension
\bqty[5mm]\bqty{5 \text{mm}}physics extension
\Braψ|\Bra{\psi}braket
\braψ|\bra{\psi}braket
\braketϕ|ψ\braket{\phi\|\psi}braket
\Braketϕ|2t2|ψ\Braket{ϕ\|\frac{∂^2}{∂ t^2}\|ψ}braket
\brace{nk}{n\brace k}
\bracevertNot supported
\brack[nk]{n\brack k}
\breveeu˘\breve{eu}
\buildrelNot supported
\bulltexvc extension
\bullet
\Bumpeqams
\bumpeqams
-

C

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or CommentPackage
\CNot supportedDeprecatedtexvc
\cc¸\text{\c{c}}
\cal𝒜𝒶𝒷{\cal AaBb}
\cancel5\cancel{5}cancel
\canceltox+10\cancelto{0}{x+1}cancel
\Capams
\cap
{cases}{aif bcif d\begin{cases}
   a &\text{if } b \\
   c &\text{if } d
\end{cases}
ams
\casesNot supportedsee {cases}
{CD}AaBbcC=D\begin{CD}
   A @>a>> B \\
@VbVV @AAcA \\
   C @= D
\end{CD}
ams
\cdot
\cdotp·
\cdots
\ce CX6HX5CHO\ce{C6H5-CHO}mhchem extension
\ceeNot supportedDeprecated
Use \ce instead.
mhchem
\centerdotams
\cfNot supportedDeprecated
Use \ce instead.
mhchem
\cfrac21+21\cfrac{2}{1+\cfrac{2}{1}}ams
\checkoeˇ\check{oe}
\chch
\checkmarkams
\ChiΧ
\chiχ
\choose(n+1k+2){n+1 \choose k+2}
\circ
\circeqams
\circlearrowleftams
\circlearrowrightams
\circledastams
\circledcircams
\circleddashams
\circledR®ams
\circledSams
\classNot supported
\clineNot supported
\clubstexvc extension
\clubsuit
\cnumstexvc extension
\cohcmll
\colon:
\Colonapprox∷≈mathtools
\colonapprox:mathtools
\coloncoloncolonequals
\coloncolonapprox∷≈colonequals
\coloncolonequalscolonequals
\coloncolonminus∷−colonequals
\coloncolonsim:colonequals
\colonminus:colonequals
\Coloneq∷−mathtools
\coloneq:mathtools
\Coloneqqmathtools
\coloneqqmathtools
\Colonsim:mathtools
\colonsim:mathtools
\colorAaBb123\color{#0000FF} AaBb123color
\colorboxBlack on red\colorbox{red}{Black on red}color
\comm[A,B]\comm{A}{B}physics extension
\commutator[A,B]\commutator{A}{B}physics extension
\complementams
\Complextexvc extension
\cong
\CoppaϘ
\coppaϙ
\coprod
\copyright©
\coscos
\coseccosec
\coshcosh
\cotcot
\cotgcotg
\cothcoth
\cp×physics extension
\crabcd\begin{matrix}
   a & b \cr
   c & d
\end{matrix}
\cross×physics extension
\crossproduct×physics extension
\csccsc
\cssIdNot supportedSee \id.
\ctgctg
\cthcth
\Cupams
\cup
\curl𝛁×physics extension
\curlyeqprecams
\curlyeqsuccams
\curlyveeams
\curlywedgeams
\curvearrowleftams
\curvearrowrightams
-

D

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\dag
\Daggertexvc extension
\dagger
\dalethams
\Darrtexvc extension
\dArrtexvc extension
\darrtexvc extension
{darray}abcd\begin{darray}{cc}
   a & b \\
   c & d
\end{darray}
\dashleftarrowams
\dashrightarrowams
\dashv
\dbinom(nk)\dbinom n kams
\dblcolonmathtools
{dcases}{aif bcif d\begin{dcases}
   a &\text{if } b \\
   c &\text{if } d
\end{dcases}
mathtools
\ddd\ddphysics extension
\ddag
\ddagger
\ddddotx\ddddot xams
\dddotx\dddot xams
\ddotx¨\ddot x
\ddots
\DeclareMathOperatorNot supported
\defx2+x2\def\foo{x^2} \foo + \foo
\definecolorF=ma\definecolor{sortaGreen}{RGB}{128,128,0}
\color{sortaGreen} F=ma
xcolor
\degdeg
\degree°
\deltaδ
\DeltaΔ
\derivativedxdy\derivative{x}{y}physics extension
\detdet
\dfraca1b1\dfrac{a-1}{b-1}ams
\differentiald\differentialphysics extension
\diagdownams
\diagonalmatrixNot supportedphysics
\diagupams
\Diamond
\diamond
\diamondstexvc extension
\diamondsuit
\DigammaNot supported
\digammaϝams
\dimdim
\displaylinesNot supported
\displaystyle0n\displaystyle\sum_0^n
\div÷
\divergence𝛁\divergencephysics extension
\divideontimesams
\dotx˙\dot x
\Doteqams
\doteq
\doteqdotams
\dotplusams
\dotproduct\dotproductphysics extension
\dotsx1++xnx_1 + \dots + x_n
\dotsbx1++xnx_1 +\dotsb + x_nams
\dotscx,,yx,\dotsc,yams
\dotsiA1A2\int_{A_1}\int_{A_2}\dotsiams
\dotsmx1x2xn$x_1 x_2 \dotsm x_nams
\dotsoams
\doublebarwedgeams
\doublecapams
\doublecupams
\Downarrow
\downarrow
\downdownarrowsams
\downharpoonleftams
\downharpoonrightams
{drcases}aif bcif d}\begin{drcases}
   a &\text{if } b \\
   c &\text{if } d
\end{drcases}
mathtools
\dvdxdy\dv{x}{y}physics extension
\dyad|ab|\dyad{a}{b}physics extension
-

E

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\edefa\def\foo{a}\edef\bar{\foo}\def\foo{}\bar
\ell
\elseNot supported
\emNot supported
\emphNot supported
\emptytexvc extension
\emptyset
\encloseNot supportedNon standard.
See \boxed, \cancel, \bcancel,
\xcancel, \sout, \longdiv, \angl
\endabcd\begin{matrix}
   a & b \\
   c & d
\end{matrix}
\endgroupa\begingroup a\endgroup
\enspaceaba\enspace b
\EpsilonΕ
\epsilonϵ
\eqalignNot supportedSee {align*}
\eqalignnoNot supportedSee {align}
\eqcircams
\Eqcolon−∷mathtools
\eqcolonmathtools
\equalscoloncolonequals
\equalscoloncolon=∷colonequals
{equation}a=b+c\begin{equation}
   a = b + c
\end{equation}
ams
{equation*}a=b+c\begin{equation*}
   a = b + c
\end{equation*}
ams
{eqnarray}Not supported
\Eqqcolon=∷mathtools
\eqqcolonmathtools
\eqdefstix
\eqref\eqref{tag1}
Some sites do not support \eqref.
ams
\eqsimams
\eqslantgtrams
\eqslantlessams
\equiv
\erferf(x)\erf(x)physics extension
\EtaΗ
\etaη
\ethðams
\euro
\evx\ev{x}physics extension
\eval12x|0n\eval{\tfrac 1 2 x}_0^nphysics extension
\evaluated12x|0n\evaluated{\tfrac 1 2 x}_0^nphysics extension
\existtexvc extension
\exists
\expexp
\expandafter
\expectationvaluex\expectationvalue{x}physics extension
\expvalx\expval{x}physics extension
-

F

- - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\fallingdotseq ams
\fbox Hi there!\fbox{Hi there!}
\fcolorbox A\fcolorbox{red}{aqua}{A}xcolor
\fdv δxδy\fdv{x}{y}physics extension
\female stix
\fi Not supported
\Finv ams
\flat
\footnotesize footnotesize\footnotesize footnotesize
\forall
\frac ab\frac a bams
\frak 𝔄𝔞𝔅𝔟\frak{AaBb}
\frown
\functionalderivative δxδy\functionalderivative{x}{y}physics extension
\futurelet
-

G

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\Game ams
\Gamma Γ
\gamma γ
{gather} a=be=b+c\begin{gather}
   a=b \\
   e=b+c
\end{gather}
ams
{gather*} a=be=b+c\begin{gather*}
   a=b \\
   e=b+c
\end{gather*}
ams
{gathered} a=be=b+c\begin{gathered}
   a=b \\
   e=b+c
\end{gathered}
ams
\gcd gcd
\gdef Not supported
\ge
\geneuro Not supported See \euro
\geneuronarrow Not supported See \euro
\geneurowide Not supported See \euro
\genfrac (aa+1]\genfrac ( ] {2pt}{0}a{a+1}ams
\geq
\geqq ams
\geqslant ams
\gets
\gg
\ggg ams
\gggtr ams
\gimel ams
\global Not supported
\gnapprox ams
\gneq ams
\gneqq ams
\gnsim ams
\grad 𝛁physics extension
\gradient 𝛁physics extension
\grave eu`\grave{eu}
\gt a>ba \gt bMathJax
\gtrapprox ams
\gtrdot ams
\gtreqless ams
\gtreqqless ams
\gtrless ams
\gtrsim ams
\gvertneqq ≩︀ams
-

H

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\H a˝\text{\H{a}}
\Harr texvc extension
\hArr texvc extension
\harr texvc extension
\hat θ^\hat{\theta}
\hbar
\hbox x2\hbox{$x^2$}
\hbox to Not supported
\hdashline abcd\begin{matrix}
   a & b \\
   \hdashline
   c & d
\end{matrix}
arydshln
\hearts texvc extension
\heartsuit
\hfil Not supported
\hfill Not supported
\hline abcd\begin{matrix}
   a & b \\ \hline
   c & d
\end{matrix}
\hom hom
\hookleftarrow
\hookrightarrow
\hphantom abcda\hphantom{bc}d
\href TEMML\href{https://temml.org/}{\Temml}
Requires trust option
href
\hskip widw\hskip1em i\hskip2em d
\hslash ams
\hspace sks\hspace{7ex} k
\class x\class{foo}{x}
Must enable trust and disable strict option
\data x\data{foo=a, bar=b}{x}
Must enable trust and disable strict option
\id x\id{bar}{x}
Must enable trust and disable strict option
\style x\style{color: red;}{x}
Must enable trust and disable strict option
\huge huge\huge huge
\Huge Huge\Huge Huge
-

I

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\i ı\text{\i}
\idotsint \int\idotsint\intams
\iddots
\if Not supported
\iff ABA\iff B
\ifmode Not supported
\ifx Not supported
\iiiint ams
\iiint ams
\iint ams
\Im
\image texvc extension
\imageof stix
\imath ı
\impliedby PQP\impliedby Qams
\implies PQP\implies Qams
\in
\includegraphics sphere\includegraphics[height=1em,
totalheight=1.2em, width=1.2em,
alt=sphere]{../sphere.jpg}
graphicx
\incoh cmll
\inf inf
\infin texvc extension
\infty
\injlim injlim\injlimams
\innerproduct a|b\innerproduct{a}{b}physics extension
\int
\intbar
\intBar
\intcap
\intclockwise
\intcup
\intercal ams
\intlarhk
\intop
\intx
\invamp cmll
\Iota Ι
\iota ι
\isin texvc extension
\it AaBb{\it AaBb}
\itshape Not supported
-

JK

- - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\j ȷ\text{\j}
\jmath ȷ
\Join ams
\Kappa Κ
\kappa κ
\ker ker
\kern IRI\kern-2.5pt R
\Ket |ψ\Ket{\psi}braket
\ket |ψ\ket{\psi}braket
\ketbra |ab|\ketbra{a}{b}physics extension
\Koppa Ϟ
\koppa ϟ
-

L

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\L Not supported
\l Not supported
\Lambda Λ
\lambda λ
\label \label{idName}
Creates an HTML id.
Characters limited to: A-Za-z0-9_-
\land
\lang A\lang A\rangletexvc extension
\langle A\langle A\rangle
\laplacian 2physics extension
\Larr texvc extension
\lArr texvc extension
\larr texvc extension
\large large\large large
\Large Large\Large Large
\LARGE LARGE\LARGE LARGE
\LaTeX LATEX
\lBrace stix
\lbrace {
\lbrack [
\lceil
\ldotp .
\ldots
\le
\leadsto ams
\left {ab\left\lbrace \dfrac ab \right.
\leftarrow
\Leftarrow
\LeftArrow Not supported Non standard
\leftarrowtail ams
\leftharpoondown
\leftharpoonup
\leftleftarrows ams
\Leftrightarrow
\leftrightarrow
\leftrightarrows ams
\leftrightharpoons ams
\leftrightsquigarrow ams
\leftroot Not supported
\leftthreetimes ams
\leq
\leqalignno Not supported
\leqq ams
\leqslant ams
\lessapprox ams
\lessdot ams
\lesseqgtr ams
\lesseqqgtr ams
\lessgtr ams
\lesssim ams
\let
\lfloor
\lg lg
\lgroup
\lhd ams
\lightning
\lim lim
\liminf liminf
\limits limx\lim\limits_x
\limsup limsup
\ll
\llap ={=}\llap{/\,}
\llbracket stmaryrd
\llcorner ams
\Lleftarrow ams
\lll ams
\llless ams
\lmoustache
\ln ln
\lnapprox ams
\lneq ams
\lneqq ams
\lnot ¬
\lnsim ams
\log log
\long
\longdiv 3x2+2x+5\longdiv{3x^2 + 2x + 5}Temml
\Longleftarrow
\longleftarrow
\Longleftrightarrow
\longleftrightarrow
\longmapsto
\Longrightarrow
\longrightarrow
\looparrowleft ams
\looparrowright ams
\lor
\lower MM2MM\lower5pt{M^2}M  or
M\lower5pt\hbox{$M^2}M
\lozenge ams
\lparen (mathtools
\Lrarr texvc extension
\lrArr texvc extension
\lrarr texvc extension
\lrcorner ams
\lq
\Lsh ams
\lt <MathJax
\ltimes ams
\lVert ams
\lvert |ams
\lvertneqq ≨︀ams
-

M

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\malestix
\malteseams
\mapsto
\mathbb𝔸𝔹\mathbb{AB}ams
\mathbf𝐀𝐚𝐁𝐛𝟏𝟐𝟑\mathbf{AaBb123}
\mathbina!ba\mathbin{!}b
\mathcal𝒜𝒶𝒷\mathcal{AaBb}
\mathchoiceaba\mathchoice{\,}{\,\,}{\,\,\,}{\,\,\,\,}b
\mathclap1inxi\sum_{\mathclap{1\le i\le n}} x_{i}mathtools
\mathclosea+(b>+ca + (b\mathclose\gt + c
\mathellipsis
\mathfrak𝔄𝔞𝔅𝔟\mathfrak{AaBb}ams
\mathinnerabinsidecdab\mathinner{\text{inside}}cd
\mathitAaBb\mathit{AaBb}
\mathllap={=}\mathllap{/\,}mathtools
\mathnormalAaBb\mathnormal{AaBb}
\mathopab\mathop{\star}_a^b
\mathopena+<b)+ca + \mathopen\lt b) + c
\mathord1,234,5671\mathord{,}234{,}567
\mathpunctABA\mathpunct{-}B
\mathrela#ba \mathrel{\#} b
\mathrlap=\mathrlap{\,/}{=}mathtools
\mathringa˚\mathring{a}ams
\mathrmAaBb12\mathrm{AaBb12}
\mathscr𝒜\mathscr{AB}
\mathsf𝖠𝖺𝖡𝖻𝟣𝟤𝟥\mathsf{AaBb123}
\mathsterling£
\mathstrut(a\sqrt{\mathstrut a}
\mathtipNot supportedSee \texttip
\mathtt𝙰𝚊𝙱𝚋𝟷𝟸𝟹\mathtt{AaBb123}
\matrixNot supportedSee {matrix}
{matrix}abcd\begin{matrix}
   a & b \\
   c & d
\end{matrix}
ams
{matrix*}1324\begin{matrix*}[r]
   -1 & 3 \\
   2 & -4
\end{matrix*}
mathtools
\matrixeln|A|m\matrixel{n}{A}{m}physics extension
\matrixelementn|A|m\matrixelement{n}{A}{m}physics extension
\meln|A|m\mel{n}{A}{m}physics extension
\maxmax
\mboxNot supported
\mdNot supported
\mdseriesNot supported
\measeqstix
\measuredangleams
\medspaceaba\medspace bams
\mho
\mid{x|x>0}\{x∈ℝ\mid x>0\}
\middleP(A|B)P\left(A\middle\vert B\right)
\minmin
\minuscoloncolonequals
\minuscoloncolon−∷colonequals
\minusoNot supportedSee \standardstate
\mitNot supportedSee \mathit
\mkernaba\mkern18mu b
\mmlTokenNot supported
\mod35mod23\equiv 5 \mod 2ams
\models
\moveleftNot supported
\moverightNot supported
\mp
\mskipaba\mskip{10mu}b
\mspaceNot supported
\MuΜ
\muμ
\multicolumnNot supported
\multimapams
\multimapbothcmll
\multimapinvcmll
{multline}unodostres\begin{multline}
  \rm uno \\
  \rm dos \\
  \rm tres
\end{multline}
ams
{multline*}unodostres\begin{multline*}
  \rm uno \\
  \rm dos \\
  \rm tres
\end{multline*}
ams
-

N

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\Ntexvc extension
\nabla
\natnumstexvc extension
\natural
\negmedspaceaba\negmedspace bams
\ncongams
\ne
\nearrow
\neg¬
\negthickspaceaba\negthickspace bams
\negthinspaceaba\negthinspace bams
\neq
\newcommand\newcommand\chk{\checkmark} \chknewcommand
\newenvironmentNot supported
\newextarrowNot supportedextpfeil
\newlineaba\newline b
\nexistsams
\ngeqams
\ngeqqams
\ngeqslantams
\ngtrams
\ni
\nleftarrowams
\nLeftarrowams
\nLeftrightarrowams
\nleftrightarrowams
\nleqams
\nleqqams
\nleqslantams
\nlessams
\nmidams
\nobreak
\nobreakspacea ba\nobreakspace bams
\noexpand
\nolimitslimx\lim\nolimits_x
\normx\norm{x}physics extension
\normalfontNot supported
\normalsizenormalsize\normalsize normalsize
\not\not =
\notaga=bd+e=f\begin{align}
  a&=b \\
  \notag d+e&=f
\end{align}
ams
\notin
\notnitxfonts/pxfonts
\nparallelams
\nprecams
\npreceqams
\nRightarrowams
\nrightarrowams
\nshortmidams
\nshortparallelams
\nsimams
\nsubsetmathabx
\nsubseteqams
\nsubseteqqams
\nsuccams
\nsucceqams
\nsupsetmathabx
\nsupseteqams
\nsupseteqqams
\ntriangleleftams
\ntrianglelefteqams
\ntrianglerightams
\ntrianglerighteqams
\NuΝ
\nuν
\nVDashams
\nVdashams
\nvDashams
\nvdashams
\nwarrow
-

O

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\OØ\text{\O}
\oø\text{\o}
\oc!cmll
\odot
\odvdfdx\odv{f}{x}derivative
\odv*ddxf\odv*{f}{x}derivative
\OEŒ\text{\OE}
\oeœ\text{\oe}
\officialeuroNot supportedSee \euro
\oiiint
\oiint
\oint
\oldstyleNot supportedSee \oldstylenums
\oldstylenums123\oldstylenums{123}LaTeX2ε
\omegaω
\OmegaΩ
\OmicronΟ
\omicronο
\ominus
\op|ab|\op{a}{b}physics extension
\operatornameasinx\operatorname{asin} xams
\operatorname*asinyx\operatorname*{asin}\limits_y xams
\operatornamewithlimitsasinyx\operatornamewithlimits{asin}\limits_y x
\oplus
\orNot supported
\order𝒪(x2)\order{x^2}physics extension
\origofstix
\oslash
\otimes
\outerproduct|ab|\outerproduct{a}{b}physics extension
\overa+1b+2+c{a+1 \over b+2}+c
\overbracex++xn times\overbrace{x+⋯+x}^{n\text{ times}}
\overbracketNot supported
\overgroupAB\overgroup{AB}MnSymbol
\overleftarrowAB\overleftarrow{AB}ams
\overleftharpoonAB\overleftharpoon{AB}MnSymbol
\overleftrightarrowAB\overleftrightarrow{AB}ams
\overlinea long argument_\overline{\text{a long argument}}
\overlinesegmentNot supported
\overparenabc\overparen{abc}
\OverrightarrowAB\Overrightarrow{AB}overrightarrow
\overrightarrowAB\overrightarrow{AB}ams
\overrightharpoonac\overrightharpoon{ac}
\overset=!\overset{!}{=}ams
\overwithdelimsNot supported
\owns
-

P

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\P\text{\P} or \P
\pagecolorNot supportedDeprecatedtexvc
\parallel
\parrcmll
\partNot supportedDeprecatedtexvc
\partial
\partialderivativexy\partialderivative{x}{y}physics extension
\pb{x,y}\pb{x}{y}physics extension
\pdv2fxy\pdv{f}{x,y}derivative
\pdv*2xyf\pdv*{f}{x,y}derivative
\permilwasysym
\perp
\Perpcmll
\phantomΓijkij\Gamma^{\phantom{i}j}_{i\phantom{j}k}
\phase78\phase{-78^\circ}steinmetz
\PhiΦ
\phiϕ
\PiΠ
\piπ
{picture}Not supported
\pitchforkams
\plimplimstatmath
\plusmn±texvc extension
\pm±
\pmatrixNot supportedSee {pmatrix}
{pmatrix}(abcd)\begin{pmatrix}
   a & b \\
   c & d
\end{pmatrix}
ams
{pmatrix*}(1324)\begin{pmatrix*}[r]
   -1 & 3 \\
   2 & -4
\end{pmatrix*}
mathtools
\pmbμ\pmb{\mu}ams
\pmodx(moda)x\pmod a
\podx(a)x \pod aams
\pointint
\poissonbracket{A,B}\poissonbracket{A}{B}physics extension
\pounds£
\pqty(5)\pqty{5}physics extension
\PrPr
\prec
\precapproxams
\preccurlyeqams
\preceqams
\precnapproxams
\precneqqams
\precnsimams
\precsimams
\prescript𝐂25+a2\prescript{a}{2}{\mathbf{C}}^{5+}_{2}mathtools
\prime
\principalvalue𝒫physics extension
\pv𝒫physics extension
\PVP.V.(x)\PV(x)physics extension
\prod
\projlimprojlim\projlimams
\propto
\providecommandHello\providecommand\greet{\text{Hello}}
\greet
\psiψ
\PsiΨ
\pu 123 kJmol\pu{123 kJ//mol}mhchem extension
-

Q

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\Q Not supported See \Bbb{Q}
\qall allphysics extension
\qand andphysics extension
\qas asphysics extension
\qassume assumephysics extension
\qc ,physics extension
\qcc c.c.physics extension
\qcomma ,physics extension
\qelse elsephysics extension
\qeven evenphysics extension
\qfor forphysics extension
\qgiven givenphysics extension
\qif ifphysics extension
\qin inphysics extension
\qinteger integerphysics extension
\qlet letphysics extension
\qodd oddphysics extension
\qor orphysics extension
\qotherwise otherwisephysics extension
\qq  text \qq{text}physics extension
\qqtext  text \qqtext{text}physics extension
\qquad aba\qquad\qquad{b}
\qsince sincephysics extension
\qthen thenphysics extension
\qty {5m}\qty{5 \text{m}}physics extension
\quad aba\quad\quad{b}
\quantity {5m}\quantity{5 \text{m}}physics extension
\qunless unlessphysics extension
\qusing usingphysics extension
\questeq stix
-

R

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\R texvc extension
\r a˚\text{\r{a}}
\raise MM2MM\raise3pt{M^2}M  or
M\raise3pt\hbox{$M^2}M
\raisebox higherh\raisebox{2pt}{ighe}r
\rang A\langle A\rangtexvc extension
\rangle A\langle A\rangle
\rank rankM\rank Mphysics extension
\Rarr texvc extension
\rArr texvc extension
\rarr texvc extension
\ratio :colonequals
\rBrace stix
\rbrace }
\rbrack ]
{rcases} aif bcif d}\begin{rcases}
   a &\text{if } b \\
   c &\text{if } d
\end{rcases}
mathtools
\rceil
\Re
\real texvc extension
\Reals texvc extension
\reals texvc extension
\ref \ref{tag1}
Some sites do not support \ref.
\relax
\renewcommand Ahoy!\def\hail{Hi!}
\renewcommand\hail{\text{Ahoy!}}
\hail
newcommand
\renewenvironment Not supportednewcommand
\require Not supported
\Res Res[f(z)]\Res[f(z)]physics extension
\restriction ams
\rfloor
\rgroup
\rhd ams
\Rho Ρ
\rho ρ
\right ab)\left.\dfrac a b\right)
\Rightarrow
\rightarrow
\rightarrowtail ams
\rightharpoondown
\rightharpoonup
\rightleftarrows ams
\rightleftharpoons ams
\rightrightarrows ams
\rightsquigarrow ams
\rightthreetimes ams
\risingdotseq ams
\rlap =\rlap{\,/}{=}
\rm AaBb12{\rm AaBb12}
\rmoustache
\root Not supported
\rotatebox Not supported
\rparen )mathtools
\rppolint
\rq
\rrbracket stmaryrd
\Rrightarrow ams
\Rsh ams
\rtimes ams
\Rule Not supportedsee \rule
\rule xxx\rule[6pt]{2ex}{1ex}x
\rVert ams
\rvert |ams
-

S

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\S§\text{\S} or \S
\SampiϠ
\sampiϡ
\scNot supportedSee \textsc
\scohcmll
\scaleboxNot supported
\scpolint
\scrNot supportedSee \mathscr
\scriptscriptstylecd\scriptscriptstyle \frac cd
\scriptsizescriptsize\scriptsize scriptsize
\scriptstyleABA{\scriptstyle B}
\sdottexvc extension
\searrow
\secsec
\sect§\text{\sect}texvc extension
\set{x|x<5}\set{x | x<5}braket
\Set{x|x<12}\Set{ x | x<\tfrac 1 2 }braket
\setlengthNot supported
\setminus
\sf𝖠𝖺𝖡𝖻𝟣𝟤𝟥{\sf AaBb123}
\sgnsgnmismath
\sharp
\shiftcmll
\shnegcmll
\shortmidams
\shortparallelams
\shoveleftNot supportedams
\shoverightNot supportedams
\shposcmll
\sidesetcdab\sideset{_a^b}{_c^d}\sumams
\SigmaΣ
\sigmaσ
\sim
\simeq
\sinsin
\sincohcmll
\sinhsinh
\sixptsizesixptsize\sixptsize sixptsize
\shsh
\skewNot supported
\skipNot supported
\slNot supported
\smallsmall\small small
\smallfrownams
\smallint
{smallmatrix}abcd\begin{smallmatrix}
   a & b \\
   c & d
\end{smallmatrix}
\smallsetminusams
\smallsmileams
\smash(x2)\left(x^{\smash{2}}\right)
\smile
\smileywasysym
\soutabc\sout{abc}ulem
\SpaceNot supportedsee \space
\spacea ba\space b
\spadestexvc extension
\spadesuit
\sphericalangleams
{split}a=b+c=e+f\begin{equation}
\begin{split}
   a &=b+c\\
      &=e+f
\end{split}
\end{equation}
ams
\sqcap
\sqcup
\sqint
\square
\sqrtx3\sqrt[3]{x}
\sqsubsetams
\sqsubseteq
\sqsupsetams
\sqsupseteqams
\ssß\text{\ss}
\stackrel=!\stackrel{!}{=}
\standardstatechemstyle
\star
\stareqstix
\StigmaϚ
\stigmaϛ
\strictiftxfonts/pxfonts
\strictfitxfonts/pxfonts
\strutNot supported
\styleNot supportedNon standard
\subtexvc extension
{subarray}iΛ0<j<nP(i,j)\sum_{\begin{subarray}{l}
 i\in\Lambda\\
  0<j<n
\end{subarray}}P(i,j)
ams
\subetexvc extension
\Subsetams
\subset
\subseteq
\subseteqqams
\subsetneqams
\subsetneqqams
\substack0<i<m0<j<n\sum_{\substack{0<i<m\\0<j<n}}ams
\succ
\succapproxams
\succcurlyeqams
\succeq
\succnapproxams
\succneqqams
\succnsimams
\succsimams
\sum
\supsup
\supetexvc extension
\Supsetams
\supsetams
\supseteq
\supseteqqams
\supsetneqams
\supsetneqqams
\surd
\swarrow
-

T

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\tage=mc2(hi)\tag{hi} e=mc^2 \label{tag1}ams
\tag*e=mc2hey\tag*{hey} e=mc^2ams
\tantan
\tanhtanh
\TauΤ
\tauτ
\tbinom(nk)\tbinom n kams
\TeXTEX
\text yes & no \text{ yes }\&\text{ no }
\textasciitilde~\text{\textasciitilde}
\textasciicircum^\text{\textasciicircum}
\textbackslash\\text{\textbackslash}
\textbar|\text{\textbar}
\textbardbl\text{\textbardbl}
\textbf𝐀𝐚𝐁𝐛𝟏\textbf{AaBb123}
\textbraceleft{\text{\textbraceleft}
\textbraceright}\text{\textbraceright}
\textbullet\text{\textbullet}
\textcircledNot supported
\textcolorF=ma\textcolor{blue}{F=ma}color
\textdagger\text{\textdagger}
\textdaggerdbl\text{\textdaggerdbl}
\textdegree°\text{\textdegree}
\textdollar$\text{\textdollar}
\textellipsis\text{\textellipsis}
\textemdash\text{\textemdash}
\textendash\text{\textendash}
\texteuro\text{\texteuro}
\textgreater>\text{\textgreater}
\textit𝐴𝑎𝐵𝑏\textit{AaBb}
\textless<\text{\textless}
\textmdAaBb123\textmd{AaBb123}
\textnormalAB\textnormal{AB}
\textquotedblleft\text{\textquotedblleft}
\textquotedblright\text{\textquotedblright}
\textquoteleft\text{\textquoteleft}
\textquoteright\text{\textquoteright}
\textregistered®\text{\textregistered}
\textrmAaBb123\textrm{AaBb123}
\textscʜᴇʏ\textsc{hey}
\textsf𝖠𝖺𝖡𝖻𝟣\textsf{AaBb123}
\textslNot supported
\textsterling£\text{\textsterling}
\textstyle0n\textstyle\sum_0^n
\texttiphover here\texttip{\text{hover here}}
{This is a tooltip.}
MathJax
\texttt𝙰𝚊𝙱𝚋𝟷\texttt{AaBb123}
\textunderscore_\text{\textunderscore}
\textupAaBb123\textup{AaBb123}
\textvisiblespace\text{\textvisiblespace}
\tfracab\tfrac abams
\tgtg
\thth
\thereforeams
\ThetaΘ
\thetaθ
\thetasymϑtexvc extension
\thickapproxams
\thicksimams
\thickspaceaba\thickspace bams
\thinspaceaba\thinspace bams
\tildeM~\tilde M
\times×
\TinyTiny\Tiny Tiny
\tinytiny\tiny tiny
\to
\toggleClick meHey!Ow!\toggle{\text{Click me}}
{Hey!}{Ow!}\endtoggle
MathJax
\top
\TrTrρ\Tr\rhophysics extension
\trtrρ\tr\rhophysics extension
\triangle
\triangledownams
\triangleleft
\trianglelefteqams
\triangleqams
\triangleright
\trianglerighteqams
\tt𝙰𝚊𝙱𝚋𝟷𝟸𝟹{\tt AaBb123}
\twoheadleftarrowams
\twoheadrightarrowams
-

U

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\u a˘\text{\u{a}}
\Uarr texvc extension
\uArr texvc extension
\uarr texvc extension
\ulcorner ams
\underbar X_\underbar{X}
\underbrace x++xn times\underbrace{x+⋯+x}_{n\text{ times}}
\underbracket Not supported
\undergroup AB\undergroup{AB}MnSymbol
\underleftarrow AB\underleftarrow{AB}ams
\underleftrightarrow AB\underleftrightarrow{AB}ams
\underrightarrow AB\underrightarrow{AB}ams
\underline a long argument_\underline{\text{a long argument}}
\underlinesegment Not supported
\underparen abc\underparen{abc}
\underrightarrow AB\underrightarrow{AB}
\underset =!\underset{!}{=}AMS
\unicode Not supported See \char
\unlhd ams
\unrhd ams
\up Not supported
\upalpha αupgreek
\Uparrow
\uparrow
\upbeta βupgreek
\updelta δupgreek
\upchi χupgreek
\Updownarrow
\updownarrow
\upeta ηupgreek
\upepsilon ϵupgreek
\upgamma γupgreek
\upharpoonleft ams
\upharpoonright ams
\upiota ιupgreek
\upkappa κupgreek
\uplambda λupgreek
\upmu μupgreek
\upnu νupgreek
\upomega ωupgreek
\upomicron οupgreek
\uplus upgreek
\upphi ϕupgreek
\uppi πupgreek
\uppsi ψupgreek
\uprho ρupgreek
\uproot Not supported
\upshape Not supported
\upsigma σupgreek
\Upsilon Υ
\upsilon υ
\uptau τupgreek
\uptheta θupgreek
\upuparrows ams
\upupsilon υupgreek
\upxi ξupgreek
\upzeta ζupgreek
\urcorner ams
\url 𝚑𝚝𝚝𝚙𝚜://𝚝𝚎𝚖𝚖𝚕.𝚘𝚛𝚐/\url{https://temml.org/}
Requires trust option
\utilde AB~\utilde{AB}undertilde
-

V

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\vaˇ\text{\v{a}}
\va𝒂\va{a}physics extension
\varδphysics extension
\varcoppaϙ
\varclubsuittxfonts
\varDelta𝛥ams
\vardiamondsuittxfonts
\varepsilonε
\varGamma𝛤ams
\varheartsuittxfonts
\variationδphysics extension
\varinjlimlim\varinjlimams
\varkappaϰams
\varLambda𝛬ams
\varliminflim_\varliminfams
\varlimsuplim_\varlimsupams
\varnothingøams
\varointclockwise
\varOmega𝛺ams
\varPhi𝛷ams
\varphiφ
\varPi𝛱ams
\varpiϖ
\varprojlimlim\varprojlimams
\varproptoams
\varPsi𝛹ams
\varrhoϱ
\varSigma𝛴ams
\varsigmaς
\varspadesuittxfonts
\varstigmaNot supported
\varsubsetneq⊊︀ams
\varsubsetneqq⫋︀ams
\varsupsetneqams
\varsupsetneqq⫌︀ams
\varTheta𝛩ams
\varthetaϑ
\vartriangleams
\vartriangleleftams
\vartrianglerightams
\varUpsilon𝛶ams
\varXi𝛯ams
\vb𝒂\vb{a}physics extension
\vcentcolon:
\vcenterNot supported
\Vdashams
\vDashams
\vdash
\vdotphysics extension
\vdots
\vecF\vec{F}
\vectorarrow𝒂\vectorarrow{a}physics extension
\vectorbold𝒂\vectorbold{a}physics extension
\vectorunit𝒂^\vectorunit{a}physics extension
\vee
\veebarams
\veeeqstix
\verb\frac a b\verb!\frac a b!
\Vert
\vert|
\vfilNot supported
\vfillNot supported
\vlineNot supported
{Vmatrix}abcd\begin{Vmatrix}
   a & b \\
   c & d
\end{Vmatrix}
ams
{Vmatrix*}1324\begin{Vmatrix*}[r]
   -1 & 3 \\
   2 & -4
\end{Vmatrix*}
mathtools
{vmatrix}|abcd|\begin{vmatrix}
   a & b \\
   c & d
\end{vmatrix}
ams
{vmatrix*}|1324|\begin{vmatrix*}[r]
   -1 & 3 \\
   2 & -4
\end{vmatrix*}
mathtools
\vphantomMa_\overline{\vphantom{M}a}
\vqty|x|\vqty{x}physics extension
\vu𝒂^\vu{a}physics extension
\Vvdashams
-

W

- - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\wedge
\wedgeq stix
\weierp texvc extension
\widecheck ABˇ\widecheck{AB}mathabx
\widehat AB^\widehat{AB}
\wideparen abc\wideparen{abc}MnSymbol
\widetilde AB~\widetilde{AB}
\with &cmll
\wn ?cmll
\wp
\wr
-

X

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function Rendered Source or Comment Package
\xcancel ABC\xcancel{ABC}cancel
\xdef Not supported
\Xi Ξ
\xi ξ
\xhookleftarrow abc\xhookleftarrow{abc}mathtools
\xhookrightarrow abc\xhookrightarrow{abc}mathtools
\xLeftarrow abc\xLeftarrow{abc}mathtools
\xleftarrow abc\xleftarrow{abc}ams
\xleftharpoondown abc\xleftharpoondown{abc}mathtools
\xleftharpoonup abc\xleftharpoonup{abc}mathtools
\xLeftrightarrow abc\xLeftrightarrow{abc}mathtools
\xleftrightarrow abc\xleftrightarrow{abc}mathtools
\xleftrightharpoons abcabc\xleftrightharpoons{abc}mathtools
\xlongequal =abc\xlongequal{abc}extpfeil
\xmapsto abc\xmapsto{abc}mathtools
\xRightarrow abc\xRightarrow{abc}mathtools
\xrightarrow abc\xrightarrow{abc}ams
\xrightharpoondown abc\xrightharpoondown{abc}mathtools
\xrightharpoonup abc\xrightharpoonup{abc}mathtools
\xrightleftharpoons abcabc\xrightleftharpoons{abc}mathtools
\xtofrom abcabc\xtofrom{abc}extpfeil
\xtwoheadleftarrow abc\xtwoheadleftarrow{abc}extpfeil
\xtwoheadrightarrow abc\xtwoheadrightarrow{abc}extpfeil
-

YZ

- - - - - - - - - -
Function Rendered Source or Comment Package
\yen ¥ams
\Z texvc extension
\Zeta Ζ
\zeta ζ
-
-

Copyright © 2021, 2022 Ron Kok. Released under the MIT License

-
-
- -
- - - - -
- - - diff --git a/site/docs/en/supported.html b/site/docs/en/supported.html deleted file mode 100644 index a5b3dafe..00000000 --- a/site/docs/en/supported.html +++ /dev/null @@ -1,751 +0,0 @@ - - - - - - Temml Functions - - - - - - -
-

Supported Functions

-

Temml is a JavaScript library that converts TeX math-mode functions to MathML. This page lists the TeX functions it supports, sorted into logical groups.

-

To read this page, use a browser that supports MathML, such as Firefox or Safari. Chrome and Edge will support MathML soon.

-

There is a similar Support Table, sorted alphabetically, that lists both supported and some un-supported functions.

-

Accents

- - - - - - - - - - - - - -
a a'a~ \tilde{a}ac~ \widetilde{ac}
a a''F \vec{F}AB~ \utilde{AB}
a a^{\prime}AB \overleftarrow{AB}AB \overrightarrow{AB}
aˊ \acute{a} AB \underleftarrow{AB}AB \underrightarrow{AB}
y \bar{y} AB_ \overline{AB}AB \Overrightarrow{AB}
a˘ \breve{a} AB_ \underline{AB}AB \overleftrightarrow{AB}
aˇ \check{a} acˇ \widecheck{ac}AB \underleftrightarrow{AB}
a˙ \dot{a} ac \overleftharpoon{ac}ac \overrightharpoon{ac}
a¨ \ddot{a} AB \overgroup{AB}AB \wideparen{AB}
a \dddot{a} AB \undergroup{AB}AB \overparen{AB}
a \ddddot{a}X_ \underbar{X}AB \underparen{AB}
a` \grave{a} g˚ \mathring{g}AB \overbrace{AB}
θ^ \hat{\theta}ac^ \widehat{ac}AB \underbrace{AB}
-

Accent functions inside \text{…}

- - - -
aˊ \'{a}a˜ \~{a}a˙ \.{a}a˝ \H{a}
aˋ \`{a}aˉ \={a}a¨ \"{a}aˇ \v{a}
aˆ \^{a}a˘ \u{a}a˚ \r{a}c¸ \c{c}
-

See also letters

-

Annotation

- - - - - - - - -
5 \cancel{5} a+b+cnote \overbrace{a+b+c}^{\text{note}}
5 \bcancel{5} a+b+cnote \underbrace{a+b+c}_{\text{note}}
ABC \xcancel{ABC} x+10 \cancelto{0}{x+1}
abc \sout{abc} π=cd \boxed{\pi=\frac c d}
\ref{tag1} hover here \texttip{\text{hover here}}{This is a tooltip.}`
Click meHey!Ow! \toggle{\text{Click me}}{Hey!}{Ow!}\endtoggle
x+y2x(hi)\tag{hi} x+y^{2x} \label{tag1}
x+y2xbye\tag*{bye} x+y^{2x}
-

Also some environments have automatic equation numbering.

-

A \label{…} may be placed anywhere and will create an HTML id matching the \label{…} argument. That argument may contain only the characters A-Za-z0-9_-.

-

On sites where Temml fields are updated dynamically, \ref{…} may not be supported. Other Temml functions update only the local field. \ref{…} must make two passes through the entire document. Some sites may choose not to do this.

-

Color

- - - - - -
F=ma {\color{blue} F=ma}F=ma {\color[RGB]{255,0,255} F=ma}
F=ma \textcolor{blue}{F=ma}F=ma {\color[rgb]{1,0,1} F=ma}
F=ma \textcolor{#228B22}{F=ma}F=ma {\color[HTML]{ff00ff} F=ma}
A \colorbox{aqua}{A}\definecolor{sortaGreen}{RGB}{128,128,0}
F=ma {\color{sortaGreen} F=ma}
A \fcolorbox{red}{aqua}{A}
-

\definecolor functions can be included in a preamble. If so, their color definitions will have document-wide scope.

-

Color functions can all take an optional argument to set the color model, as in the xcolor package. (Exception: \definecolor’s model argument is required.) Temml supports color models HTML, RGB, and rgb.

-

If the color model is omitted, Temml color functions will accept:

-
  • #rrggbb, #rgb, or rrggbb.
  • -
  • A color name previously created by \definecolor.
  • -
  • Any color from the following xcolor table.
  • -
  • Any of the standard HTML predefined color names.
  • -
-
- - - - - - - - - - - - - - - - - - - - - -
  Apricot  ForestGreen  olive  RoyalPurple
  Aquamarine  Fuchsia  OliveGreen  RubineRed
  Bittersweet  Goldenrod  orange  Salmon
  blue  gray  Orange  SeaGreen
  Blue  Gray  OrangeRed  Sepia
  BlueGreen  green  Orchid  SkyBlue
  BlueViolet  Green  Peach  SpringGreen
  BrickRed  GreenYellow  Periwinkle  Tan
  brown  JungleGreen  PineGreen  teal
  Brown  Lavender  pink  TealBlue
  BurntOrange  lightgray  Plum  Thistle
  CadetBlue  lime  ProcessBlue  Turquoise
  CarnationPink  LimeGreen  purple  violet
  Cerulean  magenta  Purple  Violet
  CornflowerBlue  Magenta  RawSienna  VioletRed
  cyan  Mahogany  red  WildStrawberry
  Cyan  Maroon  Red  yellow
  Dandelion  Melon  RedOrange  Yellow
  darkgray  MidnightBlue  RedViolet  YellowGreen
  DarkOrchid  Mulberry  Rhodamine  YellowOrange
  Emerald  NavyBlue  RoyalBlue
-

Delimiters

- - - - - - - - -
( ) ( ) ( ) \lparen
     \rparen
  ⌈ ⌉   \lceil
      \rceil
\uparrow
[ ] [ ] [ ] \lbrack
     \rbrack
  ⌊ ⌋   \lfloor
      \rfloor
\downarrow
{} \{ \} {} \lbrace
     \rbrace
⎰⎱ \lmoustache
     \rmoustache
\updownarrow
  ⟨ ⟩   \langle
      \rangle
  ⟮ ⟯   \lgroup
      \rgroup
\Uparrow
| | | \vert ┌ ┐ \ulcorner
     \urcorner
\Downarrow
\| \Vert └ ┘ \llcorner
     \lrcorner
\Updownarrow
| | \lvert
     \rvert
  \lVert
      \rVert
\left. \right. \ \backslash
<> \lt
           \gt
  ⟦ ⟧   \llbracket
     \rrbracket
  \lBrace \rBrace
-

The texvc extension includes \lang and \rang.

-

Delimiter Sizing

-

(AB) \left(\LARGE{AB}\right)

-

((((( ( \big( \Big( \bigg( \Bigg(

- - - - -
\left\big\bigl\bigm\bigr
\middle\Big\Bigl\Bigm\Bigr
\right\bigg\biggl\biggm\biggr
\Bigg\Biggl\Biggm\Biggr
-

Environments

- - - - - - -
abcd\begin{matrix}
   a & b \\
   c & d
\end{matrix}
   ab   cd\begin{array}{cc}
   a & b \\
   c & d
\end{array}
(abcd)\begin{pmatrix}
   a & b \\
   c & d
\end{pmatrix}
[abcd]\begin{bmatrix}
   a & b \\
   c & d
\end{matrix}
|abcd|\begin{vmatrix}
   a & b \\
   c & d
\end{vmatrix}
abcd\begin{Vmatrix}
   a & b \\
   c & d
\end{Vmatrix}
{abcd} \begin{Bmatrix}
   a & b \\
   c & d
\end{Bmatrix}
abcdefghi \def\arraystretch{1.5}
\begin{array}{c|c:c}
   a & b & c \\ \hline
   d & e & f \\
   \hdashline
   g & h & i
\end{array}
x={aif bcif dx = \begin{cases}
   a &\text{if } b \\
   c &\text{if } d
\end{cases}
aif bcif d}\begin{rcases}
   a &\text{if } b \\
  c &\text{if } d
\end{rcases}⇒
abcd \begin{smallmatrix}
   a & b \\
   c & d
\end{smallmatrix}
iΛ0<j<n\sum_{\begin{subarray}{l}
   i\in\Lambda\\
   0<j<n
\end{subarray}}
-

The auto-render extension will render the following environments even if they are not inside math delimiters such as $$…$$. They are display-mode only.

-
- - - -
a=b+c=e+f\begin{equation}
\begin{split}
   a &=b+c\\
   &=e+f
\end{split}
\end{equation}
a=b+cd+e=f \begin{align}
   a&=b+c \\
   d+e&=f
\endalign
a=be=b+c\begin{gather}
   a=b \\
   e=b+c
\end{gather}
10x+3y=23x+13y=4\begin{alignat}{2}
   10&x+ &3&y = 2 \\
   3&x+&13&y = 4
\end{alignat}
AaBbcC=D\begin{CD}
A @>a>> B \\
@VbVV @AAcA \\
C @= D
\end{CD}
unodostres\begin{multline}
   \rm uno \\
   \rm dos \\
   \rm tres
\end{multline}
-

Other Temml Environments

- - - - - - - -
EnvironmentsHow they differ from those shown above
darray, dcases, drcases… apply displaystyle
matrix*, pmatrix*, bmatrix*
Bmatrix*, vmatrix*, Vmatrix*
… take an optional argument that sets column
alignment, as in \begin{matrix*}[r]
equation*, gather*
align*, alignat*
… have no automatic numbering.
gathered, aligned, alignedat … do not need to be in display mode.
… have no automatic numbering.
… must be inside math delimiters in
order to be rendered by the auto-render
extension.
-

Acceptable horizontal line separators are: \\ and \cr.

-

Temml supports \tag{…}, \notag, and \nonumber to modify equation numbering.

-

The {array} environment does not yet support \cline or \multicolumn.

-

HTML

-

The following "raw HTML" features are potentially dangerous for untrusted inputs, so they are disabled by default, and attempting to use them produces the command names in red (which you can configure via the errorColor option). To fully trust your LaTeX input, you need to pass an option of trust: true; you can also enable just some of the commands or for just some URLs via the trust option.

- - - - - - - -
TEMML\href{https://temml.org/}{\Temml}
𝚑𝚝𝚝𝚙𝚜://𝚝𝚎𝚖𝚖𝚕.𝚘𝚛𝚐/\url{https://temml.org/}
sphere\includegraphics[height=1em,
totalheight=1.2em,width=1.2em, alt=sphere]
{../sphere.jpg}
x\id{idName}{x}
x\class{class-name}{x}
x\style{color: red;}{x}
x\data{datum1=a, datum2=b}{x}
-

Letters

-

Greek Letters

- - - - - - - - - - - - - - - - - - - - - -
Α \AlphaΒ \BetaΓ \GammaΔ \DeltaΕ \Epsilon
Ζ \ZetaΗ \EtaΘ \ThetaΙ \IotaΚ \Kappa
Λ \LambdaΜ \Mu Ν \Nu Ξ \Xi Ο \Omicron
Π \PiΡ \RhoΣ \SigmaΤ \TauΥ \Upsilon
Φ \PhiΧ \ChiΨ \PsiΩ \Omega𝛤 \varGamma
𝛥 \varDelta𝛩 \varTheta𝛬 \varLambda𝛯 \varXi 𝛱 \varPi
𝛴 \varSigma𝛶 \varUpsilon𝛷 \varPhi𝛹 \varPsi𝛺 \varOmega
α \alphaβ \betaγ \gammaδ \deltaϵ \epsilon
ζ \zetaη \etaθ \thetaι \iotaκ \kappa
λ \lambda`μ \mu ν \nu ξ \xi ο \omicron
π \piρ \rhoσ \sigmaτ \tauυ \upsilon
ϕ \phiχ \chiψ \psiω \omega
α \upalphaβ \upbetaγ \upgammaδ \updeltaϵ \upepsilon
ζ \upzetaη \upetaθ \upthetaι \upiotaκ \upkappa
λ \uplambdaμ \upmu ν \upnu ξ \upxi ο \upomicron
π \uppi ρ \uprhoσ \upsigmaτ \uptau υ \upupsilon
ϕ \upphi χ \upchiψ \uppsi ω \upomega
ε \varepsilonϰ \varkappaϑ \varthetaϖ \varpi ϱ \varrho
ς \varsigmaφ \varphiϘ \Coppa ϙ \coppa Ϟ \Koppa
ϟ \koppa Ϡ \Sampiϡ \sampi Ϛ \Stigmaϛ \stigma
ϝ \digammaϙ \varcoppa
-

Direct Input: Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω - α β γ δ ϵ ζ η θ ι κ λ μ ν ξ o π ρ σ τ υ ϕ χ ψ ω ε ϑ ϖ ϱ ς φ ϝ

-

Other Letters

- - - - - - -
\aleph \nablaı \imatha˚ \text{\aa}Œ \text{\OE}
\beth \partialȷ \jmath \text{\AA} ø \text{\o}
\gimel \Game \Imæ \text{\ae}Ø \text{\O}
\daleth \Finv𝕜 \BbbkÆ \text{\AE}ß \text{\ss}
ð \eth \hbar \Reœ \text{\oe}ı \text{\i}
\ell \hslash \wp ȷ \text{\j}
-

Letters in the texvc extension

- - - -
\alef \Complex \natnums \real \weierp
\alefsym \image \R \realsϑ \thetasym
\cnums \N \Reals \Z
-

Direct Input: ∂ ∇ ℑ Ⅎ ℵ ℶ ℷ ℸ ⅁ ℏ ð À Á Â Ã Ä Å Æ Ç È É Ê Ë -Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ù Ú Û Ü Ý Þ ß à á â ã ä å ç è é ê ë ì í î ï ð ñ ò ó ô ö ù ú û ü ý þ ÿ - ₊ ₋ ₌ ₍ ₎ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₐ ₑ ₕ ᵢ ⱼ ₖ ₗ ₘ ₙ ₒ ₚ ᵣ ₛ ₜ ᵤ ᵥ ₓ ᵦ ᵧ ᵨ ᵩ ᵪ ⁺ ⁻ ⁼ ⁽ ⁾ ⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ᵃ ᵇ ᶜ ᵈ ᵉ ᵍ ʰ ⁱ ʲ ᵏ ˡ ᵐ ⁿ ᵒ ᵖ ʳ ˢ ᵗ ᵘ ʷ ˣ ʸ ᶻ ᵛ ᵝ ᵞ ᵟ ᵠ ᵡ

-

Math-mode Unicode (sub|super)script characters will render as if you had written regular characters in a subscript or superscript. For instance, A²⁺³ will render the same as A^{2+3}.

-

Unicode Mathematical Alphanumeric Symbols

- - - - - - - - - - -
Item Range Item Range
Bold 𝐀-𝐙 𝐚-𝐳 𝟎-𝟗Double-struck 𝔸-ℤ 𝕒-𝕫 𝟘-𝟡
Italic 𝐴-𝑍 𝑎-𝑧Sans serif 𝖠-𝖹 𝖺-𝗓 𝟢-𝟫
Bold Italic 𝑨-𝒁 𝒂-𝒛Sans serif bold 𝗔-𝗭 𝗮-𝘇 𝟬-𝟵
Fractur 𝔄-ℨ𝔞-𝔷Sans serif italic 𝘈-𝘡 𝘢-𝘻
Monospace 𝙰-𝚉 𝚊-𝚣 𝟶-𝟿Sans serif bold italic 𝘼-𝙕 𝙖-𝙯
-

Any character can be written with the \char function and the Unicode code in hex. For example \char"263a will render as .

-
-
For chancery or roundhand characters, it’s probably best to use \mathcal and \mathscr instead of Unicode input.
Why? -

Unicode has historically accepted either chancery or roundhand glyphs in the range U+1D49C—U+1D4B5. That's confusing, -because Cambria Math has chancery in those code points and some other math fonts have roundhand in the same code points. -Unicode 14 has recently added code points that resolve the ambiguity. Both chancery and roundhand still occupy the same range, but each unambigous chancery character has a \ufe00 appended to the code point and each unambigous roundhand character has a \ufe01 appended to the code point.

-

Published fonts have not yet caught up to the new code point assignments. If you want your documents to not break in the future, it’s probably best to avoid Unicode input and stick with \mathcal and \mathscr.

-
-
-

Layout

-

Line Breaks

-

Hard line breaks are \\ and \newline.

-

If the rendering options do not include annotations, Hurmet will write MathML with soft line breaks after relations and binary operators. These soft line breaks will appear only in Firefox. Chromium and Safari do not support soft line breaks.

-

Vertical Layout

- - - - -
xn x_n=! \stackrel{!}{=}abc a\raisebox{0.25em}{b}c
ex e^x=! \overset{!}{=}MM2M M\raise3pt{M^2}M
uo _u^o=! \underset{!}{=}MM2M M\lower3pt{M^2}M
ab a \atop b
- -
0<i<m0<j<n\sum_{\substack{0<i<m\\0<j<n}}
-

LaTeX puts the second argument of \raisebox into text mode, but it can contain math if the math is nested within $…$ delimiters, as in \raisebox{0.25em}{$\frac a b$}

-

Overlap and Spacing

- - -
= {=}\mathllap{/\,}(x2) \left(x^{\smash{2}}\right)
= \mathrlap{\,/}{=}y \sqrt{\smash[b]{y}}
- -
1ijnxij\sum\_{\mathclap{1\le i\le j\le n}} x\_{ij}
-

Temml also supports \llap, \rlap, and \clap. They work only in text mode if the rendering options include strict: true.

-

Spacing

- - - - - - - - - - - - - - - - - - - -
Function Produces Function Produces
\,³∕₁₈ em space \kern{distance}space, width = distance
\thinspace³∕₁₈ em space \mkern{distance}space, width = distance
\>⁴∕₁₈ em space \mskip{distance}space, width = distance
\:⁴∕₁₈ em space \hskip{distance}space, width = distance
\medspace⁴∕₁₈ em space \hspace{distance}space, width = distance
\;⁵∕₁₈ em space \hspace*{distance}space, width = distance
\thickspace⁵∕₁₈ em space \phantom{content}space the width and height of content
\enspace½ em space \hphantom{content}space the width of content
\quad1 em space \vphantom{content}a strut the height of content
\qquad2 em space \!– ³∕₁₈ em space
~non-breaking space \negthinspace– ³∕₁₈ em space
\<space>space \negmedspace– ⁴∕₁₈ em space
\nobreakspacenon-breaking space \negthickspace– ⁵∕₁₈ em space
\spacespace
-

Notes:

-

distance will accept any of the Temml units.

-

\kern\mkern, \mskip, and \hskip accept unbraced distances, as in: \kern1em.

-

\mkern and \mskip will not work in text mode and both will write a console warning for any unit except mu.

-

\rule{}{distance} is valuable as a vertical strut.

-

Logic and Set Theory

- - - - - - - - -
\forall \complement \therefore \emptyset
\exists \subset \becauseø \varnothing
\nexists \supset \mapsto \implies
\in| \mid \to \impliedby
\ni \land \gets \iff
\notin \lor \leftrightarrow \lightning
\notni ¬ \neg or \lnot{x|x<12}
\Set{ x | x<\frac 1 2 }
{x|x<5}
\set{x|x<5}
\strictif \strictfi
-

Linear Logic (from the cmll package):

- - - - -
Operators ! \oc? \wn& \with \parr
\shpos \shneg \shift \invamp
Relations \coh \scoh \Perp \multimapboth
\incoh \sincoh \multimapinv
-

Equivalents in the texvc extension

- -
\exist \isin \empty \sub
-

Direct Input: ∀ ∴ ∁ ∵ ∃ ∣ ∈ ∉ ∋ ⊂ ⊃ ∧ ∨ ↦ → ← ↔ ∅ ⟹ ⟺ ¬ ↯ ⥼ ⥽
ℂ ℍ ℕ ℙ ℚ ℝ

-

Macros

- - - - - - - -
a2b3+c2d3 \def\macroname<arg list>{definition to be expanded}
\def\foo#1#2{#1^2 #2^3}
\foo a b + \foo c d
\edef\macroname#1#2…{definition}
\let\foo=\bar
\futurelet\foo\bar x
a2b3+c2d3 \newcommand\macroname[numargs]{definition}
\newcommand\foo[2]{#1^2 #2^3}
\foo a b + \foo c d
\renewcommand\macroname[numargs]{definition}
\providecommand\macroname[numargs]{definition}
-

To create macros with document-wide scope, a preamble can be defined as one of the Temml rendering options

-

Macros accept up to nine arguments: #1, #2, etc.

-

Available functions include:

-

\char \mathchoice \TextOrMath \@ifstar \@ifnextchar \@firstoftwo \@secondoftwo \relax \expandafter \noexpand

-

@ is a valid character for commands, as if \makeatletter were in effect.

-

Temml macros do not escape their group, so \gdef, \xdef, and\global are not supported. Temml has no \par, so \long is ignored.

-

Numbers

-

Temml’s default mode will consolidate a string of numerals into a single MathML <mn> element. This applies to any string that begins and ends with a digit (0-9) and includes digits, commas, or dots. Example: <mn>2,000.00</mn>.

-

In strict mode, Temml acts like LaTeX and treats each digit individually. This is not as nice semantically, but it does maintain backwards compatibility for LaTeX macros.

-

Operators

-

Big Operators

- - - - - - - - - -
\sum \prod \bigotimes \bigvee
\int \coprod \bigoplus \bigwedge
\iint \intop \bigodot \bigcap
\iiint \smallint \biguplus \bigcup
\iiiint \intcap \intcup \bigsqcup
\oint \varointclockwise \intclockwise \bigsqcap
\oiint \pointint \rppolint \scpolint
\oiiint \intlarhk \sqint \intx
\intbar \intBar \fint cdab \sideset{_a^b}{_c^d}\sum
-

Direct Input: ∫ ∬ ∭ ⨌ ∮ ∯ ∰ ⨖ ∲ ∏ ∐ ∑ ⋀ ⋁ ⋂ ⋃ ⨀ ⨁ ⨂ ⨄ ⨆ ⨅

-

Binary Operators

- - - - - - - - - - - - - - - - - - -
+ + \cdot \gtrdot x(moda) x \pmod -a
- · \cdotp \intercalx(a) x \pod a
/ \centerdot \land \rhd
* * \circ \leftthreetimes \rightthreetimes
⨿ \amalg \circledast. \ldotp \rtimes
& \And \circledcirc \lor \setminus
\ast \circleddash \lessdot \smallsetminus
\barwedge \Cup \lhd \sqcap
\bigcirc \cup \ltimes \sqcup
mod \bmod \curlyveexmoda x\mod a × \times
\boxdot \curlywedge \mp \unlhd
\boxminus÷ \div \odot \unrhd
\boxplus \divideontimes \ominus \uplus
\boxtimes \dotplus \oplus \vee
\bullet \doublebarwedge \otimes \veebar
\Cap \doublecap \oslash \wedge
\cap \doublecup \parr & \with
± \pm \wr
-

The texvc extension provides ± \plusmn.

-

Direct Input: + - / ∖ * ⋅ ∘ ± × ÷ ∓ ∔ ∧ ∨ ∩ ∪ ≀ ⊎ ⊓ ⊔ ⊕ ⊖ ⊗ ⊘ ⊙ ⊚ ⊛ ⊝ ◯

-

Fractions and Binomials

- - - -
ab \frac{a}{b}ab \tfrac{a}{b}(aa+1] \genfrac ( ] {2pt}{1}a{a+1}
ab {a \over b}ab \dfrac{a}{b}ab+1 {a \above{2pt} b+1}
ab a/b a1+1b \cfrac{a}{1 + \cfrac{1}{b}}
- - -
(nk) \binom{n}{k}(nk) \dbinom{n}{k}{nk} {n\brace k}
(nk) {n \choose k}(nk) \tbinom{n}{k}[nk] {n\brack k}
-

Math Operators

- - - - - - - - - - - - - - - -
f \operatorname{f}cosec \cosec dim \dim 2xyf \pdv*{f}{x,y}
arcsin \arcsincosh \coshexp \expsec \sec
arccos \arccoscot \cothom \homsgn \sgn
arctan \arctancotg \cotgker \kersin \sin
arctg \arctgcoth \cothlg \lgsinh \sinh
arcctg \arcctgcsc \cscln \lnsh \sh
arg \argctg \ctg log \logtan \tan
ch \chcth \cthdfdx \odv{f}{x}tanh \tanh
cos \cos \nabladdxf \odv*{f}{x}tg \tg
\partialdeg \deg2fxy \pdv{f}{x,y}th \th
f \operatorname*{f} or
\operatornamewithlimits
inf \inf max \max sup \sup
argmax \argmax injlim \injlim min \min lim \varinjlim
argmin \argmin lim \lim plim \plim lim_ \varliminf
det \det liminf \liminf Pr \Pr lim_ \varlimsup
gcd \gcd limsup \limsup projlim \projlim lim \varprojlim
-

Functions in the bottom five rows of this table can take \limits.

-

Enclosing Operators

- - - -
x \sqrt{x}3x2+2x+5 \longdiv{3x^2 + 2x + 5}
x3 \sqrt[3]{x}78 \phase{-78^\circ}
an   a_{\angl n}an   a_\angln
-

Physics and Chemistry

- - - - -
ϕ| \bra{\phi} 𝐂25+a2 \prescript{a}{2}{\mathbf{C}}^{5+}_{2}
|ψ \ket{\psi} ϕ|ψ \braket{\phi\vert\psi}
ϕ| \Bra{\phi} ϕ|2t2|ψ
\Braket{ \phi | \frac{\partial^2}{\partial t^2} | \psi }
|ψ \Ket{\psi}
-

From the mhchem extension:

- - -
SO42+Ba2+BaSO4\ce{SO4^2- + Ba^2+ -> BaSO4 v}
75.3 JmolK\pu{75.3 J // mol K}
-

There is much more mhchem information in the -mhchem docs.

-
-
Click to see the physics extension. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|x| \abs{x} a|b \innerproduct{a}{b}if \qif
|x| \absolutevalue{x}|ab| \ketbra{a}{b}in \qin
{A,B} \acomm{A}{B} 2 \laplacianinteger \qinteger
{A,B} \anticommutator{A}{B}n|A|m \matrixel{n}{A}{m}let \qlet
{5mm} \Bqty{5 \text{mm}}n|A|m \matrixelement{n}{A}{m}odd \qodd
[5mm] \bqty{5 \text{mm}}n|A|m \mel{n}{A}{m}or \qor
[A,B] \comm{A}{B} x \norm{x} otherwise \qotherwise
[A,B] \commutator{A}{B}|ab| \op{a}{b}  text  \qq{text}
× \cp 𝒪(x2) \order{x^2} text  \qqtext{text}
× \cross |ab| \outerproduct{a}{b}since \qsince
× \crossproductxy \partialderivative{x}{y}then \qthen
𝛁× \curl {x,y} \pb{x}{y} {5m} \qty{5 \text{m}}
d \dd {5m} \quantity{5 \text{m}}
dxdy \derivative{x}{y}{A,B} \poissonbracket{A}{B}unless \qunless
d \differential(5) \pqty{5} using \qusing
𝛁 \divergence 𝒫 \principalvaluerankM \rank M
\dotproduct 𝒫 \pv Res[f(z)] \Res\[f(z)\]
dxdy \dv{x}{y}P.V.(x) \PV(x)Trρ \Tr\rho
|ab| \dyad{a}{b}all \qalltrρ \tr\rho
erf(x) \erf(x)and \qand𝒂 \va{a}
x \ev{x}as \qasδ \var
12x|0n \eval{\tfrac 1 2 x}_0^nassume \qassume δ \variation
12x|0n \evaluated{\tfrac 1 2 x}_0^n, \qc 𝒂 \vb{a}
x \expectationvalue{x}c.c. \qcc \vdot
x \expval{x} , \qcomma 𝒂 \vectorarrow{a}
δxδy \fdv{x}{y} else \qelse 𝒂 \vectorbold{a}
δxδy \functionalderivative{x}{y}even \qeven 𝒂^ \vectorunit{a}
𝛁 \gradfor \qfor|x| \vqty{x}
𝛁 \gradientgiven \qgiven𝒂^ \vu{a}
-
-

Relations

-

=!ab \stackrel{!}{=}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
= = \eqcirc \lesseqqgtr \smallsmile
< < \eqcolon or
  \minuscolon
\lessgtr \smile
> > −∷ \Eqcolon or
   \minuscoloncolon
\lesssim \sqsubset
: : \eqqcolon \ll \sqsubseteq
:= := =∷ \Eqqcolon \lll \sqsupset
\approx \eqdef \llless \sqsupseteq
\approxeq \eqsim < \lt \stareq
\arceq \eqslantgtr \measeq \Subset
\asymp \eqslantless| \mid \subset
\backcong \equiv \models \subseteq
\backepsilon \fallingdotseq \multimap \subseteqq
\backsim \frown \multimapboth \succ
\backsimeq \ge \multimapinv \succapprox
\between \geq \origof \succcurlyeq
\bowtie \geqq \owns \succeq
\bumpeq \geqslant \parallel \succsim
\Bumpeq \gg \perp \Supset
\circeq \ggg \Perp \supset
\coh \gggtr \pitchfork \supseteq
: \colonapprox> \gt \prec \supseteqq
∷≈ \Colonapprox or
   \coloncolonapprox
\gtrapprox \precapprox \thickapprox
: \coloneq or
   \colonminus
\gtreqless \preccurlyeq \thicksim
∷− \Coloneq or
   \coloncolonminus
\gtreqqless \preceq \trianglelefteq
\coloneqq or
   \colonequals
\gtrless \precsim \triangleq
\Coloneqq or
    \coloncolonequals
\gtrsim \propto \trianglerighteq
: \colonsim \imageof \questeq \varpropto
: \Colonsim or
   \coloncolonsim
\in or \isin :\ratio or
  \vcentcolon
\vartriangle
\cong \incoh \risingdotseq \vartriangleleft
\curlyeqprec \Join \scoh \vartriangleright
\curlyeqsucc \le \shortmid \vdash
\dashv \leq \shortparallel \vDash
\dblcolon or
   \coloncolon
\leqq \sim \Vdash
\doteq \leqslant \simeq \Vvdash
\Doteq \lessapprox \sincoh \veeeq
\doteqdot \lesseqgtr \smallfrown \wedgeq
-

The texvc extension provides \sub, \sube, and \supe.

-

Direct Input: = < > : ∈ ∋ ∝ ∼ ∽ ≂ ≃ ≅ ≈ ≊ ≍ ≎ ≏ ≐ ≑ ≒ ≓ ≖ -≗ ≜ ≡ ≤ ≥ ≦ ≧ ≫ ≬ ≳ ≷ ≺ ≻ ≼ ≽ ≾ ≿ ⊂ ⊃ ⊆ ⊇ ⊏ ⊐ ⊑ ⊒ ⊢ ⊣ ⊩ ⊪ ⊸ ⋈ ⋍ ⋐ ⋑ ⋔ ⋙ -⋛ ⋞ ⋟ ⌢ ⌣ ⩾ ⪆ ⪌ ⪕ ⪖ ⪯ ⪰ ⪷ ⪸ ⫅ ⫆ ≲ ⩽ ⪅ ≶ ⋚ ⪋ ⟂ ⊨ ≔ ≕ ⩴ ⊷ ⊶

-

Negated Relations

-

\not =

- - - - - - - - - - - - - - - -
\gnapprox \ngeqslant \nsubset \nVdash
\gneq \ngtr \nsubseteq \precnapprox
\gneqq \nleq \nsubseteqq \precneqq
\gnsim \nleqq \nsucc \precnsim
≩︀ \gvertneqq \nleqslant \nsucceq \subsetneq
\lnapprox \nless \nsupset \subsetneqq
\lneq \nmid \nsupseteq \succnapprox
\lneqq \notin \nsupseteqq \succneqq
\lnsim \notni \ntriangleleft \succnsim
≨︀ \lvertneqq \nparallel \ntrianglelefteq \supsetneq
\ncong \nprec \ntriangleright \supsetneqq
\ne \npreceq \ntrianglerighteq⊊︀ \varsubsetneq
\neq \nshortmid \nvdash ⫋︀ \varsubsetneqq
\ngeq \nshortparallel \nvDash \varsupsetneq
\ngeqq \nsim \nVDash ⫌︀ \varsupsetneqq
-

Direct Input: ∉ ∌ ∤ ∦ ≁ ≆ ≠ ≨ ≩ ≮ ≯ ≰ ≱ ⊀ ⊁ ⊄ ⊅ ⊈ ⊉ ⊊ ⊋ ⊬ ⊭ -⊮ ⊯ ⋠ ⋡ ⋦ ⋧ ⋨ ⋩ ⋬ ⋭ ⪇ ⪈ ⪉ ⪊ ⪵ ⪶ ⪹ ⪺ ⫋ ⫌

-

Arrows

- - - - - - - - - - - - - - - - - - - - - - - - - -
\circlearrowleft \Leftrightarrow \rightarrow
\circlearrowright \leftrightarrows \Rightarrow
\curvearrowleft \leftrightharpoons \rightarrowtail
\curvearrowright \leftrightsquigarrow \rightharpoondown
\dashleftarrow \Lleftarrow \rightharpoonup
\dashrightarrow \longleftarrow \rightleftarrows
\downarrow \Longleftarrow \rightleftharpoons
\Downarrow \longleftrightarrow \rightrightarrows
\downdownarrows \Longleftrightarrow \rightsquigarrow
\downharpoonleft \longmapsto \Rrightarrow
\downharpoonright \longrightarrow \Rsh
\gets \Longrightarrow \searrow
\hookleftarrow \looparrowleft \swarrow
\hookrightarrow \looparrowright \to
\iff \Lsh \twoheadleftarrow
\impliedby \mapsto \twoheadrightarrow
\implies \nearrow \uparrow
\leadsto \nleftarrow \Uparrow
\leftarrow \nLeftarrow \updownarrow
\Leftarrow \nleftrightarrow \Updownarrow
\leftarrowtail \nLeftrightarrow \upharpoonleft
\leftharpoondown \nrightarrow \upharpoonright
\leftharpoonup \nRightarrow \upuparrows
\leftleftarrows \nwarrow
\leftrightarrow \restriction
-

Arrows in the texvc extension

- - - -
\Darr \Harr \Larr \Lrarr \Rarr \Uarr
\dArr \hArr \lArr \lrArr \rArr \uArr
\darr \harr \larr \lrarr \rarr \uarr
-

Direct Input: ← ↑ → ↓ ↔ ↕ ↖ ↗ ↘ ↙ ↚ ↛ ↞ ↠ ↢ ↣ ↦ ↩ ↪ ↫ ↬ ↭ ↮ ↰ ↱↶ ↷ ↺ ↻ ↼ ↽ ↾ ↾ ↿ ⇀ ⇁ ⇂ ⇃ ⇄ ⇆ ⇇ ⇈ ⇉ ⇊ ⇋ ⇌⇍ ⇎ ⇏ ⇐ ⇑ ⇒ ⇓ ⇔ ⇕ ⇚ ⇛ ⇝ ⇠ ⇢ ⟵ ⟶ ⟷ ⟸ ⟹ ⟺ ⟼ ↽

-

Extensible Arrows

- - - - - - - - - - -
abc \xleftarrow{abc}underover \xrightarrow[under]{over}
abc \xLeftarrow{abc}abc \xRightarrow{abc}
abc \xleftrightarrow{abc}abc \xLeftrightarrow{abc}
abc \xhookleftarrow{abc}abc \xhookrightarrow{abc}
abc \xtwoheadleftarrow{abc}abc \xtwoheadrightarrow{abc}
abc \xleftharpoonup{abc}abc \xrightharpoonup{abc}
abc \xleftharpoondown{abc}abc \xrightharpoondown{abc}
abcabc \xleftrightharpoons{abc}abcabc \xrightleftharpoons{abc}
abcabc \xtofrom{abc}abc \xmapsto{abc}
=abc \xlongequal{abc}
-

All extensible arrows can take an optional argument in the same manner as \xrightarrow[under]{over}.

-

Style, Size, and Font

-

Class Assignment

-

Override the usual spacing and semantic meaning of a character or fragment.

- -
a=b  a = b
a=b  a \mathord{=} b
a=b  a \mathopen{=} b
a=b  a \mathclose{=} b
a|b  a | b
a|b  a \mathpunct{|} b
a|b  a \mathop{|} b
a|b  a \mathbin{|} b
a|b  a \mathrel{|} b
-

See also \operatorname.

-

Font

- - - - - - - - - - - -
Ab0 \mathrm{Ab0}𝐀𝐛𝟎𝛉 \mathbf{Ab0θ}Ab0θ \mathit{Ab0θ}
Ab0 \mathnormal{Ab0}𝐀𝐛𝟎𝛉 \textbf{Ab0θ} 𝐴𝑏𝑏0𝜃 \textit{Ab0θ}
Ab0θ \textrm{Ab0θ}𝐀𝐛𝟎𝛉 {\bf Ab0θ} Ab0θ {\it Ab0θ}
Ab0 {\rm Ab0}𝐀𝐛𝟎𝛉 \bold{Ab0θ}Ab0θ \textup{Ab0θ}
Ab0θ \textnormal{Ab0θ}𝑨𝒃0𝜽 \boldsymbol{Ab0θ}𝔸𝕓𝟘 \Bbb{Ab0}
Ab0θ \text{Ab0θ}𝑨𝒃0𝜽 \bm{Ab0θ}𝔸𝕓𝟘 \mathbb{Ab0}
𝖠𝖻𝟢 \mathsf{Ab0}Ab0θ \textmd{Ab0θ}𝔄𝔟 \frak{Ab}
𝖠𝖻𝟢 \textsf{Ab0}𝙰𝚋𝟶 \mathtt{Ab0}𝔄𝔟 \mathfrak{Ab}
𝖠𝖻𝟢 {\sf Ab0}𝙰𝚋𝟶 \texttt{Ab0}𝒜 \mathcal{AB}
ʜᴇʏ \textsc{hey}𝙰𝚋𝟶 {\tt Ab0 }𝒜 {\cal AB}
123 \oldstylenums{123}𝒜 \mathscr{AB}
-

The \textXX versions can stack font family, font weight, and font shape. So \textsf{\textbf{H}} will produce 𝗛. The other versions do not stack, e.g., \mathsf{\mathbf{H}} will produce 𝐇.

-

In cases where math fonts do not have a bold glyph, \pmb can simulate one. For example, \pmb{\vartheta} renders as : ϑ

-

Font Size

- - - - - - -
AB \Huge ABAB \normalsize AB
AB \huge ABAB \small AB
AB \LARGE ABAB \footnotesize AB
AB \Large ABAB \scriptsize AB
AB \large ABAB \Tiny AB
AB \tiny AB
-

Style

- - - - - - - - -
i=1n\displaystyle\sum_{i=1}^n
i=1n\textstyle\sum_{i=1}^n
x\scriptstyle x     (The size of a first sub/superscript)
x\scriptscriptstyle x (The size of subsequent sub/superscripts)
limyx\lim\limits_y x
limyx\lim\nolimits_y x
x^2\verb!x^2!
ABcd ABcd\text{ABcd $ABcd$}
-

\text{…} shifts its contents into text mode, but you can shift back into math mode by nesting $…$.

-

Symbols and Punctuation

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
% comment \dotsTEX \TeX
% \% \cdotsLATEX \LaTeX
# \# \ddotsTEMML \Temml
& \& \ldots \rule[6pt]{2ex}{1ex}
_ \_ \vdots \surd
_ \text{\textunderscore} \iddots \infty
\text{--} \dotsb \checkmark
\text{\textendash} \dotsc \ballotx
\text{---} \dotsi \dagger or \dag
\text{\textemdash} \dotsm \text{\textdagger}
~ \text{\textasciitilde} \dotso \ddagger or \ddag
^ \text{\textasciicircum} \idotsin \text{\textdaggerdbl}
` \mathellipsis \angle
text{\textquoteleft} \text{\textellipsis} \measuredangle
\lq \Box \sphericalangle
\text{\textquoteright} \square \top
\rq \blacksquare \bot
\text{\textquotedblleft} \triangle \Bot
" " \triangledown$ \$
\text{\textquotedblright} \triangleleft$ \text{\textdollar}
: \colon \triangleright£ \pounds
\backprime \bigtriangledown£ \mathsterling
\prime \bigtriangleup£ \text{\textsterling}
< \text{\textless} \blacktriangle¥ \yen
> \text{\textgreater} \blacktriangledown \euro
| \text{\textbar} \blacktriangleleft \text{\texteuro}
\text{\textbardbl} \blacktriangleright° \degree
{ \text{\textbraceleft} \diamond ° \text{\textdegree}
} \text{\textbraceright} \Diamond \mho
\ \text{\textbackslash} \lozenge \diagdown
\text{\textvisiblespace} \blacklozenge \diagup
\text{\P} or \P \star \flat
§ \text{\S} or \S \bigstar \natural
© \copyright \maltese \sharp
® \circledR \clubsuit \varclubsuit
\circledS \diamondsuit \vardiamondsuit
® \text{\textregistered} \heartsuit \varheartsuit
\text{\textbullet} \spadesuit \varspadesuit
\smiley \female \male
\standardstate \lightning \permil
-

Symbols in the texvc extension

- - - -
\clubs \hearts \sdot
\diamonds \spades \infin
\bull§ \text{\sect} \Dagger
-

Direct Input: § ¶ £ ¥ € ∇ ∞ · ∠ ∡ ∢ ♠ ♡ ♢ ♣ ♭ ♮ ♯ © ® ☺ ✓ ↯ … ⋮ ⋯ ⋱ ! ‼

-

Units

- - - - - - - - - - - - -
Unit Value Unit Value
em CSS em bp 1/72​ inch
ex CSS ex pc 12 pt
mu 1/18 em dd 1238/1157​ pt
pt 1/72.27 inch cc 14856/1157 pt
mm 1 mm nd 685/642 pt
cm 1 cm nc 1370/107​ pt
in 1 inch sp 1/65536 pt
-

The effect of script level and font size:

- - - - - - - - -
Unit textstyle
normal size
scriptscript huge
em or ex
mu
others
-

em and ex are affected by font size changes such as \Large, but they are not affected by script level, so they will not change size in a fraction numerator or an exponent.

-

mu is affected by both script level and font size.

-

The other units are absolute and are not affected by either script level or font size.

-
-

Copyright © 2021, 2022 Ron Kok. -Released under the MIT License

-
-
- - - - - diff --git a/site/docs/katex.css b/site/docs/katex.css deleted file mode 100644 index 73bb33e6..00000000 --- a/site/docs/katex.css +++ /dev/null @@ -1,11 +0,0 @@ -.katex .eqn-num::before { - counter-increment: katexEqnNo; - content: "(" counter(katexEqnNo) ")"; -} -.katex .mml-eqn-num::before { - counter-increment: mmlEqnNo; - content: "(" counter(mmlEqnNo) ")"; -} -body { - counter-reset: katexEqnNo mmlEqnNo tmlEqnNo; -} diff --git a/site/docs/sphere.jpg b/site/docs/sphere.jpg deleted file mode 100644 index d5f063a4..00000000 Binary files a/site/docs/sphere.jpg and /dev/null differ diff --git a/site/index.html b/site/index.html deleted file mode 100644 index d97077d6..00000000 --- a/site/index.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - -Temml - Convert TeX to MathML - - - - - - - - - - - - -
- - -

- TEMML -

- -
-
-

A TeX-to-MathML conversion library in JavaScript.

- -

- -
-
- -
- - -
-
-
- -
- -
-
- CBdl=μ0(Ienc+ε0ddtSEn^da) -
-
-
- -
-
-
-
- -     - -   -
- -   -    -   - -
-
- -
-
    -
  • Fast
  • -
  • Lightweight
  • -
  • Extensive LaTeX coverage
  • -
  • Thoroughly - - - Mozilla tests - Wikipedia tests - mhchem tests - LaTeXML tests - -
  • -
  • Works in browser or server-side with Node.js
  • -
  • No dependencies
  • -
  • Use any math font
  • -
  • MathML is supported by Firefox and partly supported by Safari.
    - It will soon be supported by Chrome, Edge, Opera, and Brave.
  • -
-
-
- -
- - - - - - - diff --git a/site/indexStyles.css b/site/indexStyles.css deleted file mode 100644 index 88321280..00000000 --- a/site/indexStyles.css +++ /dev/null @@ -1,200 +0,0 @@ -* { margin:0; } /* reset */ - -body { - margin: 0 0 5px; - line-height: 1.45; - background: white; - font-family: Calibri, 'Helvetica Neue', Arial, Cambria, sans-serif; - font-size: 18px; - position: relative; -} - -nav { - max-width: 800px; - margin: 0 auto; - background: #fff; - font-size: 16px; - height: 66px -} - -nav * { - font-family: Arial, sans-serif; -} - -nav ul { - list-style: none; - margin: 0; - padding: 0; - float: right; -} - -nav ul li { - display: block; - float: right; - padding-top: 27px; - text-decoration: none -} - -nav a { - padding: 33px 0 0 18px; - text-decoration: none; - color: inherit; -} - -article, #title { - max-width: 800px; - margin: 0 auto; -} - -#demo { - margin: 0px 2.5px 0px 2.5px; - overflow: fixed; -} - -h1 { - font-family: Verdana, sans-serif; - font-variant: small-caps; - letter-spacing: 0.05em; - margin-top: 3em; - font-size: 140%; - margin-top: 1em; -} - -p { - margin-top: 1em; - line-height: 1.35; - text-align: justify; -} - -#why { - width: 70%; - margin-top: 2em; - margin-left: auto; - margin-right: auto; -} - -#why ul li { - list-style-type: disc; - line-height: 1.35; - margin-top: 0.5em; - position: relative; - left: 1.8em; -} - -a { - text-decoration: underline; - color: black; -} - -#demo-parent { - width: 100%; -} - -#demo { - width: 100%; - display: flex; - flex-direction: row; - flex-wrap: wrap; -} - -.wide #demo { - flex-direction: column; -} - -#input, -#output { - width: 395px; - flex-basis: auto; -} - -.wide #input, -.wide #output { - width: 100%; -} - -#spacer { - width: 10px; -} - -.ioArea { - font-size: 0.9em; - width: 360px; - height: 10em; - border-radius: 4px; - border: 1px solid rgb(200, 200, 200); - display: inline-block; - padding: 1em 1em; - vertical-align: top; - resize: none; - overflow: auto; -} - -.wide .ioArea { - width: 760px; -} - -math { - font-size: 115%; -} - -#demoSource { - font-family: Consolas, Menlo, Monaco, monospace; -} - -#notice { - margin-top: 2em; - color:rgb(182, 32, 32); -} - -@media (max-width: 799px){ - nav { - width: 90%; - } - article, #input, #output, #title, #copyright { - width: 100%; - } - .ioArea { - width: 93% - } - #why ul { padding-inline-start: 0; } -} - -#copyright { - max-width: 800px; - margin: 0 auto; - font-family: Arial, sans-serif; - font-size: 10px; - text-align: center; -} - -#copyright a { - color: inherit; -} - -.dropdown { - position: relative; - display: inline-block; -} - -.dropbtn { - background-color: #d3d3d3; - padding: 4px; - border: none; - cursor: pointer; -} - -.dropdown-content { - display: none; - position: absolute; - background-color: #f9f9f9; - min-width: 160px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - padding: 12px 16px; - z-index: 1; -} - -.dropdown a { text-decoration: none; } - -.dropdown:hover .dropdown-content { - display: block; -} \ No newline at end of file diff --git a/site/mathml.css b/site/mathml.css deleted file mode 100644 index af84a2d7..00000000 --- a/site/mathml.css +++ /dev/null @@ -1,218 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - - /* This file is a backup for browsers that do not support MathML. - * Hopefully, it will get very little use. - */ - -/* See https://github.com/fred-wang/mathml.css */ - -@namespace "http://www.w3.org/1998/Math/MathML"; - -/* math */ -math { - display: inline; - text-indent: 0; -} -math[display="block"] { - display: block; - text-align: center; -} - -/* fraction */ -mfrac { - display: inline-block !important; - vertical-align: -50%; - border-collapse: collapse; - text-align: center; -} -mfrac > * { - display: block !important; -} -mfrac > * + * { - display: inline-block !important; - vertical-align: top; -} -mfrac:not([linethickness="0"]) > *:first-child { - border-bottom: solid thin; -} - -/* sub/sup scripts */ -msub > *:nth-child(2), msubsup > *:nth-child(2), -mmultiscripts > *:nth-child(2n+2), -mmultiscripts > mprescripts ~ *:nth-child(2n+3) { - font-size: 0.8em; - vertical-align: sub; -} -msup > *:nth-child(2), msubsup > *:nth-child(3), -mmultiscripts > *:nth-child(2n+3), -mmultiscripts > mprescripts ~ *:nth-child(2n+2) { - font-size: 0.8em; - vertical-align: super; -} -mprescripts:after { - content: ";"; -} - -/* under/over scripts */ -munder, mover, munderover { - display: inline-flex !important; - flex-direction: column; -} -munder > *:nth-child(2), munderover > *:nth-child(2) { - font-size: 0.8em; - order: +1; -} -mover > *:nth-child(2), munderover > *:nth-child(3) { - font-size: 0.8em; - order: -1; -} -munder { - vertical-align: text-top; -} -mover { - vertical-align: text-bottom; -} -munderover { - vertical-align: middle; -} - -/* roots */ -msqrt, mroot { - display: inline-flex !important; - margin-left: .6em; - vertical-align: middle; - border-top: solid thin; -} -msqrt:before, mroot:before { - margin-left: -.6em; - content: "\221A"; -} -mroot > *:nth-child(2) { - margin-right: .25em; - margin-left: -.75em; - font-size: 0.8em; - order: -1; -} - -/* menclose */ -menclose { - display: inline-table !important; - border-collapse: separate; - border-spacing: 0.4ex 0; -} -menclose[notation*="top"], menclose[notation*="actuarial"] { - border-top: solid thin; -} -menclose[notation*="bottom"], menclose[notation*="madruwb"] { - border-bottom: solid thin; -} -menclose[notation*="right"], menclose[notation*="actuarial"], -menclose[notation*="madruwb"] { - border-right: solid thin; -} -menclose[notation*="left"] { - border-left: solid thin; -} -menclose[notation*="box"], menclose[notation*="roundedbox"], -menclose[notation*="circle"] { - border: solid thin; -} -menclose[notation*="roundedbox"] { - border-radius: 15%; -} -menclose[notation*="circle"] { - border-radius: 50%; -} -menclose[notation*="horizontalstrike"] { - text-decoration: line-through; -} - -/* table */ -mtable { - display: inline-table !important; - vertical-align: middle; - text-align: center; -} -mtr { - display: table-row !important; -} -mtd { - display: table-cell !important; - padding: 0 0.5ex; -} - -/* token elements */ -mspace { - margin: .2em; -} -mi { - font-style: italic; -} -mo { - margin-right: .2em; - margin-left: .2em; -} -ms:before, ms:after { - content:"\0022"; -} -ms[lquote]:before { - content: attr(lquote); -} -ms[rquote]:after { - content: attr(rquote); -} - -/* mathvariants */ -[mathvariant="bold"], [mathvariant="bold-italic"], -[mathvariant="bold-sans-serif"], [mathvariant="sans-serif-bold-italic"] { - font-weight: bold; - font-style: normal; -} -[mathvariant="monospace"] { - font-family: monospace; - font-style: normal; -} -[mathvariant="sans-serif"], -[mathvariant="bold-sans-serif"], [mathvariant="sans-serif-italic"], -[mathvariant="sans-serif-bold-italic"] { - font-family: sans-serif; - font-style: normal; -} -[mathvariant="italic"], [mathvariant="bold-italic"], -[mathvariant="sans-serif-italic"], [mathvariant="sans-serif-bold-italic"] { - font-style: italic; -} -[mathvariant="normal"] { - font-style: normal; -} - -/* mphantom */ -mphantom { - visibility: hidden; -} - -/* merror */ -merror { - outline: solid thin red; -} -merror:before { - content: "Error: "; -} - -/* annotations */ -semantics > *:first-child { - display: inline; -} -annotation, annotation-xml { - font-family: monospace; - display: none !important; -} -math:active > semantics > *:first-child, -math:active > semantics > *:first-child { - display: none !important; -} -math:active annotation:first-of-type { - display: inline !important; -} \ No newline at end of file diff --git a/site/tests/LaTeXML-tests.html b/site/tests/LaTeXML-tests.html deleted file mode 100644 index 7734160d..00000000 --- a/site/tests/LaTeXML-tests.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - Temml LaTeXML Tests - - - - - - -

LaTeXML Test

-

This LaTeXML test reproduces math examples from https://latexml.mathweb.org/editor
The equations in the first table came originally from http://www.mathjax.org/demos/tex-samples/, which no longer exists.

-

Equations

- - - - - - - - - - - - - - - - - - -
SourceTemml
The Lorenz Equations
1 \begin{aligned}
\dot{x} & = \sigma(y-x) \\
\dot{y} & = \rho x - y - xz \\
\dot{z} & = -\beta z + xy
\end{aligned}
x˙=σ(yx)y˙=ρxyxzz˙=βz+xy
The Cauchy-Schwarz Inequality
2 \left( \sum_{k=1}^n ak bk \right)^2
\leq \left( \sum_{k=1}^n ak^2 \right)
\left( \sum_{k=1}^n bk^2 \right) \
(k=1nakbk)2(k=1nak2)(k=1nbk2)
A Cross Product Formula
3 \mathbf{V}_1 \times \mathbf{V}_2 =
\begin{vmatrix}
\mathbf{i} & \mathbf{j} & \mathbf{k} \\
\frac{\partial X}{\partial u} &
\frac{\partial Y}{\partial u} & 0 \\
\frac{\partial X}{\partial v} &
\frac{\partial Y}{\partial v} & 0
\end{vmatrix}
𝐕1×𝐕2=|𝐢𝐣𝐤XuYu0XvYv0|
The probability of getting k heads when flipping n coins is:
4P(E) = {n \choose k} p^k (1-p)^{ n-k} \P(E)=(nk)pk(1p)nk
An Identity of Ramanujan
5 \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-
\phi\Bigr) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}}
{1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } }
1(ϕ5ϕ)e25π=1+e2π1+e4π1+e6π1+e8π1+
A Rogers-Ramanujan Identity
6 1 + \frac{q^2}{(1-q)}+
\frac{q^6}{(1-q)(1-q^2)}+\cdots =
\prod_{j=0}^{\infty}\frac{1}
{(1-q^{5j+2})(1-q^{5j+3})},
\quad\quad \text{for} |q|<1.
1+q2(1q)+q6(1q)(1q2)+=j=01(1q5j+2)(1q5j+3),for|q|<1.
Maxwell's Equations
7 \begin{aligned}
\nabla \times \vec{\mathbf{B}} -\\,
\frac1c\, \frac{\partial\vec{
\mathbf{E}}}{\partial t} &
= \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} &
= 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\,
\frac1c\, \frac{\partial\vec{
\mathbf{B}}}{\partial t} &
= \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} &
= 0
\end{aligned} \
×𝐁1c𝐄t=4πc𝐣𝐄=4πρ×𝐄+1c𝐁t=𝟎𝐁=0
-

Boxes

- - - - -
Source Temml
\raisebox{0pt}[0pt][0pt]{\Large%
\textbf{Aaaa\raisebox{-0.3ex}{a}%
\raisebox{-0.7ex}{aa}\raisebox{-1.2ex}{r}%
\raisebox{-2.2ex}{g}\raisebox{-4.5ex}{h}}}
𝐀𝐚𝐚𝐚𝐚𝐚𝐚𝐚𝐚𝐚𝐫𝐠𝐡
-

Unicode

-

The tests below come from https://latexml.mathweb.org/editor
They got them from https://trac.edgewall.org/wiki/TracUnicode
I have no idea what these lines say.

-

All the Unicode characters are written inside \text{}.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Language Temml
Arabic تراك يقوم بحفظ كل الكلمات باستخدام صيغة2
Bulgarian Българският език работи ли?2
Česky Cˇesˇtina v koˊdovaˊnıˊ UTF-8, zˇaˊdnyˊ probleˊm.2
Chinese (Traditional) 繁體中文, 漢字測試2
Chinese (Simplified) 简体中文,汉字测试2
Croatian (Ako podrko podrzˇava srpski i slovenski mora podrzˇavati i Hrvatski - i Hrvatski - cˇcˊzˇsˇđ CˇCˊZˇSˇĐ)
English Yes indeed, Trac supports English. Fully.2
Français Il est possible d’l est possible deˊcrire en Français : aˋ, ç, uˆ, 2
German (Trac-Wiki muß auch deutsche Umlaute richtig anzeigen:o¨, a¨, u¨, A¨, O¨, U¨; und das scharfe ß)
Greek Τα Ελληνικα Ελληνικαˊ υποστηριˊζονται επαρκωˊς επιˊσης.2
Hebrew אני יכול לאכול זכוכית וזה לא מזיק לי2
Hindi अब हिन्दी में।2
Hungarian Aˊrvıˊztu˝ro˝ tu¨ko¨rfuˊroˊgeˊp2
Icelandic Ævar sagði við var sagði við o¨mmu sıˊna: Sjaˊðu hvað eˊg er stoˊr!2
Japanese 漢字 ひらがな カタカナ ハンカクカナ 日本語試験2
Korean 이번에는 한글로 써보겠습니다. 잘 보이나요? 한글2
Latvian Latvieatviesˇu valoda arıˉ straˉdaˉ!2
Lithuanian (Sudalyvaukime ir mes. Ar veikia lietuviudalyvaukime ir mes. Ar veikia lietuvisˇkos raide˙s?ącˇęe˙įsˇųuˉzˇ ĄCˇĘE˙ĮSˇŲUˉZˇ Zˇinoma, kad veikia :) Kas tie mes?)
Persian (Farsi) (ولی امکان نوشتن مستقیم فارسی نیست چون حالت متن از راست به چپ و جوداین یک متن فارسی است ندارد برای فارسی نوشتن باید از HTML استفاده کنید.)
Polish (Pchnąchnącˊ w tę łoˊdzˊ jez˙a lub osiem skrzynˊ fig;Nocna gocna gz˙egz˙oˊłka zawsze dzienną przekuka.)
Portuguese (Eˊ possıˊvel guardar caracteres especias da lıˊngua portuguesa, incluindo o sncluindo o sıˊmbolo da moeda europeˊia , trema u¨, crase aˋ, agudos aˊeˊıˊoˊuˊ,circunflexos ’ircunflexos aˆeˆoˆ, til a˜o˜, cedilha ç, ordinais ªº, grau °¹²³.)
Russian (Проверка русского языка: кажется работает... И буква "ё" есть...2
Serbian (Podrodrzˇan, uprkos cˇinjenici da se za njegovopisanje koriste чак два алфабета.)
Slovenian Ta suhi a suhi sˇkafec pusˇcˇa vodo zˇe od nekdaj!2
Spanish (Esto es un pequesto es un pequen˜o texto en Espan˜ol,donde el veloz murcionde el veloz murcieˊlago hinduˊ comıˊa cardlllo y kiwi)
Swedish Ra¨ven raskar o¨ver isen med luva pa˚.2
Thai Trac แสดงภาษาไทยได้อย่างถูกต้อง!2
Ukrainian Перевірка української мови...2
Urdu ٹریک اردو بھی سپورٹ کرتا ہے۔2
Vietnamese Viieˆˊt tieˆˊng Vit cu˜ng đưc.2
-
- - diff --git a/site/tests/images/AccentsText.svg b/site/tests/images/AccentsText.svg deleted file mode 100644 index 8020e45e..00000000 --- a/site/tests/images/AccentsText.svg +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/ArrayMode.svg b/site/tests/images/ArrayMode.svg deleted file mode 100644 index 683d1aa9..00000000 --- a/site/tests/images/ArrayMode.svg +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/ArrayType.svg b/site/tests/images/ArrayType.svg deleted file mode 100644 index ca29097d..00000000 --- a/site/tests/images/ArrayType.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/Arrays.svg b/site/tests/images/Arrays.svg deleted file mode 100644 index 075bfb7b..00000000 --- a/site/tests/images/Arrays.svg +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/BinCancellation.svg b/site/tests/images/BinCancellation.svg deleted file mode 100644 index 43585d72..00000000 --- a/site/tests/images/BinCancellation.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/BoldSymbol.svg b/site/tests/images/BoldSymbol.svg deleted file mode 100644 index 5a65f027..00000000 --- a/site/tests/images/BoldSymbol.svg +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/CD.svg b/site/tests/images/CD.svg deleted file mode 100644 index fdc49725..00000000 --- a/site/tests/images/CD.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/site/tests/images/ColorBox.svg b/site/tests/images/ColorBox.svg deleted file mode 100644 index 4796accc..00000000 --- a/site/tests/images/ColorBox.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/ColorImplicit.svg b/site/tests/images/ColorImplicit.svg deleted file mode 100644 index b51c9868..00000000 --- a/site/tests/images/ColorImplicit.svg +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/ColorSpacing.svg b/site/tests/images/ColorSpacing.svg deleted file mode 100644 index 0e4eec2c..00000000 --- a/site/tests/images/ColorSpacing.svg +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/DashesAndQuotes.svg b/site/tests/images/DashesAndQuotes.svg deleted file mode 100644 index d1478411..00000000 --- a/site/tests/images/DashesAndQuotes.svg +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/DelimiterSizing1.svg b/site/tests/images/DelimiterSizing1.svg deleted file mode 100644 index 5eef3f3c..00000000 --- a/site/tests/images/DelimiterSizing1.svg +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/DelimiterSizing2.svg b/site/tests/images/DelimiterSizing2.svg deleted file mode 100644 index d56576cf..00000000 --- a/site/tests/images/DelimiterSizing2.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/DisplayMode.svg b/site/tests/images/DisplayMode.svg deleted file mode 100644 index 40c7d930..00000000 --- a/site/tests/images/DisplayMode.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/ExtensibleArrows.svg b/site/tests/images/ExtensibleArrows.svg deleted file mode 100644 index 5fac9045..00000000 --- a/site/tests/images/ExtensibleArrows.svg +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/Fractions1.svg b/site/tests/images/Fractions1.svg deleted file mode 100644 index 07a80f1c..00000000 --- a/site/tests/images/Fractions1.svg +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/Fractions2.svg b/site/tests/images/Fractions2.svg deleted file mode 100644 index cd42d03a..00000000 --- a/site/tests/images/Fractions2.svg +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/HorizontalBraces.svg b/site/tests/images/HorizontalBraces.svg deleted file mode 100644 index a304a034..00000000 --- a/site/tests/images/HorizontalBraces.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/Integrands.svg b/site/tests/images/Integrands.svg deleted file mode 100644 index 77ccc388..00000000 --- a/site/tests/images/Integrands.svg +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/LargeRuleNumerator.svg b/site/tests/images/LargeRuleNumerator.svg deleted file mode 100644 index 6dc12522..00000000 --- a/site/tests/images/LargeRuleNumerator.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/LeftRight.svg b/site/tests/images/LeftRight.svg deleted file mode 100644 index 55f59eec..00000000 --- a/site/tests/images/LeftRight.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/LeftRightListStyling.svg b/site/tests/images/LeftRightListStyling.svg deleted file mode 100644 index 505f0e76..00000000 --- a/site/tests/images/LeftRightListStyling.svg +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/LeftRightMiddle.svg b/site/tests/images/LeftRightMiddle.svg deleted file mode 100644 index 8ae04751..00000000 --- a/site/tests/images/LeftRightMiddle.svg +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/LeftRightStyleSizing.svg b/site/tests/images/LeftRightStyleSizing.svg deleted file mode 100644 index 10caa36b..00000000 --- a/site/tests/images/LeftRightStyleSizing.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/LimitControls.svg b/site/tests/images/LimitControls.svg deleted file mode 100644 index 6c2bbf40..00000000 --- a/site/tests/images/LimitControls.svg +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/MathChoice.svg b/site/tests/images/MathChoice.svg deleted file mode 100644 index 1e7a205c..00000000 --- a/site/tests/images/MathChoice.svg +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/MathtoolsMatrix.svg b/site/tests/images/MathtoolsMatrix.svg deleted file mode 100644 index 4304daf3..00000000 --- a/site/tests/images/MathtoolsMatrix.svg +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/NegativeSpace.svg b/site/tests/images/NegativeSpace.svg deleted file mode 100644 index a7fa46c8..00000000 --- a/site/tests/images/NegativeSpace.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/NestedFractions.svg b/site/tests/images/NestedFractions.svg deleted file mode 100644 index 3c82194b..00000000 --- a/site/tests/images/NestedFractions.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/NullDelimiterInteraction.svg b/site/tests/images/NullDelimiterInteraction.svg deleted file mode 100644 index db3d62eb..00000000 --- a/site/tests/images/NullDelimiterInteraction.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/OpLimits.svg b/site/tests/images/OpLimits.svg deleted file mode 100644 index 585914c8..00000000 --- a/site/tests/images/OpLimits.svg +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/OperatorName.svg b/site/tests/images/OperatorName.svg deleted file mode 100644 index 1b6fd3be..00000000 --- a/site/tests/images/OperatorName.svg +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/OverUnderline.svg b/site/tests/images/OverUnderline.svg deleted file mode 100644 index 3865b737..00000000 --- a/site/tests/images/OverUnderline.svg +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/OverUnderset.svg b/site/tests/images/OverUnderset.svg deleted file mode 100644 index 16b105fa..00000000 --- a/site/tests/images/OverUnderset.svg +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/PrimeSpacing.svg b/site/tests/images/PrimeSpacing.svg deleted file mode 100644 index 1575dfa6..00000000 --- a/site/tests/images/PrimeSpacing.svg +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/PrimeSuper.svg b/site/tests/images/PrimeSuper.svg deleted file mode 100644 index 009ce817..00000000 --- a/site/tests/images/PrimeSuper.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/RelativeUnits.svg b/site/tests/images/RelativeUnits.svg deleted file mode 100644 index 68f44547..00000000 --- a/site/tests/images/RelativeUnits.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/SizingBaseline.svg b/site/tests/images/SizingBaseline.svg deleted file mode 100644 index a5a2207c..00000000 --- a/site/tests/images/SizingBaseline.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/SqrtRoot.svg b/site/tests/images/SqrtRoot.svg deleted file mode 100644 index 636858dd..00000000 --- a/site/tests/images/SqrtRoot.svg +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/StretchyAccent.svg b/site/tests/images/StretchyAccent.svg deleted file mode 100644 index a44f996f..00000000 --- a/site/tests/images/StretchyAccent.svg +++ /dev/null @@ -1,385 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/StrikeThrough.svg b/site/tests/images/StrikeThrough.svg deleted file mode 100644 index 721dce43..00000000 --- a/site/tests/images/StrikeThrough.svg +++ /dev/null @@ -1,337 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/StrikeThroughColor.svg b/site/tests/images/StrikeThroughColor.svg deleted file mode 100644 index df033b99..00000000 --- a/site/tests/images/StrikeThroughColor.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/StyleSpacing.svg b/site/tests/images/StyleSpacing.svg deleted file mode 100644 index 45c03462..00000000 --- a/site/tests/images/StyleSpacing.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/StyleSwitching.svg b/site/tests/images/StyleSwitching.svg deleted file mode 100644 index fd2de68c..00000000 --- a/site/tests/images/StyleSwitching.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/SupSubCharacterBox.svg b/site/tests/images/SupSubCharacterBox.svg deleted file mode 100644 index 755711fc..00000000 --- a/site/tests/images/SupSubCharacterBox.svg +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/SupSubHorizSpacing.svg b/site/tests/images/SupSubHorizSpacing.svg deleted file mode 100644 index 7cbcc203..00000000 --- a/site/tests/images/SupSubHorizSpacing.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/SupSubLeftAlignReset.svg b/site/tests/images/SupSubLeftAlignReset.svg deleted file mode 100644 index 65be9280..00000000 --- a/site/tests/images/SupSubLeftAlignReset.svg +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/SupSubOffsets.svg b/site/tests/images/SupSubOffsets.svg deleted file mode 100644 index 6b2edf53..00000000 --- a/site/tests/images/SupSubOffsets.svg +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/TextSpace.svg b/site/tests/images/TextSpace.svg deleted file mode 100644 index 01d15c69..00000000 --- a/site/tests/images/TextSpace.svg +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/TextStacked.svg b/site/tests/images/TextStacked.svg deleted file mode 100644 index 734253f0..00000000 --- a/site/tests/images/TextStacked.svg +++ /dev/null @@ -1,405 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/TextWithMath.svg b/site/tests/images/TextWithMath.svg deleted file mode 100644 index a01d94f0..00000000 --- a/site/tests/images/TextWithMath.svg +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/accents.svg b/site/tests/images/accents.svg deleted file mode 100644 index 20942f66..00000000 --- a/site/tests/images/accents.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/align.svg b/site/tests/images/align.svg deleted file mode 100644 index 8df18980..00000000 --- a/site/tests/images/align.svg +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/aligned.svg b/site/tests/images/aligned.svg deleted file mode 100644 index 89dd2bbb..00000000 --- a/site/tests/images/aligned.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/alignedat.svg b/site/tests/images/alignedat.svg deleted file mode 100644 index 2dd5edc9..00000000 --- a/site/tests/images/alignedat.svg +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/angl.svg b/site/tests/images/angl.svg deleted file mode 100644 index b54829e7..00000000 --- a/site/tests/images/angl.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/site/tests/images/baseline.svg b/site/tests/images/baseline.svg deleted file mode 100644 index 92c16ffa..00000000 --- a/site/tests/images/baseline.svg +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/binom.svg b/site/tests/images/binom.svg deleted file mode 100644 index 52ba9ac6..00000000 --- a/site/tests/images/binom.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/boxed.svg b/site/tests/images/boxed.svg deleted file mode 100644 index f7c5d50e..00000000 --- a/site/tests/images/boxed.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/cases.svg b/site/tests/images/cases.svg deleted file mode 100644 index 0517a9a1..00000000 --- a/site/tests/images/cases.svg +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/colors.svg b/site/tests/images/colors.svg deleted file mode 100644 index 7b0dc958..00000000 --- a/site/tests/images/colors.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/displaystyle.svg b/site/tests/images/displaystyle.svg deleted file mode 100644 index d88829f6..00000000 --- a/site/tests/images/displaystyle.svg +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/dots.svg b/site/tests/images/dots.svg deleted file mode 100644 index b8b82d35..00000000 --- a/site/tests/images/dots.svg +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/equation.svg b/site/tests/images/equation.svg deleted file mode 100644 index afd21ac0..00000000 --- a/site/tests/images/equation.svg +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/ex1.gif b/site/tests/images/ex1.gif deleted file mode 100644 index 7d39a37d..00000000 Binary files a/site/tests/images/ex1.gif and /dev/null differ diff --git a/site/tests/images/ex10.gif b/site/tests/images/ex10.gif deleted file mode 100644 index 53938109..00000000 Binary files a/site/tests/images/ex10.gif and /dev/null differ diff --git a/site/tests/images/ex11.gif b/site/tests/images/ex11.gif deleted file mode 100644 index cc6596a0..00000000 Binary files a/site/tests/images/ex11.gif and /dev/null differ diff --git a/site/tests/images/ex12.gif b/site/tests/images/ex12.gif deleted file mode 100644 index f97f1d2f..00000000 Binary files a/site/tests/images/ex12.gif and /dev/null differ diff --git a/site/tests/images/ex13.gif b/site/tests/images/ex13.gif deleted file mode 100644 index fa8405b7..00000000 Binary files a/site/tests/images/ex13.gif and /dev/null differ diff --git a/site/tests/images/ex14.gif b/site/tests/images/ex14.gif deleted file mode 100644 index 2c927bcd..00000000 Binary files a/site/tests/images/ex14.gif and /dev/null differ diff --git a/site/tests/images/ex15.gif b/site/tests/images/ex15.gif deleted file mode 100644 index 63c99884..00000000 Binary files a/site/tests/images/ex15.gif and /dev/null differ diff --git a/site/tests/images/ex16.gif b/site/tests/images/ex16.gif deleted file mode 100644 index 86ced9a6..00000000 Binary files a/site/tests/images/ex16.gif and /dev/null differ diff --git a/site/tests/images/ex17.gif b/site/tests/images/ex17.gif deleted file mode 100644 index f6973e22..00000000 Binary files a/site/tests/images/ex17.gif and /dev/null differ diff --git a/site/tests/images/ex18.gif b/site/tests/images/ex18.gif deleted file mode 100644 index aa1afcb1..00000000 Binary files a/site/tests/images/ex18.gif and /dev/null differ diff --git a/site/tests/images/ex19.gif b/site/tests/images/ex19.gif deleted file mode 100644 index 27b81934..00000000 Binary files a/site/tests/images/ex19.gif and /dev/null differ diff --git a/site/tests/images/ex2.gif b/site/tests/images/ex2.gif deleted file mode 100644 index c0c54b45..00000000 Binary files a/site/tests/images/ex2.gif and /dev/null differ diff --git a/site/tests/images/ex20.gif b/site/tests/images/ex20.gif deleted file mode 100644 index b6a13750..00000000 Binary files a/site/tests/images/ex20.gif and /dev/null differ diff --git a/site/tests/images/ex21.gif b/site/tests/images/ex21.gif deleted file mode 100644 index 04aecd15..00000000 Binary files a/site/tests/images/ex21.gif and /dev/null differ diff --git a/site/tests/images/ex22.gif b/site/tests/images/ex22.gif deleted file mode 100644 index 207568a2..00000000 Binary files a/site/tests/images/ex22.gif and /dev/null differ diff --git a/site/tests/images/ex23.gif b/site/tests/images/ex23.gif deleted file mode 100644 index da8f92e6..00000000 Binary files a/site/tests/images/ex23.gif and /dev/null differ diff --git a/site/tests/images/ex24.gif b/site/tests/images/ex24.gif deleted file mode 100644 index 4f165bd4..00000000 Binary files a/site/tests/images/ex24.gif and /dev/null differ diff --git a/site/tests/images/ex25.gif b/site/tests/images/ex25.gif deleted file mode 100644 index 18d14980..00000000 Binary files a/site/tests/images/ex25.gif and /dev/null differ diff --git a/site/tests/images/ex26.gif b/site/tests/images/ex26.gif deleted file mode 100644 index a9dca4f7..00000000 Binary files a/site/tests/images/ex26.gif and /dev/null differ diff --git a/site/tests/images/ex27.gif b/site/tests/images/ex27.gif deleted file mode 100644 index f4dc0504..00000000 Binary files a/site/tests/images/ex27.gif and /dev/null differ diff --git a/site/tests/images/ex28.gif b/site/tests/images/ex28.gif deleted file mode 100644 index 87c1be08..00000000 Binary files a/site/tests/images/ex28.gif and /dev/null differ diff --git a/site/tests/images/ex29.png b/site/tests/images/ex29.png deleted file mode 100644 index a0fb31c9..00000000 Binary files a/site/tests/images/ex29.png and /dev/null differ diff --git a/site/tests/images/ex3.gif b/site/tests/images/ex3.gif deleted file mode 100644 index bf10c18c..00000000 Binary files a/site/tests/images/ex3.gif and /dev/null differ diff --git a/site/tests/images/ex30.png b/site/tests/images/ex30.png deleted file mode 100644 index e8f75cfb..00000000 Binary files a/site/tests/images/ex30.png and /dev/null differ diff --git a/site/tests/images/ex4.gif b/site/tests/images/ex4.gif deleted file mode 100644 index f2b49256..00000000 Binary files a/site/tests/images/ex4.gif and /dev/null differ diff --git a/site/tests/images/ex5.gif b/site/tests/images/ex5.gif deleted file mode 100644 index 4c3a7b9b..00000000 Binary files a/site/tests/images/ex5.gif and /dev/null differ diff --git a/site/tests/images/ex6.gif b/site/tests/images/ex6.gif deleted file mode 100644 index 679f278f..00000000 Binary files a/site/tests/images/ex6.gif and /dev/null differ diff --git a/site/tests/images/ex7.gif b/site/tests/images/ex7.gif deleted file mode 100644 index 981d6a32..00000000 Binary files a/site/tests/images/ex7.gif and /dev/null differ diff --git a/site/tests/images/ex8.gif b/site/tests/images/ex8.gif deleted file mode 100644 index 016ddab0..00000000 Binary files a/site/tests/images/ex8.gif and /dev/null differ diff --git a/site/tests/images/ex9.gif b/site/tests/images/ex9.gif deleted file mode 100644 index d3a23631..00000000 Binary files a/site/tests/images/ex9.gif and /dev/null differ diff --git a/site/tests/images/exponents.svg b/site/tests/images/exponents.svg deleted file mode 100644 index f1bc8c0f..00000000 --- a/site/tests/images/exponents.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/functions.svg b/site/tests/images/functions.svg deleted file mode 100644 index eb73cbb9..00000000 --- a/site/tests/images/functions.svg +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/gather.svg b/site/tests/images/gather.svg deleted file mode 100644 index b9da20e4..00000000 --- a/site/tests/images/gather.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/greek.svg b/site/tests/images/greek.svg deleted file mode 100644 index dcecf702..00000000 --- a/site/tests/images/greek.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/kern.svg b/site/tests/images/kern.svg deleted file mode 100644 index 663bc3bc..00000000 --- a/site/tests/images/kern.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/lap.svg b/site/tests/images/lap.svg deleted file mode 100644 index 96c9fdf2..00000000 --- a/site/tests/images/lap.svg +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/latex.svg b/site/tests/images/latex.svg deleted file mode 100644 index 3cab59a1..00000000 --- a/site/tests/images/latex.svg +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/mathop.svg b/site/tests/images/mathop.svg deleted file mode 100644 index 5cd5fec6..00000000 --- a/site/tests/images/mathop.svg +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/mod.svg b/site/tests/images/mod.svg deleted file mode 100644 index 50fde308..00000000 --- a/site/tests/images/mod.svg +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/newline.svg b/site/tests/images/newline.svg deleted file mode 100644 index 5cf3127a..00000000 --- a/site/tests/images/newline.svg +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/not.svg b/site/tests/images/not.svg deleted file mode 100644 index f6282dab..00000000 --- a/site/tests/images/not.svg +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/oldfont.svg b/site/tests/images/oldfont.svg deleted file mode 100644 index fa3aefc7..00000000 --- a/site/tests/images/oldfont.svg +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/phantom.svg b/site/tests/images/phantom.svg deleted file mode 100644 index 174f72f4..00000000 --- a/site/tests/images/phantom.svg +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/pmb.svg b/site/tests/images/pmb.svg deleted file mode 100644 index 56f21738..00000000 --- a/site/tests/images/pmb.svg +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/raisebox.svg b/site/tests/images/raisebox.svg deleted file mode 100644 index 1fb62705..00000000 --- a/site/tests/images/raisebox.svg +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/rcases.svg b/site/tests/images/rcases.svg deleted file mode 100644 index b7fcc413..00000000 --- a/site/tests/images/rcases.svg +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/rlapbug.svg b/site/tests/images/rlapbug.svg deleted file mode 100644 index 7bc1588f..00000000 --- a/site/tests/images/rlapbug.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/rule.svg b/site/tests/images/rule.svg deleted file mode 100644 index 0e987fd9..00000000 --- a/site/tests/images/rule.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/site/tests/images/sizing.svg b/site/tests/images/sizing.svg deleted file mode 100644 index fe4dcb37..00000000 --- a/site/tests/images/sizing.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/smash.svg b/site/tests/images/smash.svg deleted file mode 100644 index d0083e45..00000000 --- a/site/tests/images/smash.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/spacing.svg b/site/tests/images/spacing.svg deleted file mode 100644 index ddb3fd6a..00000000 --- a/site/tests/images/spacing.svg +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/sqrt.svg b/site/tests/images/sqrt.svg deleted file mode 100644 index 240c63fa..00000000 --- a/site/tests/images/sqrt.svg +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/stackrel.svg b/site/tests/images/stackrel.svg deleted file mode 100644 index 2409d798..00000000 --- a/site/tests/images/stackrel.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/subarray.svg b/site/tests/images/subarray.svg deleted file mode 100644 index b874f36b..00000000 --- a/site/tests/images/subarray.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/text.svg b/site/tests/images/text.svg deleted file mode 100644 index 8f83ceed..00000000 --- a/site/tests/images/text.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/units.svg b/site/tests/images/units.svg deleted file mode 100644 index db485204..00000000 --- a/site/tests/images/units.svg +++ /dev/null @@ -1,351 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/images/verb.svg b/site/tests/images/verb.svg deleted file mode 100644 index fb31aae7..00000000 --- a/site/tests/images/verb.svg +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/tests/katex-tests.html b/site/tests/katex-tests.html deleted file mode 100644 index 77c04e6c..00000000 --- a/site/tests/katex-tests.html +++ /dev/null @@ -1,382 +0,0 @@ - - - - - - Temml Screen Tests - - - - - - -

Tests from KaTeX

-

This file renders examples from KaTeX’s screenshotter tests.
Images from LaTeX are also provided for comparison.
(Images come from LaTeX Previewer, thanks.)

-

Accents

- - - - - -
SourceTemmlLaTeX
\vec{A}\vec{x}\vec x^2
\vec{x}_2^2 \vec{A}^2
\vec{xA}^2; \underbar{X}
Axx2x22A2xA2X_ accents
-

AccentsText

- -
ıˊı˙ıˋı¨ı˝ı˚ȷˊȷ˙ȷˋȷ¨ȷ˝ȷ˚aˊa˙aˋa¨a˝a˚AˊA˙AˋA¨A˝A˚I˙ I˙e˝ e˝ııAccentsText
-

Actuarial Angle

- -
a_{\angl n}\; a_\anglnananangl
-

Align

- -
\begin{align}
a &= 1 & b &= 2 \\
3a &= 3 & 17b &= 34
\end{align}
a=1b=23a=317b=34
-

Alignat

- -
\begin{alignat}{3}
a &= 1\quad & b &= 2 &\quad c &= 3\\
3a &= 3 &\quad 17b &= 34 &\quad 400c &= 1200
\end{alignat}
a=1b=2c=33a=317b=34400c=1200
-

Aligned

- -
\begin{aligned}
a &= 1 & b &= 2 \\
3a &= 3 & 17b &= 34
\end{aligned}
a=1b=23a=317b=34 aligned
-

Alignedat

- -
\begin{alignedat}{3}
a &= 1\quad & b &= 2 &\quad c &= 3\\
3a &= 3 &\quad 17b &= 34 &\quad 400c &= 1200
\end{alignedat}
a=1b=2c=33a=317b=34400c=1200alignedat
-

Arrays

-

This LaTeX image does include dashed lines.
LaTeX Previewer does not include the arydshln package.

- - -
\left(\begin{array}{|rl:c|} 1&2&3\\ \hline
1+1&2+1&3+1\cr1\over2&\scriptstyle 1/2&\frac 1 2\\
\hdashline
\begin{pmatrix}x\\y\end{pmatrix}&0&
\begin{vmatrix}a&b\\c&d\end{vmatrix}
\end{array}\right]
(1231+12+13+1121212(xy)0|abcd|]Arrays
\begin{smallmatrix} a & b \\ c & d \end{smallmatrix}
\begin{subarray}{c}a \\ b\end{subarray}
abcd absubarray
-

ArrayMode

- -
2fx122fx1x22fx1xn2fx2x12fx222fx2xn2fxnx12fxnx22fxn2ArrayMode
-

ArrayType

- -
1\begin{array}{c}2\\3\end{array}41234ArrayType
-

ArrayRemoveEmptyLine

-

A \\ at the end of a matrix should not create another line.

- -
\begin{pmatrix} 1 \\ 2 \\ \end{pmatrix}(12)
-

Baseline

- -
a+b-c\cdot d/ea+bcdeBaseline
-

BasicTest

-

a

-

BinCancellation

- -
\begin{array}{cccc}
+1 & 1+ & 1+1 & (,) \\
1++1 & 3\times) & 1+, & \left(,\right)
\end{array}
+11+1+1(,)1++13×)1+,(,)BinCancellation
-

Binom

- -
\dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17}(ab)(ab)(ab)+17binom
-

BoldSpacing

- -
\mathbf{A}^2+\mathbf{B}_3*\mathscr{C}'𝐀2+𝐁3*𝒞
-

BoldSymbol

- -
\sum_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}}
\boldsymbol{\omega}+
\boldsymbol{\int_\alpha^\beta}
\boldsymbol{\Omega + {}} \\
\boldsymbol{\lim_{x \to \infty}
\log Ax2k\omega\Omega\imath+} \\
x \boldsymbol{+} y \boldsymbol{=} z
𝜶𝜷𝝎+𝜶𝜷𝛀+lim𝒙log𝑨𝒙2𝒌𝝎𝛀ı+x+y=zBoldSymbol
-

Boxed

- -
\boxed{F=ma} \quad \boxed{ac}
\color{magenta}{\boxed{F}}\boxed{F=mg}
F=maacFF=mgboxed
-

Cases

- - -
f(a,b)=
\begin{cases}
a+1&\text{if }b\text{ is odd} \\
a&\text{if }b=0 \\
a-1&\text{otherwise}
\end{cases}
f(a,b)={a+1if b is oddaif b=0a1otherwisecases
\begin{rcases}
a &\text{if } b \\
c &\text{if } d
\end{rcases}\Rightarrow\ldots
aif bcif d}rcases
-

CD

- -
\begin{CD}
A @<a<< B @>>b> C \\
@| @AcAA @VVdV \\
D @= E @>>> F
\end{CD}
AaBbCcdD=EFCD
-

Colors

- -
\textcolor{#0f0}{b}
\textcolor{red}{c}
bccolors
-

ColorImplicit

- -
bl{ack\color{red}red
\textcolor{green}{green}
red\color{blue}blue}black \\
black\left(black
\color{red}red\right)black
blackredgreenredblueblackblack(blackred)blackColorImplicit
-

ColorSpacing

- -
\textcolor{red}{x} + 1
{\color{green}+ 2 +} 3 + 4
x+1+2+3+4ColorSpacing
-

Colorbox

- -
a \colorbox{teal} B
\fcolorbox{blue}{red}{C}
e+\colorbox{teal}x
aBCe+xColorbox
-

DashesAndQuotes

- -

\begin{array}{l}
\text{``a'' b---c -- d----`e'-{-}-f} -- \\
\text{\it ``a'' b---c -- d----`e'-{-}-f} ``x'' \\
\text{\tt ``a''---} \texttt{``a''---} \mathtt{--}
\end{array}

-

“a” b—c – d—-‘e’---f“𝑎” 𝑏—𝑐 – 𝑑—-‘𝑒’---𝑓x``𝚊''---``𝚊''---

-
DashesAndQuotes
-

DelimiterSizing

- - -
\bigl\uparrow\Bigl\downarrow
\biggl\updownarrow
\Biggl\Uparrow\Biggr\Downarrow
\biggr\langle\Bigr\}\bigr\rfloor
}DelimiterSizing1
\begin{pmatrix}
a & b & c\\
a & b & c\\
a & b & c
\end{pmatrix}
(abcabcabc)DelimiterSizing2
-

DisplayMode

- -
\sum_{i=0}^\infty \frac{1}{i}i=01iDisplayMode
-

DisplayStyle

- -
{\displaystyle\sqrt{x}}{\sqrt{x}}
{\displaystyle \frac 1 2}{\frac 1 2}
{\displaystyle x^1_2}{x^1_2}
xx1212x21x21displaystyle
-

Dots

- -
\begin{array}{l}
\cdots;\dots+\dots\int\dots,\dots \\
\cdots{};\ldots+\ldots\int\ldots,\ldots
\end{array}
;+,;+,dots
-

Equation

- -
\begin{equation}
\begin{split}
a& =b+c-d \\
& \quad +e-f \\
& =g+h \\
& =i
\end{split}
\end{equation}
a=b+cd+ef=g+h=iequation
-

Exponents

- -
a^{a^a_a}_{a^a_a}aaaaaaaexponents
-

ExtensibleArrows

- -
\begin{array}{l}
\xrightarrow[ab]{ABC} +
\xRightarrow{ABC} \\
\xleftrightharpoons[ab]{ABC} +
\xhookrightarrow[ab]{ABC} \\
\xmapsto{ABC} +
\frac{\xrightarrow[ab]{ABC}}
{\xrightarrow[ab]{ABC}} +
\left\lvert\xrightarrow[ab]{ABC}
\right\rvert
\end{array}
abABC+ABCabABCabABC+abABCABC+abABCabABC+|abABC|ExtensibleArrows
-

Fractions

- - -
\dfrac{a}{b}\frac{a}{b}
\tfrac{a}{b}\;-
\dfrac 1 2\;1\tfrac 1 2\;{1 \atop 2}\;
{a \brace b} \; {a \brack b}
ababab1211212{ab}[ab]Fractions1
\genfrac \{ ]{0.8pt}{0}{a}{b}\;
{a \above1.0pt b} \;
\cfrac{1}{1+\cfrac{1}{x}}
\xrightarrow[\dfrac g h]{\displaystyle\frac g h}
\; \xrightarrow [2.\, \dfrac c d]
{1.\, \displaystyle\frac c d}
{ab]ab11+1xghgh2.cd1.cdFractions2
-

Functions

- -
\sin\cos\tan\ln\logsincostanlnlogfunctions
-

Gather

- -
\begin{gather}
a=\frac 1 2 \\
e=b+c
\end{gather}
a=12e=b+cgather
-

GreekLetters

- -
\alpha\beta\gamma\omegaαβγωgreek
-

GreekUnicode

- -
\frac{αβγδεϵζηθϑικλμνξοπϖρϱςστυφϕχψω}
{ΓΔΘΞΠΣΦΨΩϝ\mathbf{Ω}\mathbf{\Omega}}
αβγδεϵζηθϑικλμνξοπϖρϱςστυφϕχψωΓΔΘΞΠΣΦΨΩϝ𝛀𝛀
-

HorizontalBraces

- -
\overbrace{\displaystyle{
\oint_S{\vec E\cdot\hat n\,\mathrm d a}}}^
\text{emf} =
\underbrace{\frac{q_{
\text{enc}}}{\varepsilon_0}}_{\text{charge}}
SEn^daemf=qencε0chargeHorizontalBraces
-

HTML

- -
\id{a}{a+}b\style{color:red;}{+c}a+b+cN/A
-

Includegraphics

-

Asphere_+sphere+AspheresphereAsphere_+xsphere+Aspheresphere

-

Integrands

- -
\begin{array}{l}
\displaystyle \int + \oint +
\iint + \oiint_i^n \\
\displaystyle \iiint + \oiiint +
\textstyle \int + \oint_i^n \\
\iint + \oiint +
\iiint + \oiiint \end{array}
+++in+++in+++Integrands
-

Kern

- -
\frac{a\kern{1em}b}{c}a
\kern{1em}b
\kern{1ex}c\kern{-0.25em}d
abcabcdkern
-

Lap

- -
\begin{array}{l}
ab\mathllap{f}cd\mathrlap{g}hij\mathclap{k}lm ;
ab\llap{f}cd\rlap{g}hij\clap{k}lm \\
\mathrlap{\frac a b}\frac a b \\
\mathrlap{\overbrace{
\phantom{a_0+a_1+a_2}}^m}a_0+a_1+a_2
\end{array}
abfcdghijklmabfcdghijklmababa0+a1+a2ma0+a1+a2lap
-

LargeRuleNumerator

- -
\frac{\textcolor{blue}
{\rule{1em}{2em}}}{x}
xLargeRuleNumerator
-

LaTeX

- -
\text{\LaTeX}, \text{\TeX}LATEX,TEXlatex
-

LeftRight

- -
\left( x^2 \right)
\left\{ x^{x^{x^{x^x}}} \right.
(x2){xxxxxLeftRight
-

LeftRightListStyling

- -
a+\left(x+y\right)-xa+(x+y)xLeftRightListStyling
-

LeftRightMiddle

- -
\left( x^2 \middle/ \right)
\left\{ x^{x^{x^{x^x}}}
\middle/ y \right.
\left(x\middle|y\,\middle|\,z\right)
(x2){xxxxxy(x|y|z)LeftRightMiddle
-

LeftRightStyleSizing

- -
+\left\{\rule{0.1em}{1em}\right.
x^{+\left\{\rule{0.1em}{1em}\right.
x^{+\left\{\rule{0.1em}{1em}\right.}}
+{x+{x+{LeftRightStyleSizing
-

LimitControls

- -
\displaystyle\int\limits_2^3 3x^2\,dx
+ \sum\nolimits^n_{i=1}i +
\textstyle\int\limits_x^y z
233x2dx+i=1ni+xyzLimitControls
-

LineBreak

-

Firefox will apply soft lines breaks after relationss and binary operators.

-

x2y2+z2=z2+x2y2=x2y2+z2=z2+x2y2=x2y2+ z2=z2+x2y2=x2y2+z2=z2+x2y2=x2y2+z2=z2+x2y2=x2y2+z2=hithere=hithere

-

LowerAccent

- -
\begin{array}{l}
\underleftarrow{AB} \quad \underrightarrow{AB} \quad
\underleftrightarrow{AB} \quad \undergroup{AB} \\
\text{\underline{text}} \quad \utilde{AB}
\quad \underrightarrow{AB} \\
\underrightarrow{F} + \underrightarrow{AB} +
\underrightarrow{AB}^2 + \underrightarrow{AB}_2 \\
\frac{\underrightarrow{AB}}{\underrightarrow{AB}} +
\sqrt{\underrightarrow{AB}} +
\left\lvert\underrightarrow{AB}\right\rvert
\end{array}
ABABABABtext_AB~ABF+AB+AB2+AB2ABAB+AB+|AB|
-

MathChoice

- -
{\displaystyle\mathchoice{D}{T}{S}{SS}}\;
{\textstyle\mathchoice{D}{T}{S}{SS}}\;
{\scriptstyle \mathchoice{D}{T}{S}{SS}}\;
{\scriptscriptstyle\mathchoice{D}{T}{S}{SS}}\;
\displaystyle X_{\mathchoice{D}{T}{S}{SS}_
{\mathchoice{D}{T}{S}{SS}}}
DTSSSXSSSMathChoice
-

MathDefaultFonts

- -
Ax2k\breve{a}\omega\Omega\imathAx2ka˘ωΩı
-

MathBb

- -
\mathbb{Ax2k\breve{a}\omega\Omega\imath}𝔸𝕩𝟚𝕜𝕒˘ωΩı
-

MathBf

- -
\mathbf{Ax2k\breve{a}\omega\Omega\imath}𝐀𝐱𝟐𝐤𝐚˘𝛚𝛀ı
-

MathCal

- -
\mathcal{Ax2k\breve{a}\omega\Omega\imath}𝒜𝓍2𝓀𝒶˘ωΩı
-

MathFrak

- -
\mathfrak{Ax2k\breve{a}\omega\Omega\imath}𝔄𝔵2𝔨𝔞˘ωΩı
-

MathIt

- -
\mathit{Ax2k\breve{a}\omega\Omega\imath}Ax2ka˘ωΩı
-

MathNormal

- -
\mathnormal{Ax2k\breve{a}\omega\Omega\imath}Ax2ka˘ωΩı
-

MathOp

- -
a\mathop+b\mathop:c\mathop{\delta}
e\mathop{\textrm{and}}f
\mathrel{\mathop{:}}=g\sin h
a+b:cδeandf:=gsinhmathop
-

MathRm

- -
\mathrm{Ax2k\breve{a}\omega\Omega\imath}Ax2ka˘ωΩı
-

MathSf

- -
\mathsf{Ax2k\breve{a}\omega\Omega\imath}𝖠𝗑𝟤𝗄𝖺˘𝞈𝝮ı
-

MathScr

- -
\mathscr{Ax2k\breve{a}\omega\Omega\imath}𝒜𝓍2𝓀𝒶˘ωΩı
-

MathtoolsMatrix

- -
\begin{matrix*}[l]
a & -1 \\
-1 & d
\end{matrix*} \;
\begin{pmatrix*}[r]
a & -1 \\
-1 & d
\end{pmatrix*}
a11d(a11d)MathtoolsMatrix
-

MathTt

- -
\mathtt{Ax2k\breve{a}\omega\Omega\imath}𝙰𝚡𝟸𝚔𝚊˘ωΩı
-

Mod

- -
\begin{array}{cc} a \bmod 2 & b \pod 3 \\
c \pmod{4} & d \mod{56} \\
\displaystyle a\bmod 2 & b \pod 3 \\
\displaystyle c\pmod{4} & d \mod{56}
\end{array}
amod2b(3)c(mod4)dmod56amod2b(3)c(mod4)dmod56mod
-

NegativeSpace

- -
\boxed{$1,!000,!000}$1,000,000NegativeSpace
-

NestedFractions

- -
\dfrac{\frac{a}{b}}{\frac{c}{d}}
\dfrac{\dfrac{a}{b}}{\dfrac{c}{d}}
\frac{\frac{a}{b}}{\frac{c}{d}}
abcdabcdabcdNestedFractions
-

NewLine

- -
\frac{a^2+b^2}{c^2} \newline
\frac{a^2+b^2}{c^2} \\
\begin{pmatrix} a & b \\
c & d \cr \end{pmatrix} \\
a+b+c+{d+\\e}+f+g
a2+b2c2a2+b2c2(abcd)a+b+c+d+e+f+gnewline
-

Not

- -
\not = \begin{array}{l}
\not=\not>\not\geq\not\in\not<\not\leq\not{abc} \\
\not xy + ab \not xy \\
a \neq b \notin c \end{array}
≱∉≰̸abcy+abyabcnot
-

NullDelimiterInteraction

- -
a \bigl. + 2 \quad \left. + a \right)a+2+a)NullDelimiterInteraction
-

OldFont

- -
\begin{matrix}
\rm rm & it & \it it &
\bf bf & \sf sf & \tt tt \\
\text{\rm rm} & \text{rm} & \text{\it it} &
\text{\bf bf} & \text{\sf sf} & \text{\tt tt} \\
i\rm r\it i & \text{r\it i\rm r}
\end{matrix}
rmitit𝐛𝐟𝗌𝖿𝚝𝚝rmrm𝑖𝑡𝐛𝐟𝗌𝖿𝚝𝚝irir𝑖roldfont
-

OperatorName

- -
\begin{matrix} \operatorname g (z) + 5\operatorname{g}z
+ \operatorname{Gam-ma}(z) \\
\operatorname{Gam ma}(z)
+ \operatorname{\Gamma}(z)
+ \operatorname{}x \\
\operatorname*{asin} x +
\operatorname*{asin}_y x +
\operatorname*{asin}\limits_y x \\
{\displaystyle \operatorname*{asin}_y x}
\end{matrix}
g(z)+5gz+Gam-ma(z)Gamma(z)+Γ(z)+xasinx+asinyx+asinyxasinyxOperatorName
-

OpLimits

- -
\begin{matrix}
{\sin_2^2 \lim_2^2 \int_2^2 \sum_2^2}
{\displaystyle \lim_2^2 \int_2^2 \intop_2^2 \sum_2^2} \\
\limsup_{x \rightarrow \infty} x \stackrel{?}=
\liminf_{x \rightarrow \infty} x \\
{\displaystyle \limsup_{x \rightarrow \infty}
x\:\: \sum_{\substack{0<i<m\\0<j<n}}} \end{matrix}
sin22lim222222lim22222222limsupxx=?liminfxxlimsupxx0<i<m0<j<nOpLimits
-

OverUnderline

- -
x\underline{x}\underline{\underline{x}}
\underline{x{x{x_x}}}\underline{x^{x^{x^x}}}
\overline{x}\overline{x}\overline{x^{x^{x^x}}}
\textcolor{blue}{\overline{\underline{x}}
\underline{\overline{x}}}
xx_x__xxxx_xxxx_x_x_xxxx_x__x__OverUnderline
-

OverUnderset

- -
\begin{array}{l}
x\overset?=1 \quad \underset{*}{x}^2 \quad
\overset{a}{b}b\underset{a}{b}b \\
{\displaystyle\lim_{t\underset{>0}\to0}}\\
a+b+c+d\overset{b+c=0}
\longrightarrow a+d\\
\overset { x = y } { \sqrt { a b } }
\end{array}
x=?1x*2babbablimt>00a+b+c+db+c=0a+dabx=yOverUnderset
-

Phantom

- -
\begin{array}{l} \dfrac{1+\phantom{x^{\textcolor{blue}{2}}} = x}
{1+x^{\textcolor{blue}{2}} = x}
\left(\vphantom{\int_t} zzz \right)
\left( X \hphantom{\frac{\frac X X}{X}} \right)\\
\text{a \phantom{123}} b \hphantom{\frac{1}{2}}=c
\vphantom{101112} d \\
\sqrt{\mathstrut a} + \sqrt{\mathstrut d}
\end{array}
1+x2=x1+x2=x(tzzz)(XXXX) 123b12=c101112d(a+(dphantom
-

Phase

- -
120\text{V}\phase{-78.2^\circ};
\Large\phase{78.2^\circ}
120V78.278.2
-

Pmb

- -
\mu\pmb{\mu}\pmb{=}\mu\pmb{+}\muμμ=μ+μpmb
-

PrimeSpacing

- -
f'+f_2'+f^{f'}f+f2+ffPrimeSpacing
-

PrimeSuper

- -
x'^2+x'''^2+x'^2_3+x_3'^2x2+x2+x32+x32PrimeSuper
-

Raisebox

- -
\frac{a}{a\raisebox{0.5em}{b}} \cdot
\frac{a\raisebox{-0.5em}{b}}{a} \cdot
\sqrt{a\raisebox{0.5em}{b}} \cdot
\sqrt{a\raisebox{-0.5em}{b}} \cdot
\sqrt{a\raisebox{0.5em}{b}\raisebox{-0.5em}{b}}
aababaabababbraisebox
-

RelativeUnits

- -
\begin{array}{ll}
a\kern1emb^{a\kern1emb^{a\kern1emb}} &
{\footnotesize a\kern1emb^
{a\kern1emb^{a\kern1emb}}} \\
a\mkern18mub^{a\mkern18mub^{a\mkern18mub}} &
{\footnotesize a\mkern18mub^
{a\mkern18mub^{a\mkern18mub}}} \\
\end{array}
ababababababababababababRelativeUnits
-

RlapBug

- -
\frac{\mathrlap{x}}{2}x2rlapbug
-

Rule

- -
\rule{1em}{0.5em}\rule{1ex}{2ex}
\rule{1em}{1ex}\rule{1em}{0.431ex}
rule
-

SizingBaseline

- -
\text{{\tiny a+b}a+b{\Huge a+b}}a+ba+ba+bSizingBaseline
-

Sizing

- -
\text{{\Huge x}{\LARGE y}
{\normalsize z}{\scriptsize w}}
\sqrt[\text{\small 3}]{x+1}
xy zwx+13sizing
-

Smash

- -
\left( X^{\smash 2} \right)
\sqrt{\smash[b]{y=}}
(X2)y=smash
-

Spacing

- -
\begin{matrix}
^3+[-1][1-1]1=1(=1)\lvert a\rvert~b \\
\scriptstyle{^3+[-1][1-1]
1=1(=1)\lvert a\rvert~b} \\
\scriptscriptstyle{^3+[-1][1-1]
1=1(=1)\lvert a\rvert~b} \\
a : a \colon a \\
\end{matrix}
3+[1][11]1=1(=1)|a| b3+[1][11]1=1(=1)|a| b3+[1][11]1=1(=1)|a| ba:a:aspacing
-

Sqrt

- -
\sqrt{\sqrt{\sqrt{x}}}_
{\sqrt{\sqrt{x}}}^
{\sqrt{\sqrt{\sqrt{x}}}
^{\sqrt{\sqrt{\sqrt{x}}}}} \\
\sqrt{\frac{\frac{A}{B}}{\frac{A}{B}}} \;
\sqrt{\frac{\frac{\frac{A}{B}}{\frac{A}{B}}}
{\frac{\frac{A}{B}}{\frac{A}{B}}}}
xxxxABABABABABABsqrt
-

SqrtRoot

- -
\begin{array}{l}
1+\sqrt[3]{2}+\sqrt[1923^234]
{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}} \\
\Huge \sqrt[3]{M} + x^{\sqrt[3] a}
\end{array}
1+23+2222222222221923234M3+xa3SqrtRoot
-

StackRel

- -
a \stackrel{?}{=} b
\stackrel{\text{def}}{=} c
a=?b=defcStackRel
-

StretchyAccent

- -
\begin{array}{l}
\overrightarrow{AB} \quad \overleftarrow{AB} \quad
\overleftrightarrow{AB} \quad
\left(\underleftarrow{\frac{value}{j}}\right) \\
\widehat{ABC} \quad
\widetilde{AB} \quad \widetilde{ABC} \\
\overrightarrow{F} + \overrightarrow{AB} +
\overrightarrow{F}^2 + \overrightarrow{F}_2 +
\overrightarrow{F}_1^2 \\
\overrightarrow{AB}^2+
\frac{\overrightarrow{AB}}{\overrightarrow{AB}} +
\sqrt{\overrightarrow{AB}} +
\left\lvert\overrightarrow{AB}\right\rvert \end{array}
ABABAB(valuej)ABC^AB~ABC~F+AB+F2+F2+F12AB2+ABAB+AB+|AB|StretchyAccent
-

StrikeThrough

- -
\begin{array}{l}
\cancel x \quad \cancel{2B} +
\bcancel 5 +\bcancel{5ay} \\
\sout{5ab} + \sout{5ABC} +
\xcancel{\oint_S{\vec E\cdot\hat n
\,\mathrm d a}} \\[0.3em]
\frac{x+\cancel B}{x+\cancel x} +
\frac{x+\cancel y}{x} + \cancel{B}_1^2
+ \cancel{B^2} \\[0.2em]
\left\lvert\cancel{ac}\right\rvert
\end{array}
x2B+5+5ay5ab+5ABC+SEn^dax+Bx+x+x+yx+B12+B2|ac|StrikeThrough
-

StrikeThroughColor

- -
\begin{array}{l} \textcolor{red}{\cancel x \quad \cancel{2B}} \\
\textcolor{red}{\bcancel{\textcolor{black}{5}}} +
\textcolor{red}{\bcancel{\textcolor{black}{5ay}}} \\
\color{green}{\sout{5ABC}}
\end{array}
x2B5+5ay5ABCStrikeThroughColor
-

StyleSpacing

- -
\scriptstyle ab\;cdabcdStyleSpacing
-

StyleSwitching

- -
a\cdot b\scriptstyle a\cdot ba
\textstyle\cdot ba\scriptstyle\cdot b
ababababStyleSwitching
-

SupSubCharacterBox

- -
a_2f_2{f}_2{aa}_2{af}_2\mathbf{y}_Ay_Aa2f2f2aa2af2𝐲AyASupSubCharacterBox
-

SupSubHorizSpacing

- -
x^{x^{x}}\Big|
x_{x_{x_{x_{x}}}}\bigg|
x^{x^{x_{x_{x_{x_{x}}}}}}\bigg|
xxx|xxxxx|xxxxxxx|SupSubHorizSpacing
-

SupSubLeftAlignReset

- -
\omega^8_{888} \quad
\frac{1}{\hat{\omega}^{8}_{888}} \quad
\displaystyle\sum_{\omega^{8}_{888}}
ω88881ω^8888ω8888SupSubLeftAlignReset
-

SupSubOffsets

- -
\displaystyle \int_{2+3}x f^{2+3}
+3\lim_{2+3+4+5}f
2+3xf2+3+3lim2+3+4+5fSupSubOffsets
-

SurrogatePairs

- - - - - - - - -
Source Temml
𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜 𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜
𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶 𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶
\text{𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜} 𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜
\text{𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶} 𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶
\mathrm{𝐀𝐚𝑨𝒂𝔅𝔞𝔸𝒜} 𝐀𝐚𝑨𝒂𝔅𝔞𝔸𝒜
-

Symbols1

- -
\maltese\degree\standardstate\pounds\$
\text{\maltese\degree\pounds\textdollar}
°£$✠°£$
-

Tag

- -
\tag{$+$hi} \frac{x^2}{y}+x^{2^y}x2y+x2y(+hi)
-

Text

- -
\frac{a}{b}\text{c~ {ab} \ e}+fgabc  ab  e+fgtext
-

TextSpace

- -
\begin{array}{l}
\texttt{12345678901234} \\
\texttt{A test 1~~2 \ \ 3} \\
\verb|A test 1 2 3|
\end{array}
𝟷𝙰 𝚝𝚎𝚜𝚝 𝟷  𝟸  𝟹A test 1  2  3TextSpace
-

TextStacked

- -
\begin{matrix}
\textsf{abc123 \textbf{abc123}
\textit{abc123}}\\
\text{abc123 \textbf{abc123}
\textit{abc123}}\\
\textrm{abc123 \textbf{abc123}
\textit{abc123}}\\
\textsf{\textrm{\textbf{abc123}}
\textbf{abc123}
\textit{abc123}}\\
\textit{abc123 \textbf{abc123}
\textsf{abc123}}\\
\end{matrix}
𝖺𝖻𝖼𝟣 𝗮𝗯𝗰𝟭 𝘢𝘣𝘤1abc123 𝐚𝐛𝐜𝟏 𝑎𝑏𝑐𝑏𝑐bc123 𝐚𝐛𝐜𝟏 𝑎𝑏𝑐𝑏𝑐123abc123 𝐚𝐛𝐜𝟏 𝑎𝑏𝑐𝑏𝑐bc123 𝐚𝐛𝐜𝟏 𝑎𝑏𝑐𝑏𝑐123𝐚𝐛𝐜𝟏 𝗮𝗯𝗰𝟭 𝘢𝘣𝘤1𝑎𝑏𝑐𝑏𝑐123 𝒂𝒃𝒄𝒃𝒄123 𝘢𝘣𝘤1TextStacked
-

TextWithMath

- -
\begin{matrix}
\text{for $a < b$ and $ c < d $}. \\
\textsf{for $a < b$ and $ c < d $}. \\
\textsf{for $a < b \textbf{ and } c < d $} \\
\text{\sf for $a < b$ and $c < d$.}
\end{matrix}
for or a<b and c<d.𝖿𝗈𝗋 𝗈𝗋 𝖺<𝖻 𝖺𝗇𝖽 𝖼<𝖽.𝖿𝗈𝗋 𝗈𝗋 𝖺<𝖻 𝗮𝗻𝗱 𝖼<𝖽𝖿𝗈𝗋 𝗈𝗋 𝖺<𝖻 𝖺𝗇𝖽 𝖼<𝖽.TextWithMath
-

Unicode

- - - - - - - -
Source Temml
\text{ÀàÇçÉéÏïÖöÛû} AˋaˋÇçEˊeˊI¨ı¨O¨o¨Uˆuˆ
\text{БГДЖЗЙЛФЦШЫЮЯ} БГДЖЗЙЛФЦШЫЮЯ
\text{여보세요} 여보세요
\text{私はバナナです} 私はバナナです
-

Units

- -
\begin{array}{ll}
\mathrm H\kern 1em\mathrm H
\text{\tiny (1em)} &
\mathrm H\kern 1ex\mathrm H
\text{\tiny (1ex)} \\
\mathrm H{\scriptstyle \kern 1em}\mathrm H
\text{\tiny (ss 1em)} &
\mathrm H{\scriptstyle \kern 1ex}\mathrm H
\text{\tiny (ss 1ex)} \\
\mathrm H{\small \kern 1em}\mathrm H
\text{\tiny (sm 1em)} &
\mathrm H{\small \kern 1ex}\mathrm H
\text{\tiny (sm 1ex)} \\
\mathrm H\mkern 18mu\mathrm H
\text{\tiny (18mu)} &
\mathrm H\kern 1cm\mathrm H
\text{\tiny (1cm)} \\
\mathrm H{\scriptstyle \mkern 18mu}\mathrm H
\text{\tiny (ss 18mu)} &
\mathrm H{\scriptstyle \kern 1cm}\mathrm H
\text{\tiny (ss 1cm)} \\
\mathrm H{\small \mkern 18mu}\mathrm H
\text{\tiny (sm 18mu)} &
\mathrm H{\small \kern 1cm}\mathrm H
\text{\tiny (sm 1cm)}
\end{array}
HH(1em)HH(1ex)HH(ss 1em)HH(ss 1ex)HH(sm 1em)HH(sm 1ex)HH(18mu)HH(1cm)HH(ss 18mu)HH(ss 1cm)HH(sm 18mu)HH(sm 1cm)units
-

UnsupportedCmds

-

\err\fracerr32\suberr\superr\sqrterr

-

deliberately does not compile

-

Verb

- -
\begin{array}{ll}
\verb \verb , & \verb|\verb |, \\
\verb* \verb* , & \verb*|\verb* |, \\
\verb!<x> & </y>! & \scriptstyle\verb|ss verb| \\
\verb*!<x> & </y>! & \small\verb|sm verb| \\
\verb|``---''~|
\end{array}
\verb,\verb  ,\verb*,\verb*␣,<x> & </y>ss verb<x>␣&␣</y>sm verb``---''~verb
- - diff --git a/site/tests/mhchem-tests.html b/site/tests/mhchem-tests.html deleted file mode 100644 index fb49e5bf..00000000 --- a/site/tests/mhchem-tests.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - Temml mhchem Tests - - - - - - -

mhchem

-

This file contains all the examples in the mhchem manual.
Ref: https://mhchem.github.io/MathJax-mhchem/

-

Chemical Equations (ce)

- - - - - - -
Source Temml
\ce{CO2 + C -> 2 CO}CO2+C2CO
\ce{Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2-}Hg2+IHgI2I[HgXIII4]2
C_p[\ce{H2O(l)}] = \pu{75.3 J // mol K}Cp[H2O(l)]=75.3 JmolK
-

Chemical Formulae

- - - - - -
Source Temml
\ce{H2O}H2O
\ce{Sb2O3}Sb2O3
-

Charges

- - - - - - - - -
Source Temml
\ce{H+}H+
\ce{CrO4^2-}CrO42
\ce{[AgCl2]-}[AgCl2]
\ce{Y^99+}Y99+
\ce{Y^{99+}}Y99+
-

Stoichiometric Numbers

- - - - - - - - - -
Source Temml
\ce{2 H2O}2H2O
\ce{2H2O}2H2O
\ce{0.5 H2O}0.5H2O
\ce{1/2 H2O}12H2O
\ce{(1/2) H2O}(12)H2O
\ce{$n$ H2O}nH2O
-

Isotopes

- - - - - - -
\ce{^{227}_{90}Th+}X90227X2902227Th+
\ce{^227_90Th+}X90227X2902227Th+
\ce{^{0}_{-1}n^{-}}X10X2120n
\ce{^0_-1n-}X10X2120n
\ce{H{}^3HO}HX3X223HO
\ce{H^3HO}HX3X223HO
-

Reaction Arrows

- - - - - - - - - - - - - -
Source Temml
\ce{A -> B}AB
\ce{A <- B}AB
\ce{A <-> B}AB
\ce{A <--> B}AB
\ce{A <=> B}AB
\ce{A <=>> B}AB
\ce{A <<=> B}AB
\ce{A ->[H2O] B}AH2OB
\ce{A ->[{text above}][{text below}] B}Atext belowtext aboveB
\ce{A ->[$x$][$x_i$] B}AxixB
-

Parentheses, Brackets, Braces

- - - - - - -
Source Temml
\ce{(NH4)2S}(NH4)2S
\ce{[\{(X2)3\}2]^3+}[{(X2)3}2]3+
\ce{CH4 + 2 $\left( \ce{O2 + 79/21 N2} \right)$}CH4+2 (O2+7921N2)
-

States of Aggregation

- - - - - - -
Source Temml
\ce{H2(aq)}H2(aq)
\ce{CO3^2-_{(aq)}}CO32(aq)
\ce{NaOH(aq,$\infty$)}NaOH(aq,)
-

Crystal Systems

- - - - - -
Source Temml
\ce{ZnS($c$)}ZnS(c)
\ce{ZnS(\ca$c$)}ZnS(c)
-

Variables

- - - - - - -
Source Temml
\ce{NO_x}NOx
\ce{Fe^n+}Fen+
\ce{x Na(NH4)HPO4 ->[\Delta]
(NaPO3)_x + x NH3 ^ + x H2O}
xNa(NH4)HPO4Δ(NaPO3)x+xNH3+xH2O
-

Greek Characters

- - - - - - - -
Source Temml
\ce{\mu-Cl}μ-Cl
\ce{[Pt(\eta^2-C2H4)Cl3]-}[Pt(η2-C2H4)Cl3]
\ce{\beta +}β+
\ce{^40_18Ar + \gamma{} + \nu_e}X1840X218240Ar+γ+νe
-

(Italic) Math

- - - - - - - -
Source Temml
\ce{NaOH(aq,$\infty$)}NaOH(aq,)
\ce{Fe(CN)_{$\frac{6}{2}$}}Fe(CN)62
\ce{X_{$i$}^{$x$}}Xix
\ce{X_$i$^$x$}Xix
-

Italic Text

- - - - - -
Source Temml
\ce{$cis${-}[PtCl2(NH3)2]}cis-[PtCl2(NH3)2]
\ce{CuS($hP12$)}CuS(hP12)
-

Upright Text, Escape Parsing

- - - - - - -
Source Temml
\ce{{Gluconic Acid} + H2O2}Gluconic Acid+H2O2
\ce{X_{{red}}}Xred
\ce{{(+)}_589{-}[Co(en)3]Cl3}(+)589-[Co(en)3]Cl3
-

Bonds

- - - - - - - - - - - -
Source Temml
\ce{C6H5-CHO}C6H5CHO
\ce{A-B=C#D}AB=CD
\ce{A\bond{-}B\bond{=}C\bond{#}D}AB=CD
\ce{A\bond{1}B\bond{2}C\bond{3}D}AB=CD
\ce{A\bond{~}B\bond{~-}C}ABC
\ce{A\bond{~--}B\bond{~=}C\bond{-~-}D}ABCD
\ce{A\bond{...}B\bond{....}C}ABC
\ce{A\bond{->}B\bond{<-}C}ABC
-

Addition Compounds

- - - - - - -
Source Temml
\ce{KCr(SO4)2*12H2O}KCr(SO4)212H2O
\ce{KCr(SO4)2.12H2O}KCr(SO4)212H2O
\ce{KCr(SO4)2 * 12 H2O}KCr(SO4)212H2O
-

Oxidation States

- - - - -
Source Temml
\ce{Fe^{II}Fe^{III}2O4}FeXIIFeXIII2O4
-

Unpaired Electrons, Radical Dots

- - - - - -
Source Temml
\ce{OCO^{.-}}OCO
\ce{NO^{(2.)-}}NO(2)
-

Kröger-Vink Notation

- - - - - - - - -
Source Temml
\ce{Li^x_{Li,1-2x}Mg^._{Li,x}
$V$'_{Li,x}Cl^x_{Cl}}
LiXLi,12x×MgXLi,x VXLi,xClXCl×

\ce{O''_{i,x}}

-

OXi,x

-
\ce{M^{..}_i}MXi
\ce{$V$^{4'}_{Ti}}VXTi4
\ce{V_{V,1}C_{C,0.8}$V$_{C,0.2}}VV,1CC,0.8 VC,0.2
-

Equation Operators

- - - - - - - -
Source Temml
\ce{A + B}A+B
\ce{A - B}AB
\ce{A = B}A=B
\ce{A \pm B}A±B
-

Precipitate and Gas

- - - - - -
Source Temml
\ce{SO4^2- + Ba^2+ -> BaSO4 v}SO42+Ba2+BaSO4
\ce{A v B (v) -> B ^ B (^)}A BB B
-

Other Symbols and Shortcuts

- - - - - - - - - - -
Source Temml
\ce{NO^*}NO*
\ce{1s^2-N}1s2-N
\ce{n-Pr}n-Pr
\ce{iPr}iPr
\ce{\ca Fe}Fe
\ce{A, B, C; F}A,B,C;F
\ce{{and others}}and others
-

Complex Examples

- - - - - - - -
Source Temml
\ce{Zn^2+ <=>+ 2OH-
$\underset{\text{amphoteres Hydroxid}}
{\ce{Zn(OH)2 v}}$ <=>+ 2OH-
$\underset{\text{Hydroxozikat}}
{\ce{[Zn(OH)4]^2-}}$}
Zn2++2H++2OH+2H++2OHZn(OH)2amphoteres Hydroxid+2H++2OH+2H++2OH[Zn(OH)4]2Hydroxozikat
\ce{$K = \frac{\ce{Hg^2+}}
{[\ce{Hg2^2+}]}$}
K=[Hg2+][Hg][Hg22+]
\ce{$K =
\ce{\frac{Hg^2+}{[Hg2^2+]}}$}
K=[Hg2+][Hg][Hg22+]
\ce{Hg^2+ ->[I-]
$\underset{\mathrm{red}}{\ce{HgI2}}$
->[I-] $\underset{\mathrm{red}}
{\ce{[Hg^{II}I4]^2-}}$}
Hg2+IHgI2redI[HgXIII4]2red
-

Physical Units

- - - - - - - - - - - - - - - -
Source Temml
\pu{123 kJ}123 kJ
\pu{123 mm2}123 mm2
\pu{123 J s}123 Js
\pu{123 J*s}123 Js
\pu{123 kJ/mol}123 kJmol
\pu{123 kJ//mol}123 kJmol
\pu{123 kJ mol-1}123 kJmol1
\pu{123 kJ*mol-1}123 kJmol1
\pu{1.2e3 kJ}1.2103 kJ
\pu{1,2e3 kJ}1,2103 kJ
\pu{1.2E3 kJ}1.2×103 kJ
\pu{1,2E3 kJ}1,2×103 kJ
- - diff --git a/site/tests/mozilla-tests.html b/site/tests/mozilla-tests.html deleted file mode 100644 index 869926aa..00000000 --- a/site/tests/mozilla-tests.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - Temml Mozilla Tests - - - - - - -

Mozilla Torture Test

-

This page reproduces the tests from
https://www-archive.mozilla.org/projects/mathml/demo/texvsmml.xhtml and
https://fred-wang.github.io/MathFonts/mozilla_mathml_test/

-

Images from LaTeX are also included for comparison.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SourceTemmlLaTeXComment
1x^2y^2x2y2ex1TeXbook p128
2_2F_32F3ex2TeXbook p128
3x+y^2\over k+1x+y2k+1ex3TeXbook p139
4x+y^{2\over k+1}x+y2k+1ex4TeXbook p139
5a\over{b/2}ab2ex5TeXbook p139
6 a_0 + \cfrac{1}{a_1 +
\cfrac{1}{a_2 +
\cfrac{1}{a_3 +
\cfrac{1}{a_4}}}}
a0+1a1+1a2+1a3+1a4ex6 TeXbook p142
7 a_0+{1\over a_1+{1\over
a_2+{1\over a_3+
{1\over a_4}}}}
a0+1a1+1a2+1a3+1a4ex7 TeXbook p142
8n\choose {k / 2}(nk2)ex8TeXbook p143
9 {p \choose 2} x^2 y^{p-2}
- {1\over{1-x}}
{1\over{1-x^2}}
(p2)x2yp211x11x2ex9 TeXbook p143
10 \sum_{\scriptstyle 0 \le
i \le m \atop \scriptstyle
0 < j < n} P(i, j)
0im0<j<nP(i,j)ex10 TeXbook p145
11x^{2y}x2yex11TeXbook p128
12 \sum_{i=1}^p
\sum_{j=1}^q
\sum_{k=1}^r
a_{ij}b_{jk}c_{ki}
i=1pj=1qk=1raijbjkckiex12 TeXbook p145
13 \sqrt{1+\sqrt{1+\sqrt{1+
\sqrt{1+\sqrt{1+\sqrt{1+
\sqrt{1+x}}}}}}}
1+1+1+1+1+1+1+xex13 TeXbook p145
14 \bigg(\frac{\partial^2}
{\partial x^2} + \frac
{\partial^2}{\partial y^2}
\bigg) \big\lvert\varphi
(x+iy)\big\rvert^2
(2x2+2y2)|φ(x+iy)|2ex14 TeXbook p147
152^{2^{2^x}}222xex15TeXbook p128
16\int_1^x {dt\over t}1xdttex16TeXbook p168
17\int\!\!\!\int_D dx,dyDdxdyex17TeXbook p169
18 f(x) = \begin{cases}1/3 &
\text{if }0 \le x \le 1;
\\
2/3 & \text{if }3\le x \le
4;\\ 0 &\text{elsewhere.}
\end{cases}
f(x)={13if 0x1;23if 3x4;0elsewhere. ex18 TeXbook p175
19 \overbrace{x +\cdots + x}
^{k \text{ times}}
x++xk timesex19 TeXbook p176
20y_{x^2}yx2ex20TeXbook p128
21 \sum_{p\text{ prime}}
f(p)=\int_{t>1} f(t)d\pi(t)
p primef(p)=t>1f(t)dπ(t)ex21 TeXbook p181
22 {\underbrace{\overbrace{
\mathstrut a,\dots,a}^{k
,a\rq\text{s}},\overbrace{
\mathstrut b,\dots,b}^{l,
b\rq\text{s}}}_{k+l
\text{ elements}}}
{(a,,akas,(b,,blbsk+l elements}ex22 TeXbook p181
23 \begin{pmatrix}
\begin{pmatrix}a&b\\c&d
\end{pmatrix} &
\begin{pmatrix}e&f\\g&h
\end{pmatrix} \\ 0 &
\begin{pmatrix}i&j\\k&l
\end{pmatrix}
\end{pmatrix}
((abcd)(efgh)0(ijkl))ex23 TeXbook p181
24 \det\begin{vmatrix}
c_0&c_1&c_2&\dots& c_n\\
c_1 & c_2 & c_3 & \dots &
c_{n+1}\\ c_2 & c_3 & c_4
&\dots & c_{n+2}\\ \vdots
&\vdots&\vdots & &\vdots
\\c_n & c_{n+1} & c_{n+2}
&\dots&c_{2n}
\end{vmatrix} > 0
det|c0c1c2cnc1c2c3cn+1c2c3c4cn+2cncn+1cn+2c2n|>0ex24 TeXbook p181
25y_{x_2}yx2ex25TeXbook p128
26x_{92}^{31415} + \pix9231415+πex26TeXbook p129
27x_{y^a_b}^{z^c_d}xybazdcex27TeXbook p129
28y_3'''y3ex28TeXbook p130
29 \lim_{n\rightarrow+\infty}
{\sqrt{2\pi n}\over n!}
{\binom{n}{e}}^n = 1
limn+2πnn!(ne)n=1ex29
30 \det(A) = \sum_{\sigma
\in S_n} \epsilon(\sigma)
\prod_{i=1}^n
a_{i, \sigma_i}
det(A)=σSnϵ(σ)i=1nai,σiex30
- - diff --git a/site/tests/wiki-tests.html b/site/tests/wiki-tests.html deleted file mode 100644 index e08de700..00000000 --- a/site/tests/wiki-tests.html +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - Temml Wiki Tests - - - - - - -

Wiki Test

-

Rows 1 thru 261 on this page reproduce the math examples from
https://en.wikipedia.org/wiki/Help:Displaying_a_formula

-

A few of the functions on this page require Temml’s texvc extension.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SourceTemml
1\alphaα
2f(x) = x^2f(x)=x2
3\{1,e,\pi\}{1,e,π}
4|z + 1| \leq 2|z+1|2
5 \# \$ \% ^\wedge \& \_ \{ \} \sim
\backslash
#$%&_{}\
Accents
6\dot{a}, \ddot{a}, \acute{a}, \grave{a}a˙,a¨,aˊ,a`
7\dot{a}, \ddot{a}, \acute{a}, \grave{a}a˙,a¨,aˊ,a`
8\check{a}, \breve{a}, \tilde{a}, \bar{a}aˇ,a˘,a~,a
9\hat{a}, \widehat{a}, \vec{a}a^,a^,a
Functions
10\exp_a b = a^b, \exp b = e^b, 10^mexpab=ab,expb=eb,10m
11\ln c, \lg d = \log e, \log_{10} flnc,lgd=loge,log10f
12 \sin a, \cos b, \tan c, \cot d, \sec e,
\csc f
sina,cosb,tanc,cotd,sece,cscf
13\arcsin h, \arccos i, \arctan jarcsinh,arccosi,arctanj
14\sinh k, \cosh l, \tanh m, \coth nsinhk,coshl,tanhm,cothn
15 \operatorname{sh}k, \operatorname{ch}l,
\operatorname{th}m, \operatorname{coth}n
shk,chl,thm,cothn
16\sgn r, \left\vert s \right\vertsgnr,|s|
17\min(x,y), \max(x,y)min(x,y),max(x,y)
Bounds
18\min x, \max y, \inf s, \sup tminx,maxy,infs,supt
19\lim u, \liminf v, \limsup wlimu,liminfv,limsupw
20\dim p, \deg q, \det m, \ker\phidimp,degq,detm,kerϕ
Projections
21\Pr j, \hom l, \lVert z \rVert, \arg zPrj,homl,z,argz
Differentials and derivatives
22dt, \mathrm{d}t, \partial t, \nabla\psidt,dt,t,ψ
23 dy/dx, \mathrm{d}y/\mathrm{d}x,
\frac{dy}{dx},
\frac{\mathrm{d}y}{\mathrm{d}x},
\frac{\partial^2}
{\partial x_1\partial x_2}y
dydx,dydx,dydx,dydx,2x1x2y
24 \prime, \backprime, f^\prime, f', f'',
f^{(3)}, \dot y, \ddot y
,,f,f,f,f(3),y˙,y¨
Letter-like symbols or constants
25 \infty, \aleph, \complement,\backepsilon,
\eth, \Finv, \hbar
,,,,ð,,
26 \Im, \imath, \jmath, \Bbbk, \ell, \mho,
\wp, \Re, \circledS, \S, \P, \AA
,ı,ȷ,𝕜,,,,,,§,,
Modular arithmetic
27s_k \equiv 0 \pmod{m}sk0(modm)
28a \bmod bamodb
29\gcd(m, n), \operatorname{lcm}(m, n)gcd(m,n),lcm(m,n)
30\mid, \nmid, \shortmid, \nshortmid|,,,
Radicals
31 \surd, \sqrt{2}, \sqrt[n]{2},
\sqrt[3]{\frac{x^3+y^3}{2}}
,2,2n,x3+y323
Operators
32+, -, \pm, \mp, \dotplus+,,±,,
33\times, \div, \divideontimes, /,\backslash×,÷,,,\
34\cdot, * \ast, \star, \circ, \bullet,*,,,
35\boxplus, \boxminus, \boxtimes, \boxdot,,,
36\oplus, \ominus, \otimes, \oslash, \odot,,,,
37\circleddash, \circledcirc, \circledast,,
38\bigoplus, \bigotimes, \bigodot,,
Sets
39{ }, \O \empty \emptyset, \varnothing{},Ø,ø
40\in, \notin \not\in, \ni, \not\ni,∉,,∌
41\cap, \Cap, \sqcap, \bigcap,,,
42 \cup, \Cup, \sqcup, \bigcup, \bigsqcup,
\uplus, \biguplus
,,,,,,
43\setminus, \smallsetminus, \times,,×
44\subset, \Subset, \sqsubset,,
45\supset, \Supset, \sqsupset,,
46 \subseteq, \nsubseteq, \subsetneq,
\varsubsetneq, \sqsubseteq
,,,⊊︀,
47 \supseteq, \nsupseteq, \supsetneq,
\varsupsetneq, \sqsupseteq
,,,,
48 \subseteqq, \nsubseteqq, \subsetneqq,
\varsubsetneqq
,,,⫋︀
49 \supseteqq, \nsupseteqq, \supsetneqq,
\varsupsetneqq
,,,⫌︀
Relations
50=, \ne, \neq, \equiv, \not\equiv=,,,,≢
51 \doteq, \doteqdot,
\overset{\underset{\mathrm{def}}{}}{=}, :=
,,=def,:=
52 \sim, \nsim, \backsim, \thicksim, \simeq,
\backsimeq, \eqsim, \cong, \ncong
,,,,,,,,
53 \approx, \thickapprox, \approxeq, \asymp,
\propto, \varpropto
,,,,,
54 <, \nless, \ll, \not\ll, \lll, \not\lll,
\lessdot
<,,,≪̸,,⋘̸,
55 \le, \leq, \lneq, \leqq, \nleq, \nleqq,
\lneqq, \lvertneqq
,,,,,,,≨︀
56 \ge, \geq, \gneq, \geqq, \ngeq, \ngeqq,
\gneqq, \gvertneqq
,,,,,,,≩︀
57 \lessgtr, \lesseqgtr, \lesseqqgtr,
\gtrless, \gtreqless, \gtreqqless
,,,,,
58\leqslant, \nleqslant, \eqslantless,,
59\geqslant, \ngeqslant, \eqslantgtr,,
60\lesssim, \lnsim, \lessapprox, \lnapprox,,,
61\gtrsim, \gnsim, \gtrapprox, \gnapprox,,,
62\prec, \nprec, \preceq, \npreceq,\precneqq,,,,
63\succ, \nsucc, \succeq, \nsucceq,\succneqq,,,,
64\preccurlyeq, \curlyeqprec,
65\succcurlyeq, \curlyeqsucc,
66 \precsim, \precnsim, \precapprox,
\precnapprox
,,,
67 \succsim, \succnsim, \succapprox,
\succnapprox
,,,
Geometric
68 \parallel, \nparallel, \shortparallel,
\nshortparallel
,,,
69 \perp, \angle, \sphericalangle,
\measuredangle, 45^\circ
,,,,45
70 \Box, \square, \blacksquare, \diamond,
\Diamond, \lozenge, \blacklozenge,\bigstar
,,,,,,,
71 \bigcirc, \triangle, \bigtriangleup,
\bigtriangledown
,,,
72\vartriangle, \triangledown,
73 \blacktriangle, \blacktriangledown,
\blacktriangleleft, \blacktriangleright
,,,
Logic
74\forall, \exists, \nexists,,
75\therefore, \because, \And,,&
76\lor \vee, \curlyvee, \bigvee,,
77\land \wedge, \curlywedge, \bigwedge,,
78 \bar{q}, \bar{abc}, \overline{q},
\overline{abc},\\
\lnot \neg, \not\operatorname{R},\bot,\top
q,abc,q_,abc_,¬¬,̸R,,
79\vdash \dashv, \vDash, \Vdash, \models,,,
80\Vvdash \nvdash \nVdash \nvDash \nVDash
81\ulcorner \urcorner \llcorner \lrcorner
Arrows
82\Rrightarrow, \Lleftarrow,
83 \Rightarrow, \nRightarrow,
\Longrightarrow, \implies
,,,
84\Leftarrow, \nLeftarrow, \Longleftarrow,,
85 \Leftrightarrow, \nLeftrightarrow,
\Longleftrightarrow, \iff
,,,
86\Uparrow, \Downarrow, \Updownarrow,,
87 \rightarrow \to, \nrightarrow,
\longrightarrow
,,
88 \leftarrow \gets, \nleftarrow,
\longleftarrow
,,
89 \leftrightarrow, \nleftrightarrow,
\longleftrightarrow
,,
90\uparrow, \downarrow, \updownarrow,,
91\nearrow, \swarrow, \nwarrow, \searrow,,,
92\mapsto, \longmapsto,
93 \rightharpoonup \rightharpoondown
\leftharpoonup \leftharpoondown
\upharpoonleft \upharpoonright
\downharpoonleft \downharpoonright
\rightleftharpoons \leftrightharpoons
94 \curvearrowleft \circlearrowleft \Lsh
\upuparrows \rightrightarrows
\rightleftarrows \rightarrowtail
\looparrowright
95 \curvearrowright \circlearrowright \Rsh
\downdownarrows \leftleftarrows
\leftrightarrows \leftarrowtail
\looparrowleft
96 \hookrightarrow \hookleftarrow \multimap
\leftrightsquigarrow \rightsquigarrow
\twoheadrightarrow \twoheadleftarrow
Special
97\amalg \P \S %\dagger\ddagger\ldots\cdots⨿§%
98 \smile \frown \wr \triangleleft
\triangleright
99 \diamondsuit, \heartsuit, \clubsuit,
\spadesuit, \Game, \flat, \natural, \sharp
,,,,,,,
Unsorted
100 \diagup \diagdown \centerdot \ltimes
\rtimes \leftthreetimes \rightthreetimes
101 \eqcirc \circeq \triangleq \bumpeq\Bumpeq
\doteqdot \risingdotseq \fallingdotseq
102 \intercal \barwedge \veebar
\doublebarwedge \between \pitchfork
103 \vartriangleleft \ntriangleleft
\vartriangleright \ntriangleright
104 \trianglelefteq \ntrianglelefteq
\trianglerighteq \ntrianglerighteq
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Larger expressions
SourceTemml
105a^2, a^{x+3}a2,ax+3
106a_2a2
107 10^{30} a^{2+2}
a_{i,j} b_{f'}
1030a2+2ai,jbf
108 x_2^3
{x_2}^3
x23x23
10910^{10^{8}}10108
110 \sideset{_1^2}{_3^4}\prod_a^b
{}_1^2\!\Omega_3^4
3412ab 12Ω34
111 \overset{\alpha}{\omega}
\underset{\alpha}{\omega}
\overset{\alpha}{\underset{\gamma}{\omega}}
\stackrel{\alpha}{\omega}
ωαωαωγαωα
112 x', y'', f', f''
x^\prime, y^{\prime\prime}
x,y,f,fx,y
113\dot{x}, \ddot{x}x˙,x¨
114 \hat a \ \bar b \ \vec c
\overrightarrow{a b} \ \overleftarrow{c d}
\widehat{d e f}
\overline{g h i} \ \underline{j k l}
a^ b cab cddef^ghi_ jkl_
115\overset{\frown} {AB}A
116 A \xleftarrow{n+\mu-1} B
\xrightarrow[T]{n\pm i-1} C
An+μ1BTn±i1C
117\overbrace{ 1+2+\cdots+100 }^{5050}1+2++1005050
118\underbrace{ a+b+\cdots+z }_{26}a+b++z26
119\sum_{k=1}^N k^2k=1Nk2
120\textstyle \sum_{k=1}^N k^2k=1Nk2
121\frac{\sum_{k=1}^N k^2}{a}k=1Nk2a
122\frac{\sum\limits^{^N}_{k=1} k^2}{a}k=1Nk2a
123\prod_{i=1}^N x_ii=1Nxi
124\textstyle \prod_{i=1}^N x_ii=1Nxi
125\coprod_{i=1}^N x_ii=1Nxi
126\textstyle \coprod_{i=1}^N x_ii=1Nxi
127\lim_{n \to \infty}x_nlimnxn
128\textstyle \lim_{n \to \infty}x_nlimnxn
129\int\limits_{1}^{3}\frac{e^3/x}{x^2}\, dx13e3xx2dx
130\int_{1}^{3}\frac{e^3/x}{x^2}\, dx13e3xx2dx
131\textstyle \int\limits_{-N}^{N} e^x dxNNexdx
132\textstyle \int_{-N}^{N} e^x dxNNexdx
133\iint\limits_D dx\,dyDdxdy
134\iiint\limits_E dx\,dy\,dzEdxdydz
135\iiiint\limits_F dx\,dy\,dz\,dtFdxdydzdt
136\int_{(x,y)\in C} x^3\, dx + 4y^2\, dy(x,y)Cx3dx+4y2dy
137\oint_{(x,y)\in C} x^3\, dx + 4y^2\, dy(x,y)Cx3dx+4y2dy
138\bigcap_{i=1}^n E_ii=1nEi
139\bigcup_{i=1}^n E_ii=1nEi
Fractions, matrices, multiline
140\frac{2}{4}=0.5 or {2 \over 4}=0.524=0.5 or 24=0.5
141\tfrac{2}{4} = 0.524=0.5
142 \dfrac{2}{4} = 0.5 \qquad \dfrac{2}{c +
\dfrac{2}{d + \dfrac{2}{4}}} = a
24=0.52c+2d+24=a
143\cfrac{2}{c +\cfrac{2}{d +\cfrac{2}{4}}} = a2c+2d+24=a
144 \cfrac{x}{1 + \cfrac{\cancel{y}}
{\cancel{y}}} = \cfrac{x}{2}
x1+yy=x2
145\binom{n}{k}(nk)
146\tbinom{n}{k}(nk)
147\dbinom{n}{k}(nk)
148 \begin{matrix}
x & y \\
z & v
\end{matrix}
xyzv
149 \begin{vmatrix}
x & y \\
z & v
\end{vmatrix}
|xyzv|
150 \begin{Vmatrix}
x & y \\
z & v
\end{Vmatrix}
xyzv
151 \begin{bmatrix}
0 & \cdots & 0 \\
\vdots & \ddots & \vdots \\
0 & \cdots & 0
\end{bmatrix}
[0000]
152 \begin{Bmatrix}
x & y \\
z & v
\end{Bmatrix}
{xyzv}
153 \begin{pmatrix}
x & y \\
z & v
\end{pmatrix}
(xyzv)
154 \bigl( \begin{smallmatrix}
a&b\\ c&d
\end{smallmatrix} \bigr)
(abcd)
155 f(n) = \begin{cases}
n/2, & \text{if }n\text{ is even} \\
3n+1, & \text{if }n\text{ is odd} \end{cases}
f(n)={n2,if n is even3n+1,if n is odd
156 \begin{cases}
3x + 5y + z \\
7x - 2y + 4z \\
-6x + 3y + 2z \end{cases}
{3x+5y+z7x2y+4z6x+3y+2z
157 \begin{align}
f(x) & = (a+b)^2 \\
& = a^2+2ab+b^2 \\
\end{align}
f(x)=(a+b)2=a2+2ab+b2
158 \begin{alignat}{2}
f(x) & = (a+b)^2 \\
& = a^2+2ab+b^2 \\
\end{alignat}
f(x)=(a+b)2=a2+2ab+b2
159 \begin{align}
f(a,b) & = (a+b)^2 && = (a+b)(a+b) \\
& = a^2+ab+ba+b^2 && = a^2+2ab+b^2 \\
\end{align}
f(a,b)=(a+b)2=(a+b)(a+b)=a2+ab+ba+b2=a2+2ab+b2
159 \begin{alignat}{3}
f(a,b) & = (a+b)^2 && = (a+b)(a+b) \\
& = a^2+ab+ba+b^2 && = a^2+2ab+b^2 \\
\end{alignat}
f(a,b)=(a+b)2=(a+b)(a+b)=a2+ab+ba+b2=a2+2ab+b2
160 \begin{array}{lcl}
z & = & a \\
f(x,y,z) & = & x + y + z \end{array}
z=af(x,y,z)=x+y+z
161 \begin{array}{lcr}
z & = & a \\
f(x,y,z) & = & x + y + z \end{array}
z=af(x,y,z)=x+y+z
162 \begin{alignat}{4}
F:\; && C(X) && \;\to\; & C(X) \\
&& g && \;\mapsto\; & g^2 \end{alignat}
F:C(X)C(X)gg2
163 \begin{alignat}{4}
F:\; && C(X) && \;\to\; && C(X) \\
&& g && \;\mapsto\; && g^2 \end{alignat}
F:C(X)C(X)gg2
164 f(x) \,\! \sum_{n=0}^\infty a_n x^n
= a_0+a_1x+a_2x^2+\cdots
f(x) =n=0anxn =a0+a1x+a2x2+
165 \begin{array}{|c|c|c|}
a & b & S \\
\hline
0 & 0 & 1 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\end{array}
abS001011101110
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Delimiters
166( \frac{1}{2} )^n(12)n
167\left ( \frac{1}{2} \right )^n(12)n
168\left ( \frac{a}{b} \right )(ab)
169 \left [ \frac{a}{b} \right ] \quad
\left \lbrack \frac{a}{b} \right \rbrack
[ab][ab]
170 \left { \frac{a}{b} \right } \quad
\left \lbrace \frac{a}{b} \right \rbrace
{ab}{ab}
171\left \langle \frac{a}{b} \right \rangleab
172 \left | \frac{a}{b} \right \vert \quad
\left \Vert \frac{c}{d} \right |
|ab|cd
173 \left \lfloor \frac{a}{b} \right \rfloor
\quad \left \lceil \frac{c}{d} \right \rceil
abcd
174\left / \frac{a}{b} \right \backslashab
175 \left\uparrow\frac{a}{b}\right\downarrow\;
\left\Uparrow\frac{a}{b}\right\Downarrow\;
\left \updownarrow \frac{a}{b} \right
\Updownarrow
ababab
176 \left [ 0,1 \right )
\left \langle \psi \right |
[0,1)ψ|
177\left . \frac{A}{B} \right } \to XAB}X
178 ( \bigl( \Bigl( \biggl( \Biggl( \dots
\Biggr] \biggr] \Bigr] \bigr] ]
(((((]]]]]
179 { \bigl{ \Bigl{ \biggl{ \Biggl{ \dots
\Biggr\rangle \biggr\rangle \Bigr\rangle
\bigr\rangle \rangle
{{{{{
180 | \big| \Big| \bigg| \Bigg| \dots
\Bigg| \bigg| \Big| \big| |
|||||
181 \lfloor \bigl\lfloor \Bigl\lfloor
\biggl\lfloor \Biggl\lfloor \dots
\Biggr\rceil \biggr\rceil \Bigr\rceil
\bigr\rceil \ceil
182 \uparrow \big\uparrow \Big\uparrow
\bigg\uparrow \Bigg\uparrow \dots
\Bigg\Downarrow \bigg\Downarrow
\Big\Downarrow \big\Downarrow \Downarrow
183 \updownarrow\big\updownarrow\Big\updownarrow
\bigg\updownarrow \Bigg\updownarrow \dots
\Bigg\Updownarrow \bigg\Updownarrow \Big
\Updownarrow \big\Updownarrow \Updownarrow
184 / \big/ \Big/ \bigg/ \Bigg/ \dots
\Bigg\backslash \bigg\backslash \Big
\backslash \big\backslash \backslash
\
Greek Alphabet
185 \Alpha \Beta \Gamma \Delta \Epsilon \Zeta
\Eta \Theta
ΑΒΓΔΕΖΗΘ
186\Iota \Kappa \Lambda \Mu \Nu \Xi \Omicron \PiΙΚΛΜΝΞΟΠ
187 \Rho \Sigma \Tau \Upsilon \Phi \Chi \Psi
\Omega
ΡΣΤΥΦΧΨΩ
188 \alpha \beta \gamma \delta \epsilon \zeta
\eta \theta
αβγδϵζηθ
189\iota \kappa \lambda \mu \nu \xi \omicron \piικλμνξοπ
190 \rho \sigma \tau \upsilon \phi \chi \psi
\omega
ρστυϕχψω
191 \varGamma \varDelta \varTheta \varLambda
\varXi \varPi \varSigma \varPhi \varUpsilon
\varOmega
𝛤𝛥𝛩𝛬𝛯𝛱𝛴𝛷𝛶𝛺
192 \varepsilon \digamma \varkappa \varpi
\varrho \varsigma \vartheta \varphi
εϝϰϖϱςϑφ
Hebrew symbols
193\aleph \beth \gimel \daleth
Blackboard bold
194 \mathbb{ABCDEFGHI}
\mathbb{JKLMNOPQR}
\mathbb{STUVWXYZ}
𝔸𝔹𝔻𝔼𝔽𝔾𝕀𝕁𝕂𝕃𝕄𝕆𝕊𝕋𝕌𝕍𝕎𝕏𝕐
Boldface
195 \mathbf{ABCDEFGHI}
\mathbf{JKLMNOPQR}
\mathbf{STUVWXYZ}
\mathbf{abcdefghijklm}
\mathbf{nopqrstuvwxyz}
\mathbf{0123456789}
𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳𝟎𝟏𝟐𝟑𝟒𝟓𝟔𝟕𝟖𝟗
Boldface Greek
196 \boldsymbol{\Alpha \Beta \Gamma \Delta
\Epsilon \Zeta \Eta \Theta}
𝚨𝚩𝚪𝚫𝚬𝚭𝚮𝚯
197 \boldsymbol{\Iota \Kappa \Lambda \Mu \Nu \Xi
\Omicron \Pi}
𝚰𝚱𝚲𝚳𝚴𝚵𝚶𝚷
198 \boldsymbol{\Rho \Sigma \Tau \Upsilon \Phi
\Chi \Psi \Omega}
𝚸𝚺𝚻𝚼𝚽𝚾𝚿𝛀
199 \boldsymbol{\alpha \beta \gamma \delta
\epsilon \zeta \eta \theta}
𝜶𝜷𝜸𝜹𝝐𝜻𝜼𝜽
200 \boldsymbol{\iota \kappa \lambda \mu \nu \xi
\omicron \pi}
𝜾𝜿𝝀𝝁𝝂𝝃𝝄𝝅
201 \boldsymbol{\rho \sigma \tau \upsilon \phi
\chi \psi \omega}
𝝆𝝈𝝉𝝊𝝓𝝌𝝍𝝎
202 \boldsymbol{\varepsilon\digamma\varkappa
\varpi}
𝜺ϝ𝝒𝝕
203\boldsymbol{\varrho\varsigma\vartheta\varphi}𝝔𝝇𝝑𝝋
Italics
204\mathit{0123456789}0123456789
Greek Italics
205 \mathit{\Alpha \Beta \Gamma \Delta \Epsilon
\Zeta \Eta \Theta}
ΑΒΓΔΕΖΗΘ
206 \mathit{\Iota \Kappa \Lambda \Mu \Nu \Xi
\Omicron \Pi}
ΙΚΛΜΝΞΟΠ
207 \mathit{\Rho \Sigma \Tau \Upsilon \Phi \Chi
\Psi \Omega}
ΡΣΤΥΦΧΨΩ
Greek uppercase boldface italics
208 \boldsymbol{\varGamma \varDelta \varTheta
\varLambda}
𝜞𝜟𝜣𝜦
209 \boldsymbol{\varXi \varPi \varSigma
\varUpsilon \varOmega}
𝜩𝜫𝜮𝜰𝜴
Roman typeface
210 \mathrm{ABCDEFGHI}
\mathrm{JKLMNOPQR}
\mathrm{STUVWXYZ}
\mathrm{abcdefghijklm}
\mathrm{nopqrstuvwxyz}
\mathrm{0123456789}
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
Sans serif
211 \mathsf{ABCDEFGHI}
\mathsf{JKLMNOPQR}
\mathsf{STUVWXYZ}
\mathsf{abcdefghijklm}
\mathsf{nopqrstuvwxyz}
\mathsf{0123456789}
𝖠𝖡𝖢𝖣𝖤𝖥𝖦𝖧𝖨𝖩𝖪𝖫𝖬𝖭𝖮𝖯𝖰𝖱𝖲𝖳𝖴𝖵𝖶𝖷𝖸𝖹𝖺𝖻𝖼𝖽𝖾𝖿𝗀𝗁𝗂𝗃𝗄𝗅𝗆𝗇𝗈𝗉𝗊𝗋𝗌𝗍𝗎𝗏𝗐𝗑𝗒𝗓𝟢𝟣𝟤𝟥𝟦𝟧𝟨𝟩𝟪𝟫
Sans serif Greek
212 \mathsf{\Alpha \Beta \Gamma \Delta \Epsilon
\Zeta \Eta \Theta}
𝝖𝝗𝝘𝝙𝝚𝝛𝝜𝝝
213 \mathsf{\Iota \Kappa \Lambda \Mu \Nu \Xi
\Omicron \Pi}
𝝞𝝟𝝠𝝡𝝢𝝣𝝤𝝥
214 \mathsf{\Rho \Sigma \Tau \Upsilon \Phi \Chi
\Psi \Omega}
𝝦𝝨𝝩𝝪𝝫𝝬𝝭𝝮
-

Unicode has special code points for bold Greek sans-serif, but no code points for
regular-weight Greek sans-serif. Since Chromium is not going to support the math-variant
attribute, these bold Greek sans-serif glyphs are the best approximation I can make to
sans-serif Greek.

-
- - - - - - - - - - - - - - - - - - - -
Calligraphy
215 \mathcal{ABCDEFGHI}
\mathcal{JKLMNOPQR}
\mathcal{STUVWXYZ}
\mathcal{abcdefghi}
\mathcal{jklmnopqr}
\mathcal{stuvwxyz}
𝒜𝒞𝒟𝒢𝒥𝒦𝒩𝒪𝒫𝒬𝒮𝒯𝒰𝒱𝒲𝒳𝒴𝒵𝒶𝒷𝒸𝒹𝒻𝒽𝒾𝒿𝓀𝓁𝓂𝓃𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏
Fraktur
216 \mathfrak{ABCDEFGHI}
\mathfrak{JKLMNOPQR}
\mathfrak{STUVWXYZ}
\mathfrak{abcdefghi}
\mathfrak{jklmnopqr}
\mathfrak{stuvwxyz}
𝔄𝔅𝔇𝔈𝔉𝔊𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔𝔖𝔗𝔘𝔙𝔚𝔛𝔜𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷
Scriptstyle text
217{\scriptstyle\text{abcdefghijklm}}abcdefghijklm
Mixed text faces
218x y zxyz
219\text{x y z}x y z
220\text{if} n \text{is even}ifnis even
221\text{if }n\text{ is even}if n is even
222\text{if}~n\ \text{is even}if n is even
Color
223 {\color{Blue}x^2}+{\color{Orange}2x}-
{\color{LimeGreen}1}
x2+2x1
224 x_{1,2}=\frac{{\color{Blue}-b}\pm
\sqrt{\color{Red}b^2-4ac}}{\color{Green}2a }
x1,2=b±b24ac2a
225 {\color{Blue}x^2}+{\color{Orange}2x}-
{\color{LimeGreen}1}
x2+2x1
226 \color{Blue}x^2\color{Black}+\color{Orange}
2x\color{Black}-\color{LimeGreen}1
x2+2x1
227 \color{Blue}{x^2}+\color{Orange}{2x}-
\color{LimeGreen}{1}
x2+2x1
228 \definecolor{myorange}{rgb}{1,0.65,0.4}
\color{myorange}e^{i \pi}\color{Black} + 1= 0
eiπ+1=0
-

For color names, see the color section in the Temml function support page.

-
- - - - - - - - - - - - - - - - -
Spacing
229 a \qquad b
a \quad b
a\ b
a \text{ } b
a\;b
a\,b
ab
a b
\mathit{ab}
a\!b
ababa ba babababababab
230| \uparrow \rangle|
231\left| \uparrow \right\rangle|
232| {\uparrow} \rangle|
233| \mathord\uparrow \rangle|
Temml replacements for wiki workarounds
234 \oiint\limits_D dx\,dy
\oiiint\limits_E dx\,dy\,dz
Ddxdy Edxdydz
234\wideparen{AB}AB
235\dddot{x}x
236 \operatorname*{median}_
{j\,\ne\,i} X_{i,j}
medianjiXi,j
237\sout{q}q
238\mathrlap{\,/}{=}=
239\text{\textsf{textual description}}𝗍𝖾𝗑𝗍𝗎𝖺𝗅 𝖽𝖾𝗌𝖼𝗋𝗂𝗉𝗍𝗂𝗈𝗇
240α παπ
-

mhchem examples are displayed on their own test page.

-
- - - - - - - - - - - - - - - - - - - - - - -
Examples of implemented TeX formulas
241ax^2 + bx + c = 0ax2+bx+c=0
242x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}x=b±b24ac2a
243 \left( \frac{\left(3-x\right)
\times 2}{3-x} \right)
((3x)×23x)
244 S_{\text{new}} = S_{\text{old}} -
\frac{ \left( 5-T \right) ^2} {2}
Snew=Sold(5T)22
245 \int_a^x \int_a^s f(y)\,dy\,ds =
\int_a^x f(y)(x-y)\,dy
axasf(y)dyds=axf(y)(xy)dy
246 \int_e^{\infty}\frac {1}{t(\ln t)^2}dt =
\left. \frac{-1}{\ln t}\right\vert_e^\infty
= 1
e1t(lnt)2dt=1lnt|e=1
247\det(\mathsf{A}-\lambda\mathsf{I}) = 0det(𝖠λ𝖨)=0
248\sum_{i=0}^{n-1} ii=0n1i
249 \sum_{m=1}^\infty\sum_{n=1}^\infty
\frac{m^2 n}{3^m\left(m 3^n + n 3^m\right)}
m=1n=1m2n3m(m3n+n3m)
250u'' + p(x)u' + q(x)u=f(x),\quad x>au+p(x)u+q(x)u=f(x),x>a
251 |\bar{z}| = |z|, |(\bar{z})^n| = |z|^n,
\arg(z^n) = n \arg(z)
|z|=|z|,|(z)n|=|z|n,arg(zn)=narg(z)
252\lim_{z\to z_0} f(z)=f(z_0)limzz0f(z)=f(z0)
253 \phi_n(\kappa) =
\frac{1}{4\pi^2\kappa^2} \int_0^\infty
\frac{\sin(\kappa R)}{\kappa R}
\frac{\partial}{\partial R}
\left [ R^2\frac{\partial D_n(R)}
{\partial R} \right ] \,dR
ϕn(κ)=14π2κ20sin(κR)κRR[R2Dn(R)R]dR
254 \phi_n(\kappa) = 0.033C_n^2\kappa^{-11/3},
\quad\frac{1}{L_0}\ll\kappa\ll\frac{1}{l_0}
ϕn(κ)=0.033Cn2κ113,1L0κ1l0
255 f(x) = \begin{cases}
1 & -1 \le x < 0 \\
\frac{1}{2} & x = 0 \\
1 - x^2 & \text{otherwise}
\end{cases}
f(x)={11x<012x=01x2otherwise
256 {}_pF_q(a_1,\dots,a_p;c_1,\dots,c_q;z)
= \sum_{n=0}^\infty
\frac{(a1)_n\cdots(ap)_n}
{(c_1)_n\cdots(c_q)_n}\frac{z^n}{n!}
pFq(a1,,ap;c1,,cq;z)=n=0(a1)n(ap)n(c1)n(cq)nznn!
258\frac{a}{b}\ \tfrac{a}{b}ab ab
259S=dD\sin\alphaS=dDsinα
260 V = \frac{1}{6} \pi h \left [ 3 \left
( r1^2 + r2^2 \right ) + h^2 \right ]
V=16πh[3(r12+r22)+h2]
261 \begin{align}
u & = \tfrac{1}{\sqrt{2}}(x+y) \qquad &
x &= \tfrac{1}{\sqrt{2}}(u+v) \\[0.6ex]
v & = \tfrac{1}{\sqrt{2}}(x-y) \qquad &
y &= \tfrac{1}{\sqrt{2}}(u-v)
\end{align}
u=12(x+y)x=12(u+v)v=12(xy)y=12(uv)
-

That concludes the tests from Wikipedia. Now a few more tests.

-
- - - - - -
Linear Logic
262A \with B \parr CA&BC
263a \coh \oc b \incoh \wn c \scoh d \sincoh ea!b?cde
264a \Perp \shpos b \multimapinv \shneg cabc
- - - -
Nested font size
265\mathrm{f{\large f{\normalsize f{\tiny f}}}}ffff
-
- - diff --git a/site/xml-formatter.js b/site/xml-formatter.js deleted file mode 100644 index c06fbf84..00000000 --- a/site/xml-formatter.js +++ /dev/null @@ -1,432 +0,0 @@ -require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i true); - - function nextChild() { - return tag() || content() || comment() || cdata(); - } - - function nextRootChild() { - match(/\s*/); - return tag(true) || comment() || doctype() || processingInstruction(false); - } - - function document() { - const decl = declaration(); - const children = []; - let documentRootNode; - let child = nextRootChild(); - - while (child) { - if (child.node.type === 'Element') { - if (documentRootNode) { - throw new Error('Found multiple root nodes'); - } - documentRootNode = child.node; - } - - if (!child.excluded) { - children.push(child.node); - } - - child = nextRootChild(); - } - - if (!documentRootNode) { - throw new Error('Failed to parse XML'); - } - - return { - declaration: decl ? decl.node : null, - root: documentRootNode, - children - }; - } - - function declaration() { - return processingInstruction(true); - } - - function processingInstruction(matchDeclaration) { - const m = matchDeclaration ? match(/^<\?(xml)\s*/) : match(/^<\?([\w-:.]+)\s*/); - if (!m) return; - - // tag - const node = { - name: m[1], - type: 'ProcessingInstruction', - attributes: {} - }; - - // attributes - while (!(eos() || is('?>'))) { - const attr = attribute(); - if (!attr) return node; - node.attributes[attr.name] = attr.value; - } - - match(/\?>/); - - return { - excluded: matchDeclaration ? false : options.filter(node) === false, - node - }; - } - - function tag(matchRoot) { - const m = match(/^<([\w-:.]+)\s*/); - if (!m) return; - - // name - const node = { - type: 'Element', - name: m[1], - attributes: {}, - children: [] - }; - - // attributes - while (!(eos() || is('>') || is('?>') || is('/>'))) { - const attr = attribute(); - if (!attr) return node; - node.attributes[attr.name] = attr.value; - } - - const excluded = matchRoot ? false : options.filter(node) === false; - - // self closing tag - if (match(/^\s*\/>/)) { - node.children = null; - return { - excluded, - node - }; - } - - match(/\??>/); - - if (!excluded) { - // children - let child = nextChild(); - while (child) { - if (!child.excluded) { - node.children.push(child.node); - } - child = nextChild(); - } - } - - // closing - match(/^<\/[\w-:.]+>/); - - return { - excluded, - node - }; - } - - function doctype() { - const m = match(/^]*>/); - if (m) { - const node = { - type: 'DocumentType', - content: m[0] - }; - return { - excluded: options.filter(node) === false, - node - }; - } - } - - function cdata() { - if (xml.startsWith(''); - if (endPositionStart > -1) { - const endPositionFinish = endPositionStart + 3; - const node = { - type: 'CDATA', - content: xml.substring(0, endPositionFinish) - }; - xml = xml.slice(endPositionFinish); - return { - excluded: options.filter(node) === false, - node - }; - } - } - } - - function comment() { - const m = match(/^/); - if (m) { - const node = { - type: 'Comment', - content: m[0] - }; - return { - excluded: options.filter(node) === false, - node - }; - } - } - - function content() { - const m = match(/^([^<]+)/); - if (m) { - const node = { - type: 'Text', - content: m[1] - }; - return { - excluded: options.filter(node) === false, - node - }; - } - } - - function attribute() { - const m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/); - if (!m) return; - return {name: m[1], value: strip(m[2])} - } - - /** - * Strip quotes from `val`. - */ - function strip(val) { - return val.replace(/^['"]|['"]$/g, ''); - } - - /** - * Match `re` and advance the string. - */ - function match(re) { - const m = xml.match(re); - if (!m) return; - xml = xml.slice(m[0].length); - return m; - } - - /** - * End-of-source. - */ - function eos() { - return 0 === xml.length; - } - - /** - * Check for `prefix`. - */ - function is(prefix) { - return 0 === xml.indexOf(prefix); - } - - xml = xml.trim(); - - return document(); -} - -module.exports = parse; - -},{}],"xml-formatter":[function(require,module,exports){ -/** - * @typedef {Object} XMLFormatterOptions - * @property {String} [indentation=' '] The value used for indentation - * @property {function(node): boolean} [filter] Return false to exclude the node. - * @property {Boolean} [collapseContent=false] True to keep content in the same line as the element. Only works if element contains at least one text node - * @property {String} [lineSeparator='\r\n'] The line separator to use - * @property {String} [whiteSpaceAtEndOfSelfclosingTag=false] to either end ad self closing tag with `` or `` - */ - -/** - * @typedef {Object} XMLFormatterState - * @param {String} content - * @param {Number} level - * @param {XMLFormatterOptions} options - */ - -/** - * @param {XMLFormatterState} state - * @return {void} - */ -function newLine(state) { - if (!state.options.indentation && !state.options.lineSeparator) return; - state.content += state.options.lineSeparator; - let i; - for (i = 0; i < state.level; i++) { - state.content += state.options.indentation; - } -} - -/** - * @param {XMLFormatterState} state - * @param {String} content - * @return {void} - */ -function appendContent(state, content) { - state.content += content; -} - -/** - * @param {Object} node - * @param {XMLFormatterState} state - * @param {Boolean} preserveSpace - * @return {void} - */ -function processNode(node, state, preserveSpace) { - if (typeof node.content === 'string') { - processContentNode(node, state, preserveSpace); - } else if (node.type === 'Element') { - processElementNode(node, state, preserveSpace); - } else if (node.type === 'ProcessingInstruction') { - processProcessingIntruction(node, state, preserveSpace); - } else { - throw new Error('Unknown node type: ' + node.type); - } -} - -/** - * @param {Object} node - * @param {XMLFormatterState} state - * @param {Boolean} preserveSpace - * @return {void} - */ -function processContentNode(node, state, preserveSpace) { - if (!preserveSpace) { - node.content = node.content.trim(); - } - if (node.content.length > 0) { - if (!preserveSpace && state.content.length > 0) { - newLine(state); - } - appendContent(state, node.content); - } -} - -/** - * @param {Object} node - * @param {XMLFormatterState} state - * @param {Boolean} preserveSpace - * @return {void} - */ -function processElementNode(node, state, preserveSpace) { - if (!preserveSpace && state.content.length > 0) { - newLine(state); - } - - appendContent(state, '<' + node.name); - processAttributes(state, node.attributes); - - if (node.children === null) { - const selfClosingNodeClosingTag = state.options.whiteSpaceAtEndOfSelfclosingTag ? ' />' : '/>' - // self-closing node - appendContent(state, selfClosingNodeClosingTag); - } else if (node.children.length === 0) { - // empty node - appendContent(state, '>'); - } else { - - appendContent(state, '>'); - - state.level++; - - let nodePreserveSpace = node.attributes['xml:space'] === 'preserve'; - - if (!nodePreserveSpace && state.options.collapseContent) { - - const containsTextNodes = node.children.some(function(child) { - return child.type === 'Text' && child.content.trim() !== ''; - }); - - if (containsTextNodes) { - nodePreserveSpace = true; - } - } - - node.children.forEach(function(child) { - processNode(child, state, preserveSpace || nodePreserveSpace, state.options); - }); - - state.level--; - - if (!preserveSpace && !nodePreserveSpace) { - newLine(state); - } - appendContent(state, ''); - } -} - -/** - * @param {XMLFormatterState} state - * @param {Record} attributes - * @return {void} - */ -function processAttributes(state, attributes) { - Object.keys(attributes).forEach(function(attr) { - const escaped = attributes[attr].replace(/"/g, '"'); - appendContent(state, ' ' + attr + '="' + escaped + '"'); - }); -} - -/** - * @param {Object} node - * @param {XMLFormatterState} state - * @return {void} - */ -function processProcessingIntruction(node, state) { - if (state.content.length > 0) { - newLine(state); - } - appendContent(state, ''); -} - - -/** - * Converts the given XML into human readable format. - * - * @param {String} xml - * @param {XMLFormatterOptions} options - * @returns {string} - */ -function format(xml, options = {}) { - options.indentation = 'indentation' in options ? options.indentation : ' '; - options.collapseContent = options.collapseContent === true; - options.lineSeparator = 'lineSeparator' in options ? options.lineSeparator : '\r\n'; - options.whiteSpaceAtEndOfSelfclosingTag = !!options.whiteSpaceAtEndOfSelfclosingTag; - - const parser = require('xml-parser-xo'); - const parsedXml = parser(xml, {filter: options.filter}); - const state = {content: '', level: 0, options: options}; - - if (parsedXml.declaration) { - processProcessingIntruction(parsedXml.declaration, state); - } - - parsedXml.children.forEach(function(child) { - processNode(child, state, false); - }); - - return state.content; -} - - -module.exports = format; - -},{"xml-parser-xo":1}]},{},[]); diff --git a/src/Lexer.js b/src/Lexer.js deleted file mode 100644 index 45d69378..00000000 --- a/src/Lexer.js +++ /dev/null @@ -1,121 +0,0 @@ -/** - * The Lexer class handles tokenizing the input in various ways. Since our - * parser expects us to be able to backtrack, the lexer allows lexing from any - * given starting point. - * - * Its main exposed function is the `lex` function, which takes a position to - * lex from and a type of token to lex. It defers to the appropriate `_innerLex` - * function. - * - * The various `_innerLex` functions perform the actual lexing of different - * kinds. - */ - -import ParseError from "./ParseError"; -import SourceLocation from "./SourceLocation"; -import { Token } from "./Token"; - -/* The following tokenRegex - * - matches typical whitespace (but not NBSP etc.) using its first two groups - * - does not match any control character \x00-\x1f except whitespace - * - does not match a bare backslash - * - matches any ASCII character except those just mentioned - * - does not match the BMP private use area \uE000-\uF8FF - * - does not match bare surrogate code units - * - matches any BMP character except for those just described - * - matches any valid Unicode surrogate pair - * - mathches numerals - * - matches a backslash followed by one or more whitespace characters - * - matches a backslash followed by one or more letters then whitespace - * - matches a backslash followed by any BMP character - * Capturing groups: - * [1] regular whitespace - * [2] backslash followed by whitespace - * [3] anything else, which may include: - * [4] left character of \verb* - * [5] left character of \verb - * [6] backslash followed by word, excluding any trailing whitespace - * Just because the Lexer matches something doesn't mean it's valid input: - * If there is no matching function or symbol definition, the Parser will - * still reject the input. - */ -const spaceRegexString = "[ \r\n\t]"; -const controlWordRegexString = "\\\\[a-zA-Z@]+"; -const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; -const controlWordWhitespaceRegexString = `(${controlWordRegexString})${spaceRegexString}*` -const controlSpaceRegexString = "\\\\(\n|[ \r\t]+\n?)[ \r\t]*"; -const combiningDiacriticalMarkString = "[\u0300-\u036f]"; -export const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); -const tokenRegexString = - `(${spaceRegexString}+)|` + // whitespace - `${controlSpaceRegexString}|` + // whitespace - "(number" + // numbers (in non-strict mode) - "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|\\\\verb\\*([^]).*?\\4" + // \verb* - "|\\\\verb([^*a-zA-Z]).*?\\5" + // \verb unstarred - `|${controlWordWhitespaceRegexString}` + // \macroName + spaces - `|${controlSymbolRegexString})`; // \\, \', etc. - -/** Main Lexer class */ -export default class Lexer { - constructor(input, settings) { - // Separate accents from characters - this.input = input; - this.settings = settings; - this.tokenRegex = new RegExp( - // Strict Temml, like TeX, lexes one numeral at a time. - // Default Temml lexes contiguous numerals into a single element. - tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"), - "g" - ); - // Category codes. The lexer only supports comment characters (14) for now. - // MacroExpander additionally distinguishes active (13). - this.catcodes = { - "%": 14, // comment character - "~": 13 // active character - }; - } - - setCatcode(char, code) { - this.catcodes[char] = code; - } - - /** - * This function lexes a single token. - */ - lex() { - const input = this.input; - const pos = this.tokenRegex.lastIndex; - if (pos === input.length) { - return new Token("EOF", new SourceLocation(this, pos, pos)); - } - const match = this.tokenRegex.exec(input); - if (match === null || match.index !== pos) { - throw new ParseError( - `Unexpected character: '${input[pos]}'`, - new Token(input[pos], new SourceLocation(this, pos, pos + 1)) - ); - } - const text = match[6] || match[3] || (match[2] ? "\\ " : " ") - - if (this.catcodes[text] === 14) { - // comment character - const nlIndex = input.indexOf("\n", this.tokenRegex.lastIndex); - if (nlIndex === -1) { - this.tokenRegex.lastIndex = input.length; // EOF - if (this.settings.strict) { - throw new ParseError("% comment has no terminating newline; LaTeX would " + - "fail because of commenting the end of math mode") - } - } else { - this.tokenRegex.lastIndex = nlIndex + 1; - } - return this.lex(); - } - - return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); - } -} diff --git a/src/MacroExpander.js b/src/MacroExpander.js deleted file mode 100644 index 1d5bf61a..00000000 --- a/src/MacroExpander.js +++ /dev/null @@ -1,437 +0,0 @@ -/** - * This file contains the “gullet” where macros are expanded - * until only non-macro tokens remain. - */ - -import functions from "./functions"; -import symbols from "./symbols"; -import Lexer from "./Lexer"; -import { Token } from "./Token"; - -import ParseError from "./ParseError"; -import Namespace from "./Namespace"; -import macros from "./macros"; - -// List of commands that act like macros but aren't defined as a macro, -// function, or symbol. Used in `isDefined`. -export const implicitCommands = { - "^": true, // Parser.js - _: true, // Parser.js - "\\limits": true, // Parser.js - "\\nolimits": true // Parser.js -}; - -export default class MacroExpander { - constructor(input, settings, mode) { - this.settings = settings; - this.expansionCount = 0; - this.feed(input); - // Make new global namespace - this.macros = new Namespace(macros, settings.macros); - this.mode = mode; - this.stack = []; // contains tokens in REVERSE order - } - - /** - * Feed a new input string to the same MacroExpander - * (with existing macros etc.). - */ - feed(input) { - this.lexer = new Lexer(input, this.settings); - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - } - - /** - * Start a new group nesting within all namespaces. - */ - beginGroup() { - this.macros.beginGroup(); - } - - /** - * End current group nesting within all namespaces. - */ - endGroup() { - this.macros.endGroup(); - } - - /** - * Returns the topmost token on the stack, without expanding it. - * Similar in behavior to TeX's `\futurelet`. - */ - future() { - if (this.stack.length === 0) { - this.pushToken(this.lexer.lex()) - } - return this.stack[this.stack.length - 1] - } - - /** - * Remove and return the next unexpanded token. - */ - popToken() { - this.future(); // ensure non-empty stack - return this.stack.pop(); - } - - /** - * Add a given token to the token stack. In particular, this get be used - * to put back a token returned from one of the other methods. - */ - pushToken(token) { - this.stack.push(token); - } - - /** - * Append an array of tokens to the token stack. - */ - pushTokens(tokens) { - this.stack.push(...tokens); - } - - /** - * Find an macro argument without expanding tokens and append the array of - * tokens to the token stack. Uses Token as a container for the result. - */ - scanArgument(isOptional) { - let start; - let end; - let tokens; - if (isOptional) { - this.consumeSpaces(); // \@ifnextchar gobbles any space following it - if (this.future().text !== "[") { - return null; - } - start = this.popToken(); // don't include [ in tokens - ({ tokens, end } = this.consumeArg(["]"])); - } else { - ({ tokens, start, end } = this.consumeArg()); - } - - // indicate the end of an argument - this.pushToken(new Token("EOF", end.loc)); - - this.pushTokens(tokens); - return start.range(end, ""); - } - - /** - * Consume all following space tokens, without expansion. - */ - consumeSpaces() { - for (;;) { - const token = this.future(); - if (token.text === " ") { - this.stack.pop(); - } else { - break; - } - } - } - - /** - * Consume an argument from the token stream, and return the resulting array - * of tokens and start/end token. - */ - consumeArg(delims) { - // The argument for a delimited parameter is the shortest (possibly - // empty) sequence of tokens with properly nested {...} groups that is - // followed ... by this particular list of non-parameter tokens. - // The argument for an undelimited parameter is the next nonblank - // token, unless that token is ‘{’, when the argument will be the - // entire {...} group that follows. - const tokens = []; - const isDelimited = delims && delims.length > 0; - if (!isDelimited) { - // Ignore spaces between arguments. As the TeXbook says: - // "After you have said ‘\def\row#1#2{...}’, you are allowed to - // put spaces between the arguments (e.g., ‘\row x n’), because - // TeX doesn’t use single spaces as undelimited arguments." - this.consumeSpaces(); - } - const start = this.future(); - let tok; - let depth = 0; - let match = 0; - do { - tok = this.popToken(); - tokens.push(tok); - if (tok.text === "{") { - ++depth; - } else if (tok.text === "}") { - --depth; - if (depth === -1) { - throw new ParseError("Extra }", tok); - } - } else if (tok.text === "EOF") { - throw new ParseError( - "Unexpected end of input in a macro argument" + - ", expected '" + - (delims && isDelimited ? delims[match] : "}") + - "'", - tok - ); - } - if (delims && isDelimited) { - if ((depth === 0 || (depth === 1 && delims[match] === "{")) && tok.text === delims[match]) { - ++match; - if (match === delims.length) { - // don't include delims in tokens - tokens.splice(-match, match); - break; - } - } else { - match = 0; - } - } - } while (depth !== 0 || isDelimited); - // If the argument found ... has the form ‘{}’, - // ... the outermost braces enclosing the argument are removed - if (start.text === "{" && tokens[tokens.length - 1].text === "}") { - tokens.pop(); - tokens.shift(); - } - tokens.reverse(); // to fit in with stack order - return { tokens, start, end: tok }; - } - - /** - * Consume the specified number of (delimited) arguments from the token - * stream and return the resulting array of arguments. - */ - consumeArgs(numArgs, delimiters) { - if (delimiters) { - if (delimiters.length !== numArgs + 1) { - throw new ParseError("The length of delimiters doesn't match the number of args!"); - } - const delims = delimiters[0]; - for (let i = 0; i < delims.length; i++) { - const tok = this.popToken(); - if (delims[i] !== tok.text) { - throw new ParseError("Use of the macro doesn't match its definition", tok); - } - } - } - - const args = []; - for (let i = 0; i < numArgs; i++) { - args.push(this.consumeArg(delimiters && delimiters[i + 1]).tokens); - } - return args; - } - - /** - * Expand the next token only once if possible. - * - * If the token is expanded, the resulting tokens will be pushed onto - * the stack in reverse order and will be returned as an array, - * also in reverse order. - * - * If not, the next token will be returned without removing it - * from the stack. This case can be detected by a `Token` return value - * instead of an `Array` return value. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty. - * - * Used to implement `expandAfterFuture` and `expandNextToken`. - * - * If expandableOnly, only expandable tokens are expanded and - * an undefined control sequence results in an error. - */ - expandOnce(expandableOnly) { - const topToken = this.popToken(); - const name = topToken.text; - const expansion = !topToken.noexpand ? this._getExpansion(name) : null; - if (expansion == null || (expandableOnly && expansion.unexpandable)) { - if (expandableOnly && expansion == null && name[0] === "\\" && !this.isDefined(name)) { - throw new ParseError("Undefined control sequence: " + name); - } - this.pushToken(topToken); - return topToken; - } - this.expansionCount++; - if (this.expansionCount > this.settings.maxExpand) { - throw new ParseError( - "Too many expansions: infinite loop or " + "need to increase maxExpand setting" - ); - } - let tokens = expansion.tokens; - const args = this.consumeArgs(expansion.numArgs, expansion.delimiters); - if (expansion.numArgs) { - // paste arguments in place of the placeholders - tokens = tokens.slice(); // make a shallow copy - for (let i = tokens.length - 1; i >= 0; --i) { - let tok = tokens[i]; - if (tok.text === "#") { - if (i === 0) { - throw new ParseError("Incomplete placeholder at end of macro body", tok); - } - tok = tokens[--i]; // next token on stack - if (tok.text === "#") { - // ## → # - tokens.splice(i + 1, 1); // drop first # - } else if (/^[1-9]$/.test(tok.text)) { - // replace the placeholder with the indicated argument - tokens.splice(i, 2, ...args[+tok.text - 1]); - } else { - throw new ParseError("Not a valid argument number", tok); - } - } - } - } - // Concatenate expansion onto top of stack. - this.pushTokens(tokens); - return tokens; - } - - /** - * Expand the next token only once (if possible), and return the resulting - * top token on the stack (without removing anything from the stack). - * Similar in behavior to TeX's `\expandafter\futurelet`. - * Equivalent to expandOnce() followed by future(). - */ - expandAfterFuture() { - this.expandOnce(); - return this.future(); - } - - /** - * Recursively expand first token, then return first non-expandable token. - */ - expandNextToken() { - for (;;) { - const expanded = this.expandOnce(); - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (expanded.treatAsRelax) { - expanded.text = "\\relax" - } - return this.stack.pop(); // === expanded - } - } - - // This pathway is impossible. - throw new Error(); // eslint-disable-line no-unreachable - } - - /** - * Fully expand the given macro name and return the resulting list of - * tokens, or return `undefined` if no such macro is defined. - */ - expandMacro(name) { - return this.macros.has(name) ? this.expandTokens([new Token(name)]) : undefined; - } - - /** - * Fully expand the given token stream and return the resulting list of - * tokens. Note that the input tokens are in reverse order, but the - * output tokens are in forward order. - */ - expandTokens(tokens) { - const output = []; - const oldStackLength = this.stack.length; - this.pushTokens(tokens); - while (this.stack.length > oldStackLength) { - const expanded = this.expandOnce(true); // expand only expandable tokens - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - if (expanded.treatAsRelax) { - // the expansion of \noexpand is the token itself - expanded.noexpand = false; - expanded.treatAsRelax = false; - } - output.push(this.stack.pop()); - } - } - return output; - } - - /** - * Fully expand the given macro name and return the result as a string, - * or return `undefined` if no such macro is defined. - */ - expandMacroAsText(name) { - const tokens = this.expandMacro(name); - if (tokens) { - return tokens.map((token) => token.text).join(""); - } else { - return tokens; - } - } - - /** - * Returns the expanded macro as a reversed array of tokens and a macro - * argument count. Or returns `null` if no such macro. - */ - _getExpansion(name) { - const definition = this.macros.get(name); - if (definition == null) { - // mainly checking for undefined here - return definition; - } - // If a single character has an associated catcode other than 13 - // (active character), then don't expand it. - if (name.length === 1) { - const catcode = this.lexer.catcodes[name] - if (catcode != null && catcode !== 13) { - return - } - } - const expansion = typeof definition === "function" ? definition(this) : definition; - if (typeof expansion === "string") { - let numArgs = 0; - if (expansion.indexOf("#") !== -1) { - const stripped = expansion.replace(/##/g, ""); - while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { - ++numArgs; - } - } - const bodyLexer = new Lexer(expansion, this.settings); - const tokens = []; - let tok = bodyLexer.lex(); - while (tok.text !== "EOF") { - tokens.push(tok); - tok = bodyLexer.lex(); - } - tokens.reverse(); // to fit in with stack using push and pop - const expanded = { tokens, numArgs }; - return expanded; - } - - return expansion; - } - - /** - * Determine whether a command is currently "defined" (has some - * functionality), meaning that it's a macro (in the current group), - * a function, a symbol, or one of the special commands listed in - * `implicitCommands`. - */ - isDefined(name) { - return ( - this.macros.has(name) || - Object.prototype.hasOwnProperty.call(functions, name ) || - Object.prototype.hasOwnProperty.call(symbols.math, name ) || - Object.prototype.hasOwnProperty.call(symbols.text, name ) || - Object.prototype.hasOwnProperty.call(implicitCommands, name ) - ); - } - - /** - * Determine whether a command is expandable. - */ - isExpandable(name) { - const macro = this.macros.get(name); - return macro != null - ? typeof macro === "string" || typeof macro === "function" || !macro.unexpandable - : Object.prototype.hasOwnProperty.call(functions, name ) && !functions[name].primitive; - } -} diff --git a/src/Namespace.js b/src/Namespace.js deleted file mode 100644 index b32f4a4e..00000000 --- a/src/Namespace.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * A `Namespace` refers to a space of nameable things like macros or lengths, - * which can be `set` either globally or local to a nested group, using an - * undo stack similar to how TeX implements this functionality. - * Performance-wise, `get` and `set` take constant time. - */ - -import ParseError from "./ParseError"; - -export default class Namespace { - /** - * Both arguments are optional. The first argument is an object of - * built-in mappings which never change. The second argument is an object - * of initial (global-level) mappings, which will constantly change - * according to any global/top-level `set`s done. - */ - constructor(builtins = {}, globalMacros = {}) { - this.current = globalMacros; - this.builtins = builtins; - this.undefStack = []; - } - - /** - * Start a new nested group, affecting future local `set`s. - */ - beginGroup() { - this.undefStack.push({}); - } - - /** - * End current nested group, restoring values before the group began. - */ - endGroup() { - if (this.undefStack.length === 0) { - throw new ParseError( - "Unbalanced namespace destruction: attempt " + - "to pop global namespace; please report this as a bug" - ); - } - const undefs = this.undefStack.pop(); - for (const undef in undefs) { - if (Object.prototype.hasOwnProperty.call(undefs, undef )) { - if (undefs[undef] === undefined) { - delete this.current[undef]; - } else { - this.current[undef] = undefs[undef]; - } - } - } - } - - /** - * Detect whether `name` has a definition. Equivalent to - * `get(name) != null`. - */ - has(name) { - return Object.prototype.hasOwnProperty.call(this.current, name ) || - Object.prototype.hasOwnProperty.call(this.builtins, name ); - } - - /** - * Get the current value of a name, or `undefined` if there is no value. - * - * Note: Do not use `if (namespace.get(...))` to detect whether a macro - * is defined, as the definition may be the empty string which evaluates - * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or - * `if (namespace.has(...))`. - */ - get(name) { - if (Object.prototype.hasOwnProperty.call(this.current, name )) { - return this.current[name]; - } else { - return this.builtins[name]; - } - } - - /** - * Set the current value of a name, and adds an undo - * operation to the undo stack. - */ - set(name, value) { - // Undo this set at end of this group (possibly to `undefined`), - // unless an undo is already in place, in which case that older - // value is the correct one. - const top = this.undefStack[this.undefStack.length - 1]; - if (top && !Object.prototype.hasOwnProperty.call(top, name )) { - top[name] = this.current[name]; - } - this.current[name] = value; - } -} diff --git a/src/ParseError.js b/src/ParseError.js deleted file mode 100644 index ea31ca09..00000000 --- a/src/ParseError.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * This is the ParseError class, which is the main error thrown by Temml - * functions when something has gone wrong. This is used to distinguish internal - * errors from errors in the expression that the user provided. - * - * If possible, a caller should provide a Token or ParseNode with information - * about where in the source string the problem occurred. - */ -class ParseError { - constructor( - message, // The error message - token // An object providing position information - ) { - let error = " " + message; - let start; - - const loc = token && token.loc; - if (loc && loc.start <= loc.end) { - // If we have the input and a position, make the error a bit fancier - - // Get the input - const input = loc.lexer.input; - - // Prepend some information - start = loc.start; - const end = loc.end; - if (start === input.length) { - error += " at end of input: "; - } else { - error += " at position " + (start + 1) + ": "; - } - - // Underline token in question using combining underscores - const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); - - // Extract some context from the input and add it to the error - let left; - if (start > 15) { - left = "…" + input.slice(start - 15, start); - } else { - left = input.slice(0, start); - } - let right; - if (end + 15 < input.length) { - right = input.slice(end, end + 15) + "…"; - } else { - right = input.slice(end); - } - error += left + underlined + right; - } - - // Some hackery to make ParseError a prototype of Error - // See http://stackoverflow.com/a/8460753 - const self = new Error(error); - self.name = "ParseError"; - self.__proto__ = ParseError.prototype; - self.position = start; - return self; - } -} - -ParseError.prototype.__proto__ = Error.prototype; - -export default ParseError; diff --git a/src/Parser.js b/src/Parser.js deleted file mode 100644 index a3113b72..00000000 --- a/src/Parser.js +++ /dev/null @@ -1,948 +0,0 @@ -/* eslint no-constant-condition:0 */ -import functions from "./functions"; -import MacroExpander, { implicitCommands } from "./MacroExpander"; -import symbols, { ATOMS } from "./symbols"; -import { validUnit } from "./units"; -import { supportedCodepoint } from "./unicodeScripts"; -import ParseError from "./ParseError"; -import { combiningDiacriticalMarksEndRegex } from "./Lexer"; -import { uSubsAndSups, unicodeSubRegEx } from "./unicodeSupOrSub" -import SourceLocation from "./SourceLocation"; - -// Pre-evaluate both modules as unicodeSymbols require String.normalize() -import unicodeAccents from /*preval*/ "./unicodeAccents"; -import unicodeSymbols from /*preval*/ "./unicodeSymbols"; - -const numberRegEx = /^\d(?:[\d,.]*\d)?$/ // Keep in sync with numberRegEx in symbolsOrd.js - -/** - * This file contains the parser used to parse out a TeX expression from the - * input. Since TeX isn't context-free, standard parsers don't work particularly - * well. - * - * The strategy of this parser is as such: - * - * The main functions (the `.parse...` ones) take a position in the current - * parse string to parse tokens from. The lexer (found in Lexer.js, stored at - * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When - * individual tokens are needed at a position, the lexer is called to pull out a - * token, which is then used. - * - * The parser has a property called "mode" indicating the mode that - * the parser is currently in. Currently it has to be one of "math" or - * "text", which denotes whether the current environment is a math-y - * one or a text-y one (e.g. inside \text). Currently, this serves to - * limit the functions which can be used in text mode. - * - * The main functions then return an object which contains the useful data that - * was parsed at its given point, and a new position at the end of the parsed - * data. The main functions can call each other and continue the parsing by - * using the returned position as a new starting point. - * - * There are also extra `.handle...` functions, which pull out some reused - * functionality into self-contained functions. - * - * The functions return ParseNodes. - */ - -export default class Parser { - constructor(input, settings, isPreamble = false) { - // Start in math mode - this.mode = "math"; - // Create a new macro expander (gullet) and (indirectly via that) also a - // new lexer (mouth) for this parser (stomach, in the language of TeX) - this.gullet = new MacroExpander(input, settings, this.mode); - // Store the settings for use in parsing - this.settings = settings; - // Are we defining a preamble? - this.isPreamble = isPreamble; - // Count leftright depth (for \middle errors) - this.leftrightDepth = 0; - this.prevAtomType = ""; - } - - /** - * Checks a result to make sure it has the right type, and throws an - * appropriate error otherwise. - */ - expect(text, consume = true) { - if (this.fetch().text !== text) { - throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); - } - if (consume) { - this.consume(); - } - } - - /** - * Discards the current lookahead token, considering it consumed. - */ - consume() { - this.nextToken = null; - } - - /** - * Return the current lookahead token, or if there isn't one (at the - * beginning, or if the previous lookahead token was consume()d), - * fetch the next token as the new lookahead token and return it. - */ - fetch() { - if (this.nextToken == null) { - this.nextToken = this.gullet.expandNextToken(); - } - return this.nextToken; - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - this.gullet.switchMode(newMode); - } - - /** - * Main parsing function, which parses an entire input. - */ - parse() { - // Create a group namespace for every $...$, $$...$$, \[...\].) - // A \def is then valid only within that pair of delimiters. - this.gullet.beginGroup(); - - if (this.settings.colorIsTextColor) { - // Use old \color behavior (same as LaTeX's \textcolor) if requested. - // We do this within the group for the math expression, so it doesn't - // pollute settings.macros. - this.gullet.macros.set("\\color", "\\textcolor"); - } - - // Try to parse the input - const parse = this.parseExpression(false); - - // If we succeeded, make sure there's an EOF at the end - this.expect("EOF"); - - if (this.isPreamble) { - const macros = Object.create(null) - Object.entries(this.gullet.macros.current).forEach(([key, value]) => { - macros[key] = value - }) - this.gullet.endGroup(); - return macros - } - - // The only local macro that we want to save is from \tag. - const tag = this.gullet.macros.get("\\df@tag") - - // End the group namespace for the expression - this.gullet.endGroup(); - - if (tag) { this.gullet.macros.current["\\df@tag"] = tag } - - return parse; - } - - static get endOfExpression() { - return ["}", "\\endgroup", "\\end", "\\right", "\\endtoggle", "&"]; - } - - /** - * Parses an "expression", which is a list of atoms. - * - * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This - * happens when functions have higher precendence han infix - * nodes in implicit parses. - * - * `breakOnTokenText`: The text of the token that the expression should end - * with, or `null` if something else should end the - * expression. - */ - parseExpression(breakOnInfix, breakOnTokenText) { - const body = []; - // Keep adding atoms to the body until we can't parse any more atoms (either - // we reached the end, a }, or a \right) - while (true) { - // Ignore spaces in math mode - if (this.mode === "math") { - this.consumeSpaces(); - } - const lex = this.fetch(); - if (Parser.endOfExpression.indexOf(lex.text) !== -1) { - break; - } - if (breakOnTokenText && lex.text === breakOnTokenText) { - break; - } - if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { - break; - } - const atom = this.parseAtom(breakOnTokenText); - if (!atom) { - break; - } else if (atom.type === "internal") { - continue; - } - body.push(atom); - // Keep a record of the atom type, so that op.js can set correct spacing. - this.prevAtomType = atom.type === "atom" ? atom.family : atom.type; - } - if (this.mode === "text") { - this.formLigatures(body); - } - return this.handleInfixNodes(body); - } - - /** - * Rewrites infix operators such as \over with corresponding commands such - * as \frac. - * - * There can only be one infix operator per group. If there's more than one - * then the expression is ambiguous. This can be resolved by adding {}. - */ - handleInfixNodes(body) { - let overIndex = -1; - let funcName; - - for (let i = 0; i < body.length; i++) { - if (body[i].type === "infix") { - if (overIndex !== -1) { - throw new ParseError("only one infix operator per group", body[i].token); - } - overIndex = i; - funcName = body[i].replaceWith; - } - } - - if (overIndex !== -1 && funcName) { - let numerNode; - let denomNode; - - const numerBody = body.slice(0, overIndex); - const denomBody = body.slice(overIndex + 1); - - if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { - numerNode = numerBody[0]; - } else { - numerNode = { type: "ordgroup", mode: this.mode, body: numerBody }; - } - - if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { - denomNode = denomBody[0]; - } else { - denomNode = { type: "ordgroup", mode: this.mode, body: denomBody }; - } - - let node; - if (funcName === "\\\\abovefrac") { - node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); - } else { - node = this.callFunction(funcName, [numerNode, denomNode], []); - } - return [node]; - } else { - return body; - } - } - - /** - * Handle a subscript or superscript with nice errors. - */ - handleSupSubscript( - name // For error reporting. - ) { - const symbolToken = this.fetch(); - const symbol = symbolToken.text; - this.consume(); - this.consumeSpaces(); // ignore spaces before sup/subscript argument - const group = this.parseGroup(name); - - if (!group) { - throw new ParseError("Expected group after '" + symbol + "'", symbolToken); - } - - return group; - } - - /** - * Converts the textual input of an unsupported command into a text node - * contained within a color node whose color is determined by errorColor - */ - formatUnsupportedCmd(text) { - const textordArray = []; - - for (let i = 0; i < text.length; i++) { - textordArray.push({ type: "textord", mode: "text", text: text[i] }); - } - - const textNode = { - type: "text", - mode: this.mode, - body: textordArray - }; - - const colorNode = { - type: "color", - mode: this.mode, - color: this.settings.errorColor, - body: [textNode] - }; - - return colorNode; - } - - /** - * Parses a group with optional super/subscripts. - */ - parseAtom(breakOnTokenText) { - // The body of an atom is an implicit group, so that things like - // \left(x\right)^2 work correctly. - const base = this.parseGroup("atom", breakOnTokenText); - - // In text mode, we don't have superscripts or subscripts - if (this.mode === "text") { - return base; - } - - // Note that base may be empty (i.e. null) at this point. - - let superscript; - let subscript; - while (true) { - // Guaranteed in math mode, so eat any spaces first. - this.consumeSpaces(); - - // Lex the first token - const lex = this.fetch(); - - if (lex.text === "\\limits" || lex.text === "\\nolimits") { - // We got a limit control - if (base && base.type === "op") { - const limits = lex.text === "\\limits"; - base.limits = limits; - base.alwaysHandleSupSub = true; - } else if (base && base.type === "operatorname") { - if (base.alwaysHandleSupSub) { - base.limits = lex.text === "\\limits" - } - } else { - throw new ParseError("Limit controls must follow a math operator", lex); - } - this.consume(); - } else if (lex.text === "^") { - // We got a superscript start - if (superscript) { - throw new ParseError("Double superscript", lex); - } - superscript = this.handleSupSubscript("superscript"); - } else if (lex.text === "_") { - // We got a subscript start - if (subscript) { - throw new ParseError("Double subscript", lex); - } - subscript = this.handleSupSubscript("subscript"); - } else if (lex.text === "'") { - // We got a prime - if (superscript) { - throw new ParseError("Double superscript", lex); - } - const prime = { type: "textord", mode: this.mode, text: "\\prime" }; - - // Many primes can be grouped together, so we handle this here - const primes = [prime]; - this.consume(); - // Keep lexing tokens until we get something that's not a prime - while (this.fetch().text === "'") { - // For each one, add another prime to the list - primes.push(prime); - this.consume(); - } - // If there's a superscript following the primes, combine that - // superscript in with the primes. - if (this.fetch().text === "^") { - primes.push(this.handleSupSubscript("superscript")); - } - // Put everything into an ordgroup as the superscript - superscript = { type: "ordgroup", mode: this.mode, body: primes }; - } else if (uSubsAndSups[lex.text]) { - // A Unicode subscript or superscript character. - // We treat these similarly to the unicode-math package. - // So we render a string of Unicode (sub|super)scripts the - // same as a (sub|super)script of regular characters. - let str = uSubsAndSups[lex.text] - const isSub = unicodeSubRegEx.test(lex.text) - this.consume() - // Continue fetching tokens to fill out the string. - while (true) { - const token = this.fetch().text - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - this.consume() - str += uSubsAndSups[token] - } - // Now create a (sub|super)script. - const body = (new Parser(str, this.settings)).parse() - if (isSub) { - subscript = { type: "ordgroup", mode: "math", body } - } else { - superscript = { type: "ordgroup", mode: "math", body } - } - } else { - // If it wasn't ^, _, a Unicode (sub|super)script, or ', stop parsing super/subscripts - break; - } - } - - if (superscript || subscript) { - if (base && base.type === "multiscript" && !base.postscripts) { - // base is the result of a \prescript function. - // Write the sub- & superscripts into the multiscript element. - base.postscripts = { sup: superscript, sub: subscript } - return base - } else { - // We got either a superscript or subscript, create a supsub - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript - } - } - } else { - // Otherwise return the original body - return base; - } - } - - /** - * Parses an entire function, including its base and all of its arguments. - */ - parseFunction( - breakOnTokenText, - name // For determining its context - ) { - const token = this.fetch(); - const func = token.text; - const funcData = functions[func]; - if (!funcData) { - return null; - } - this.consume(); // consume command token - - if (name && name !== "atom" && !funcData.allowedInArgument) { - throw new ParseError( - "Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), - token - ); - } else if (this.mode === "text" && !funcData.allowedInText) { - throw new ParseError("Can't use function '" + func + "' in text mode", token); - } else if (this.mode === "math" && funcData.allowedInMath === false) { - throw new ParseError("Can't use function '" + func + "' in math mode", token); - } - - const prevAtomType = this.prevAtomType; - const { args, optArgs } = this.parseArguments(func, funcData); - this.prevAtomType = prevAtomType; - return this.callFunction(func, args, optArgs, token, breakOnTokenText); - } - - /** - * Call a function handler with a suitable context and arguments. - */ - callFunction(name, args, optArgs, token, breakOnTokenText) { - const context = { - funcName: name, - parser: this, - token, - breakOnTokenText - }; - const func = functions[name]; - if (func && func.handler) { - return func.handler(context, args, optArgs); - } else { - throw new ParseError(`No function handler for ${name}`); - } - } - - /** - * Parses the arguments of a function or environment - */ - parseArguments( - func, // Should look like "\name" or "\begin{name}". - funcData - ) { - const totalArgs = funcData.numArgs + funcData.numOptionalArgs; - if (totalArgs === 0) { - return { args: [], optArgs: [] }; - } - - const args = []; - const optArgs = []; - - for (let i = 0; i < totalArgs; i++) { - let argType = funcData.argTypes && funcData.argTypes[i]; - const isOptional = i < funcData.numOptionalArgs; - - if ( - (funcData.primitive && argType == null) || - // \sqrt expands into primitive if optional argument doesn't exist - (funcData.type === "sqrt" && i === 1 && optArgs[0] == null) - ) { - argType = "primitive"; - } - - const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional); - if (isOptional) { - optArgs.push(arg); - } else if (arg != null) { - args.push(arg); - } else { - // should be unreachable - throw new ParseError("Null argument, please report this as a bug"); - } - } - - return { args, optArgs }; - } - - /** - * Parses a group when the mode is changing. - */ - parseGroupOfType(name, type, optional) { - switch (type) { - case "size": - return this.parseSizeGroup(optional); - case "url": - return this.parseUrlGroup(optional); - case "math": - case "text": - return this.parseArgumentGroup(optional, type); - case "hbox": { - // hbox argument type wraps the argument in the equivalent of - // \hbox, which is like \text but switching to \textstyle size. - const group = this.parseArgumentGroup(optional, "text"); - return group != null - ? { - type: "styling", - mode: group.mode, - body: [group], - scriptLevel: "text" // simulate \textstyle - } - : null; - } - case "raw": { - const token = this.parseStringGroup("raw", optional); - return token != null - ? { - type: "raw", - mode: "text", - string: token.text - } - : null; - } - case "primitive": { - if (optional) { - throw new ParseError("A primitive argument cannot be optional"); - } - const group = this.parseGroup(name); - if (group == null) { - throw new ParseError("Expected group as " + name, this.fetch()); - } - return group; - } - case "original": - case null: - case undefined: - return this.parseArgumentGroup(optional); - default: - throw new ParseError("Unknown group type as " + name, this.fetch()); - } - } - - /** - * Discard any space tokens, fetching the next non-space token. - */ - consumeSpaces() { - while (this.fetch().text === " ") { - this.consume(); - } - } - - /** - * Parses a group, essentially returning the string formed by the - * brace-enclosed tokens plus some position information. - */ - parseStringGroup( - modeName, // Used to describe the mode in error messages. - optional - ) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF") { - str += nextToken.text; - this.consume(); - } - this.consume(); // consume the end of the argument - argToken.text = str; - return argToken; - } - - /** - * Parses a regex-delimited group: the largest sequence of tokens - * whose concatenated strings match `regex`. Returns the string - * formed by the tokens plus some position information. - */ - parseRegexGroup( - regex, - modeName // Used to describe the mode in error messages. - ) { - const firstToken = this.fetch(); - let lastToken = firstToken; - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { - lastToken = nextToken; - str += lastToken.text; - this.consume(); - } - if (str === "") { - throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); - } - return firstToken.range(lastToken, str); - } - - /** - * Parses a size specification, consisting of magnitude and unit. - */ - parseSizeGroup(optional) { - let res; - let isBlank = false; - // don't expand before parseStringGroup - this.gullet.consumeSpaces(); - if (!optional && this.gullet.future().text !== "{") { - res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); - } else { - res = this.parseStringGroup("size", optional); - } - if (!res) { - return null; - } - if (!optional && res.text.length === 0) { - // Because we've tested for what is !optional, this block won't - // affect \kern, \hspace, etc. It will capture the mandatory arguments - // to \genfrac and \above. - res.text = "0pt"; // Enable \above{} - isBlank = true; // This is here specifically for \genfrac - } - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); - if (!match) { - throw new ParseError("Invalid size: '" + res.text + "'", res); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "'", res); - } - return { - type: "size", - mode: this.mode, - value: data, - isBlank - }; - } - - /** - * Parses an URL, checking escaped letters and allowed protocols, - * and setting the catcode of % as an active character (as in \hyperref). - */ - parseUrlGroup(optional) { - this.gullet.lexer.setCatcode("%", 13); // active character - this.gullet.lexer.setCatcode("~", 12); // other character - const res = this.parseStringGroup("url", optional); - this.gullet.lexer.setCatcode("%", 14); // comment character - this.gullet.lexer.setCatcode("~", 13); // active character - if (res == null) { - return null; - } - // hyperref package allows backslashes alone in href, but doesn't - // generate valid links in such cases; we interpret this as - // "undefined" behaviour, and keep them as-is. Some browser will - // replace backslashes with forward slashes. - let url = res.text.replace(/\\([#$%&~_^{}])/g, "$1"); - url = res.text.replace(/{\u2044}/g, "/"); - return { - type: "url", - mode: this.mode, - url - }; - } - - /** - * Parses an argument with the mode specified. - */ - parseArgumentGroup(optional, mode) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - const outerMode = this.mode; - if (mode) { - // Switch to specified mode - this.switchMode(mode); - } - - this.gullet.beginGroup(); - const expression = this.parseExpression(false, "EOF"); - // TODO: find an alternative way to denote the end - this.expect("EOF"); // expect the end of the argument - this.gullet.endGroup(); - const result = { - type: "ordgroup", - mode: this.mode, - loc: argToken.loc, - body: expression - }; - - if (mode) { - // Switch mode back - this.switchMode(outerMode); - } - return result; - } - - /** - * Parses an ordinary group, which is either a single nucleus (like "x") - * or an expression in braces (like "{x+y}") or an implicit group, a group - * that starts at the current position, and ends right before a higher explicit - * group ends, or at EOF. - */ - parseGroup( - name, // For error reporting. - breakOnTokenText - ) { - const firstToken = this.fetch(); - const text = firstToken.text; - - let result; - // Try to parse an open brace or \begingroup - if (text === "{" || text === "\\begingroup" || text === "\\toggle") { - this.consume(); - const groupEnd = text === "{" - ? "}" - : text === "\\begingroup" - ? "\\endgroup" - : "\\endtoggle" - - this.gullet.beginGroup(); - // If we get a brace, parse an expression - const expression = this.parseExpression(false, groupEnd); - const lastToken = this.fetch(); - this.expect(groupEnd); // Check that we got a matching closing brace - this.gullet.endGroup(); - result = { - type: (lastToken.text === "\\endtoggle" ? "toggle" : "ordgroup"), - mode: this.mode, - loc: SourceLocation.range(firstToken, lastToken), - body: expression, - // A group formed by \begingroup...\endgroup is a semi-simple group - // which doesn't affect spacing in math mode, i.e., is transparent. - // https://tex.stackexchange.com/questions/1930/when-should-one- - // use-begingroup-instead-of-bgroup - semisimple: text === "\\begingroup" || undefined - }; - } else { - // If there exists a function with this name, parse the function. - // Otherwise, just return a nucleus - result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol(); - if (result == null && text[0] === "\\" && - !Object.prototype.hasOwnProperty.call(implicitCommands, text )) { - result = this.formatUnsupportedCmd(text); - this.consume(); - } - } - return result; - } - - /** - * Form ligature-like combinations of characters for text mode. - * This includes inputs like "--", "---", "``" and "''". - * The result will simply replace multiple textord nodes with a single - * character in each value by a single textord node having multiple - * characters in its value. The representation is still ASCII source. - * The group will be modified in place. - */ - formLigatures(group) { - let n = group.length - 1; - for (let i = 0; i < n; ++i) { - const a = group[i]; - const v = a.text; - if (v === "-" && group[i + 1].text === "-") { - if (i + 1 < n && group[i + 2].text === "-") { - group.splice(i, 3, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 2]), - text: "---" - }); - n -= 2; - } else { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: "--" - }); - n -= 1; - } - } - if ((v === "'" || v === "`") && group[i + 1].text === v) { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: v + v - }); - n -= 1; - } - } - } - - /** - * Parse a single symbol out of the string. Here, we handle single character - * symbols and special functions like \verb. - */ - parseSymbol() { - const nucleus = this.fetch(); - let text = nucleus.text; - - if (/^\\verb[^a-zA-Z]/.test(text)) { - this.consume(); - let arg = text.slice(5); - const star = arg.charAt(0) === "*"; - if (star) { - arg = arg.slice(1); - } - // Lexer's tokenRegex is constructed to always have matching - // first/last characters. - if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { - throw new ParseError(`\\verb assertion failed -- - please report what input caused this bug`); - } - arg = arg.slice(1, -1); // remove first and last char - return { - type: "verb", - mode: "text", - body: arg, - star - }; - } - // At this point, we should have a symbol, possibly with accents. - // First expand any accented base symbol according to unicodeSymbols. - if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0]) && - !symbols[this.mode][text[0]]) { - // This behavior is not strict (XeTeX-compatible) in math mode. - if (this.settings.strict && this.mode === "math") { - throw new ParseError(`Accented Unicode text character "${text[0]}" used in ` + `math mode`, - nucleus - ); - } - text = unicodeSymbols[text[0]] + text.slice(1); - } - // Strip off any combining characters - const match = combiningDiacriticalMarksEndRegex.exec(text); - if (match) { - text = text.substring(0, match.index); - if (text === "i") { - text = "\u0131"; // dotless i, in math and text mode - } else if (text === "j") { - text = "\u0237"; // dotless j, in math and text mode - } - } - // Recognize base symbol - let symbol; - if (symbols[this.mode][text]) { - const group = symbols[this.mode][text].group; - const loc = SourceLocation.range(nucleus); - let s; - if (Object.prototype.hasOwnProperty.call(ATOMS, group )) { - const family = group; - s = { - type: "atom", - mode: this.mode, - family, - loc, - text - }; - } else { - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (!this.strict && numberRegEx.test(text)) { - // A number. Wrap in a if in math mode; otherwise. - this.consume() - return { - type: "textord", - mode: this.mode, - loc: SourceLocation.range(nucleus), - text - } - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict) { - if (!supportedCodepoint(text.charCodeAt(0))) { - throw new ParseError(`Unrecognized Unicode character "${text[0]}"` + - ` (${text.charCodeAt(0)})`, nucleus); - } else if (this.mode === "math") { - throw new ParseError(`Unicode text character "${text[0]}" used in math mode`, nucleus) - } - } - // All nonmathematical Unicode characters are rendered as if they - // are in text mode (wrapped in \text) because that's what it - // takes to render them in LaTeX. - symbol = { - type: "textord", - mode: "text", - loc: SourceLocation.range(nucleus), - text - }; - } else { - return null; // EOF, ^, _, {, }, etc. - } - this.consume(); - // Transform combining characters into accents - if (match) { - for (let i = 0; i < match[0].length; i++) { - const accent = match[0][i]; - if (!unicodeAccents[accent]) { - throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); - } - const command = unicodeAccents[accent][this.mode] || - unicodeAccents[accent].text; - if (!command) { - throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); - } - symbol = { - type: "accent", - mode: this.mode, - loc: SourceLocation.range(nucleus), - label: command, - isStretchy: false, - isShifty: true, - base: symbol - }; - } - } - return symbol; - } -} diff --git a/src/Settings.js b/src/Settings.js deleted file mode 100644 index 9c154a7c..00000000 --- a/src/Settings.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * This is a module for storing settings passed into Temml. It correctly handles - * default settings. - */ - -import utils from "./utils"; - -/** - * The main Settings object - */ -export default class Settings { - constructor(options) { - // allow null options - options = options || {}; - this.displayMode = utils.deflt(options.displayMode, false); // boolean - this.annotate = utils.deflt(options.annotate, false) // boolean - this.elementIsMath = utils.deflt(options.elementIsMath, false) // boolean - this.leqno = utils.deflt(options.leqno, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.preventTagLap = utils.deflt(options.preventTagLap, false); // boolean - this.macros = options.macros || {}; - this.xml = utils.deflt(options.xml, false); // boolean - this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean - this.strict = utils.deflt(options.strict, false); // boolean - this.trust = utils.deflt(options.trust, false); // trust context. See html.js. - this.maxSize = (options.maxSize === undefined - ? [Infinity, Infinity] - : Array.isArray(options.maxSize) - ? options.maxSize - : [Infinity, Infinity] - ) - this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number - } - - /** - * Check whether to test potentially dangerous input, and return - * `true` (trusted) or `false` (untrusted). The sole argument `context` - * should be an object with `command` field specifying the relevant LaTeX - * command (as a string starting with `\`), and any other arguments, etc. - * If `context` has a `url` field, a `protocol` field will automatically - * get added by this function (changing the specified object). - */ - isTrusted(context) { - if (context.url && !context.protocol) { - context.protocol = utils.protocolFromUrl(context.url); - } - const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; - return Boolean(trust); - } -} diff --git a/src/SourceLocation.js b/src/SourceLocation.js deleted file mode 100644 index ad0f8031..00000000 --- a/src/SourceLocation.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Lexing or parsing positional information for error reporting. - * This object is immutable. - */ -export default class SourceLocation { - constructor(lexer, start, end) { - this.lexer = lexer; // Lexer holding the input string. - this.start = start; // Start offset, zero-based inclusive. - this.end = end; // End offset, zero-based exclusive. - } - - /** - * Merges two `SourceLocation`s from location providers, given they are - * provided in order of appearance. - * - Returns the first one's location if only the first is provided. - * - Returns a merged range of the first and the last if both are provided - * and their lexers match. - * - Otherwise, returns null. - */ - static range(first, second) { - if (!second) { - return first && first.loc; - } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { - return null; - } else { - return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); - } - } -} diff --git a/src/Style.js b/src/Style.js deleted file mode 100644 index c98fd9de..00000000 --- a/src/Style.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * This file contains information about the style that the mathmlBuilder carries - * around with it. Data is held in an `Style` object, and when - * recursing, a new `Style` object can be created with the `.with*` functions. - */ - -const subOrSupLevel = [2, 2, 3, 3]; - -/** - * This is the main Style class. It contains the current style.level, color, and font. - * - * Style objects should not be modified. To create a new Style with - * different properties, call a `.with*` method. - */ -class Style { - constructor(data) { - // Style.level can be 0 | 1 | 2 | 3, which correspond to - // displaystyle, textstyle, scriptstyle, and scriptscriptstyle. - // style.level does not directly set MathML's script level. MathML does that itself. - // We use style.level to track, not set, math style so that we can get the - // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em. - this.level = data.level; - this.color = data.color; // string | void - // A font family applies to a group of fonts (i.e. SansSerif), while a font - // represents a specific font (i.e. SansSerif Bold). - // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm - this.font = data.font || ""; // string - this.fontFamily = data.fontFamily || ""; // string - this.fontSize = data.fontSize || 1.0; // number - this.fontWeight = data.fontWeight || ""; - this.fontShape = data.fontShape || ""; - this.maxSize = data.maxSize; // [number, number] - } - - /** - * Returns a new style object with the same properties as "this". Properties - * from "extension" will be copied to the new style object. - */ - extend(extension) { - const data = { - level: this.level, - color: this.color, - font: this.font, - fontFamily: this.fontFamily, - fontSize: this.fontSize, - fontWeight: this.fontWeight, - fontShape: this.fontShape, - maxSize: this.maxSize - }; - - for (const key in extension) { - if (Object.prototype.hasOwnProperty.call(extension, key)) { - data[key] = extension[key]; - } - } - - return new Style(data); - } - - withLevel(n) { - return this.extend({ - level: n - }); - } - - incrementLevel() { - return this.extend({ - level: Math.min(this.level + 1, 3) - }); - } - - inSubOrSup() { - return this.extend({ - level: subOrSupLevel[this.level] - }) - } - - /** - * Create a new style object with the given color. - */ - withColor(color) { - return this.extend({ - color: color - }); - } - - /** - * Creates a new style object with the given math font or old text font. - * @type {[type]} - */ - withFont(font) { - return this.extend({ - font - }); - } - - /** - * Create a new style objects with the given fontFamily. - */ - withTextFontFamily(fontFamily) { - return this.extend({ - fontFamily, - font: "" - }); - } - - /** - * Creates a new style object with the given font size - */ - withFontSize(num) { - return this.extend({ - fontSize: num - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontWeight(fontWeight) { - return this.extend({ - fontWeight, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontShape(fontShape) { - return this.extend({ - fontShape, - font: "" - }); - } - - /** - * Gets the CSS color of the current style object - */ - getColor() { - return this.color; - } -} - -export default Style; diff --git a/src/Token.js b/src/Token.js deleted file mode 100644 index fce73082..00000000 --- a/src/Token.js +++ /dev/null @@ -1,40 +0,0 @@ -import SourceLocation from "./SourceLocation"; - -/** - * Interface required to break circular dependency between Token, Lexer, and - * ParseError. - */ - -/** - * The resulting token returned from `lex`. - * - * It consists of the token text plus some position information. - * The position information is essentially a range in an input string, - * but instead of referencing the bare input string, we refer to the lexer. - * That way it is possible to attach extra metadata to the input string, - * like for example a file name or similar. - * - * The position information is optional, so it is OK to construct synthetic - * tokens if appropriate. Not providing available position information may - * lead to degraded error reporting, though. - */ -export class Token { - constructor( - text, // the text of this token - loc - ) { - this.text = text; - this.loc = loc; - } - - /** - * Given a pair of tokens (this and endToken), compute a `Token` encompassing - * the whole input range enclosed by these two. - */ - range( - endToken, // last token of the range, inclusive - text // the text of the newly constructed token - ) { - return new Token(text, SourceLocation.range(this, endToken)); - } -} diff --git a/src/autocorrect.js b/src/autocorrect.js deleted file mode 100644 index 94178f6a..00000000 --- a/src/autocorrect.js +++ /dev/null @@ -1,126 +0,0 @@ - -const autoCorrections = { - "\\alpha": "α", - "\\beta": "β", - "\\chi": "χ", - "\\delta": "δ", - "\\Delta": "Δ", - "\\epsilon": "ε", - "\\varepsilon": "\u025B", - "\\eta": "\u03B7", - "\\gamma": "γ", - "\\Gamma": "Γ", - "\\iota": "\u03B9", - "\\kappa": "\u03BA", - "\\lambda": "λ", - "\\Lambda": "Λ", - "\\mu": "μ", - "\\nu": "\u03BD", - "\\omega": "ω", - "\\Omega": "Ω", - "\\phi": "\u03D5", - "\\varphi": "\u03C6", - "\\Phi": "\u03A6", - "\\pi": "π", - "\\Pi": "Π", - "\\psi": "ψ", - "\\Psi": "Ψ", - "\\rho": "ρ", - "\\sigma": "σ", - "\\Sigma": "Σ", - "\\tau": "τ", - "\\theta": "θ", - "\\vartheta": "\u03D1", - "\\Theta": "Θ", - "\\upsilon": "\u03C5", - "\\xi": "\u03BE", - "\\Xi": "\u039E", - "\\zeta": "\u03B6", - "\\mathbb{C}": "\u2102", - "\\mathbb{H}": "\u210D", - "\\mathbb{N}": "\u2115", - "\\mathbb{Q}": "\u211A", - "\\mathbb{R}": "\u211D", - "\\mathbb{Z}": "\u2124", - "\\infty": "∞", - "\\degree": "°", - "\\lnot": "¬", - "\\neg": "¬", - "\\cdots": "\u22ef", - "\\vdots": "\u22ee", - "\\ddots": "\u22f1", - "\\lceil": "⌈", - "\\rceil": "⌉", - "\\lfloor": "⌊", - "\\rfloor": "⌋", - "\\times": "×", - "\\int": "∫", - "\\iint": "∬", - "\\iiint": "∭", - "\\iiiint": "⨌", - "\\oint": "∮", - "\\oiint": "∯", - "\\oiiint": "∰", - "\\sum": "∑", - "\\cap": "∩", - "\\bigcap": "⋂", - "\\cup": "∪", - "\\bigcup": "⋃", - "\\del": "∂", - "\\grad": "∇", - "\\hbar": "ℏ", - "\\ell": "ℓ", - "\\nabla": "∇", - "\\aleph": "ℵ", - "\\beth": "ℶ", - "\\gimel": "ℷ", - "\\daleth": "ℸ", - "\\eth": "ð", - "\\subset": "⊂", - "\\supset": "⊃", - "\\Subset": "⋐", - "\\Supset": "⋑", - "\\complement": "∁", - "\\forall": "∀", - "\\exists": "∃", - "\\nexists": "∄", - "\\therefore": "∴", - "\\because": "∵", - "\\mapsto": "↦", - "\\checkmark": "✓", - "\\land": "∧", - "\\lor": "∨", - "\\in": "∈", - "\\ni": "∋", - "\\notin": "∉", - "\\notni": "∌", - "\\implies": "⟹", - "\\impliedby": "⟸", - "\\iff": "⟺", - "\\euro": "€", - "\\pound": "£", - "\\yen": "¥", - "\\o": "ø", - vvv: "⋁", - "\\xor": "⊻", - "!=": "≠", - ":=": "≔", - "<=": "≤", - ">=": "≥", - "-=": "≡", - "~=": "≅", - "~~": "≈", - "+-": "±", - "-+": "∓", - "\\langle ": "\u27E8", - "\\rangle ": "\u27E9", - "<->": "\u2194", - "<-": "\u2190", - "<--": "\u27F5", - "-->": "⟶", - "->": "→", - "=>": "⇒", - "\\circ": "∘", - "\\otimes": "⊗", - "\\angle": "∠" -} diff --git a/src/buildMathML.js b/src/buildMathML.js deleted file mode 100644 index ba45c072..00000000 --- a/src/buildMathML.js +++ /dev/null @@ -1,187 +0,0 @@ -/** - * This file converts a parse tree into a cooresponding MathML tree. The main - * entry point is the `buildMathML` function, which takes a parse tree from the - * parser. - */ - -import mathMLTree from "./mathMLTree" -import ParseError from "./ParseError" -import symbols, { ligatures } from "./symbols" -import { _mathmlGroupBuilders as groupBuilders } from "./defineFunction" -import { MathNode } from "./mathMLTree" -import setLineBreaks from "./linebreaking" -import utils from "./utils"; - -/** - * Takes a symbol and converts it into a MathML text node after performing - * optional replacement from symbols.js. - */ -export const makeText = function(text, mode, style) { - if ( - symbols[mode][text] && - symbols[mode][text].replace && - text.charCodeAt(0) !== 0xd835 && - !( - Object.prototype.hasOwnProperty.call(ligatures, text) && - style && - ((style.fontFamily && style.fontFamily.slice(4, 6) === "tt") || - (style.font && style.font.slice(4, 6) === "tt")) - ) - ) { - text = symbols[mode][text].replace; - } - - return new mathMLTree.TextNode(text); -}; - -/** - * Wrap the given array of nodes in an node if needed, i.e., - * unless the array has length 1. Always returns a single node. - */ -export const makeRow = function(body) { - if (body.length === 1) { - return body[0]; - } else { - return new mathMLTree.MathNode("mrow", body); - } -}; - -const isRel = item => { - return (item.type === "atom" && item.family === "rel") || - (item.type === "mclass" && item.mclass === "mrel") -} - -/** - * Takes a list of nodes, builds them, and returns a list of the generated - * MathML nodes. Also do a couple chores along the way: - * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}. - * (2) Suppress spacing between two adjacent relations. - */ -export const buildExpression = function(expression, style, isOrdgroup) { - if (expression.length === 1) { - const group = buildGroup(expression[0], style); - if (isOrdgroup && group instanceof MathNode && group.type === "mo") { - // When TeX writers want to suppress spacing on an operator, - // they often put the operator by itself inside braces. - group.setAttribute("lspace", "0em"); - group.setAttribute("rspace", "0em"); - } - return [group]; - } - - const groups = []; - for (let i = 0; i < expression.length; i++) { - const group = buildGroup(expression[i], style); - // Suppress spacing between adjacent relations - if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) { - group.setAttribute("rspace", "0em") - } - if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) { - group.setAttribute("lspace", "0em") - } - groups.push(group); - } - return groups; -}; - -/** - * Equivalent to buildExpression, but wraps the elements in an - * if there's more than one. Returns a single node instead of an array. - */ -export const buildExpressionRow = function(expression, style, isOrdgroup) { - return makeRow(buildExpression(expression, style, isOrdgroup)); -}; - -/** - * Takes a group from the parser and calls the appropriate groupBuilders function - * on it to produce a MathML node. - */ -export const buildGroup = function(group, style) { - if (!group) { - return new mathMLTree.MathNode("mrow"); - } - - if (groupBuilders[group.type]) { - // Call the groupBuilders function - const result = groupBuilders[group.type](group, style); - return result; - } else { - throw new ParseError("Got group of unknown type: '" + group.type + "'"); - } -}; - -const glue = _ => { - const glueNode = new mathMLTree.MathNode("mtd", []) - glueNode.setAttribute("style", "padding: 0;width: 50%;") - return glueNode -} - -const taggedExpression = (expression, tag, style, leqno, preventTagLap) => { - tag = buildExpressionRow(tag[0].body, style) - tag = utils.consolidateText(tag) - tag.classes = ["tml-tag"]; - if (!preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]) - tag.setAttribute("style", "width:0;") - tag.setAttribute("width", "0") - tag.setAttribute((leqno ? "rspace" : "lspace"), "-1width") - } - tag = new mathMLTree.MathNode("mtd", [tag]) - if (!preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0") } - - expression = new mathMLTree.MathNode("mtd", [expression]) - const rowArray = leqno - ? [tag, glue(), expression, glue()] - : [glue(), expression, glue(), tag]; - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]) - const table = new mathMLTree.MathNode("mtable", [mtr]) - table.setAttribute("width", "100%") - table.setAttribute("displaystyle", "true") - return table -} - -/** - * Takes a full parse tree and settings and builds a MathML representation of - * it. - */ -export default function buildMathML(tree, texExpression, style, settings) { - // Strip off outer tag wrapper for processing below. - let tag = null - if (tree.length === 1 && tree[0].type === "tag") { - tag = tree[0].tag - tree = tree[0].body - } - - const expression = buildExpression(tree, style); - - const n1 = expression.length === 0 ? null : expression[0] - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - && !(n1.type === "mstyle" && n1.attributes.mathcolor) - ? expression[0] - : setLineBreaks(expression, settings.displayMode, settings.annotate) - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno, settings.preventTagLap) - } - - let semantics - if (settings.annotate) { - // Build a TeX annotation of the source - const annotation = new mathMLTree.MathNode( - "annotation", [new mathMLTree.TextNode(texExpression)]); - annotation.setAttribute("encoding", "application/x-tex"); - semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = settings.annotate - ? new mathMLTree.MathNode("math", [semantics]) - : new mathMLTree.MathNode("math", [wrapper]) - - if (settings.xml) { - math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML") - } - if (settings.displayMode) { - math.setAttribute("display", "block"); - } - return math; -} diff --git a/src/constants.js b/src/constants.js deleted file mode 100644 index d568fd3a..00000000 --- a/src/constants.js +++ /dev/null @@ -1,25 +0,0 @@ -// In TeX, there are actually three sets of dimensions, one for each of -// textstyle, scriptstyle, and scriptscriptstyle. These are -// provided in the the arrays below, in that order. -// -export const metrics = { - quad: [1.0, 1.171, 1.472], // Extracted from TeX - - // The TeX default rule thickness, 0.04 em, often disappears from a browser screen. - // So we use a thicker rule. - defaultRuleThickness: [0.06, 0.074, 0.074], - - // The space between adjacent `|` columns in an array definition. - doubleRuleSep: [0.3, 0.3, 0.3], - - // The width of separator lines in {array} environments. - arrayRuleWidth: [0.06, 0.06, 0.04] -}; - -// Math style is not quite the same thing as script level. -export const StyleLevel = { - DISPLAY: 0, - TEXT: 1, - SCRIPT: 2, - SCRIPTSCRIPT: 3 -}; diff --git a/src/defineEnvironment.js b/src/defineEnvironment.js deleted file mode 100644 index a85b419f..00000000 --- a/src/defineEnvironment.js +++ /dev/null @@ -1,25 +0,0 @@ -import { _mathmlGroupBuilders } from "./defineFunction"; - -/** - * All registered environments. - * `environments.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `environments.js`. - */ -export const _environments = {}; - -export default function defineEnvironment({ type, names, props, handler, mathmlBuilder }) { - // Set default values of environments. - const data = { - type, - numArgs: props.numArgs || 0, - allowedInText: false, - numOptionalArgs: 0, - handler - }; - for (let i = 0; i < names.length; ++i) { - _environments[names[i]] = data; - } - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } -} diff --git a/src/defineFunction.js b/src/defineFunction.js deleted file mode 100644 index 6733612a..00000000 --- a/src/defineFunction.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * All registered functions. - * `functions.js` just exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary. - */ -export const _functions = {} - -/** - * All MathML builders. Should be only used in the `define*` and the `build*ML` - * functions. - */ -export const _mathmlGroupBuilders = {} - -export default function defineFunction({ - type, - names, - props, - handler, - mathmlBuilder -}) { - // Set default values of functions - const data = { - type, - numArgs: props.numArgs, - argTypes: props.argTypes, - allowedInArgument: !!props.allowedInArgument, - allowedInText: !!props.allowedInText, - allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, - numOptionalArgs: props.numOptionalArgs || 0, - infix: !!props.infix, - primitive: !!props.primitive, - handler: handler - } - for (let i = 0; i < names.length; ++i) { - _functions[names[i]] = data - } - if (type) { - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder - } - } -} - -/** - * Use this to register only the MathML builder for a function(e.g. - * if the function's ParseNode is generated in Parser.js rather than via a - * stand-alone handler provided to `defineFunction`). - */ -export function defineFunctionBuilders({ type, mathmlBuilder }) { - defineFunction({ - type, - names: [], - props: { numArgs: 0 }, - handler() { - throw new Error("Should never be called.") - }, - mathmlBuilder - }) -} - -export const normalizeArgument = function(arg) { - return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg -} - -// Since the corresponding buildMathML function expects a -// list of elements, we normalize for different kinds of arguments -export const ordargument = function(arg) { - return arg.type === "ordgroup" ? arg.body : [arg] -} diff --git a/src/defineMacro.js b/src/defineMacro.js deleted file mode 100644 index 130371cc..00000000 --- a/src/defineMacro.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * All registered global/built-in macros. - * `macros.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `macros.js`. - */ -export const _macros = {}; - -// This function might one day accept an additional argument and do more things. -export default function defineMacro(name, body) { - _macros[name] = body; -} diff --git a/src/domTree.js b/src/domTree.js deleted file mode 100644 index ee7ffdb3..00000000 --- a/src/domTree.js +++ /dev/null @@ -1,185 +0,0 @@ -/** - * These objects store the data about the DOM nodes we create, as well as some - * extra data. They can then be transformed into real DOM nodes with the - * `toNode` function or HTML markup using `toMarkup`. They are useful for both - * storing extra properties on the nodes, as well as providing a way to easily - * work with the DOM. - * - * Similar functions for working with MathML nodes exist in mathMLTree.js. - * - */ -import utils from "./utils"; - -/** - * Create an HTML className based on a list of classes. In addition to joining - * with spaces, we also remove empty classes. - */ -export const createClass = function(classes) { - return classes.filter((cls) => cls).join(" "); -}; - -const initNode = function(classes, style) { - this.classes = classes || []; - this.attributes = {}; - this.style = style || {}; -}; - -/** - * Convert into an HTML node - */ -const toNode = function(tagName) { - const node = document.createElement(tagName); - - // Apply the class - node.className = createClass(this.classes); - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - // Apply attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - // Append the children, also as HTML nodes - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; -}; - -/** - * Convert into an HTML markup string - */ -const toMarkup = function(tagName) { - let markup = `<${tagName}`; - - // Add the class - if (this.classes.length) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; - } - } - - markup += ">"; - - // Add the markup of the children, also as markup - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ``; - - return markup; -}; - -/** - * This node represents a span node, with a className, a list of children, and - * an inline style. - * - */ -export class Span { - constructor(classes, children, style) { - initNode.call(this, classes, style); - this.children = children || []; - } - - setAttribute(attribute, value) { - this.attributes[attribute] = value; - } - - toNode() { - return toNode.call(this, "span"); - } - - toMarkup() { - return toMarkup.call(this, "span"); - } -} - -export class TextNode { - constructor(text) { - this.text = text; - } - toNode() { - return document.createTextNode(this.text); - } - toMarkup() { - return utils.escape(this.text); - } -} - -/** - * This node represents an image embed () element. - */ -export class Img { - constructor(src, alt, style) { - this.alt = alt; - this.src = src; - this.classes = ["mord"]; - this.style = style; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - toNode() { - const node = document.createElement("img"); - node.src = this.src; - node.alt = this.alt; - node.className = "mord"; - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - return node; - } - - toMarkup() { - let markup = `${this.alt} { - const settings = context.parser.settings; - if (!settings.displayMode) { - throw new ParseError(`{${context.envName}} can be used only in display mode.`); - } -} - -const getTag = (group, style, rowNum) => { - let tag - const tagContents = group.tags.shift() - if (tagContents) { - // The author has written a \tag or a \notag in this row. - if (tagContents.body) { - tag = mml.buildExpressionRow(tagContents.body, style) - tag.classes = ["tml-tag"] - } else { - // \notag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []) - tag.setAttribute("style", "padding: 0; min-width:0") - return tag - } - } else if (group.colSeparationType === "multline" && - ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) { - // A multiline that does not receive a tag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []) - tag.setAttribute("style", "padding: 0; min-width:0") - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a post-processor. - tag = new mathMLTree.MathNode("mtext", [], ["tml-eqn"]) - } - if (!group.preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]) - tag.setAttribute("style", "width:0;") - tag.setAttribute("width", "0") - if (!group.leqno) { tag.setAttribute("lspace", "-1width") } - } - tag = new mathMLTree.MathNode("mtd", [tag]) - if (!group.preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0") } - return tag -} - -/** - * Parse the body of the environment, with rows delimited by \\ and - * columns delimited by &, and create a nested list in row-major order - * with one group per cell. If given an optional argument scriptLevel - * ("text", "display", etc.), then each cell is cast into that scriptLevel. - */ -function parseArray( - parser, - { - hskipBeforeAndAfter, // boolean - addJot, // boolean - cols, // [{ type: string , align: l|c|r|null }] - arraystretch, // number - colSeparationType, // "align" | "alignat" | "gather" | "small" | "CD" | "multline" - addEqnNum, // boolean - singleRow, // boolean - emptySingleRow, // boolean - maxNumCols, // number - leqno // boolean - }, - scriptLevel -) { - parser.gullet.beginGroup(); - if (!singleRow) { - // \cr is equivalent to \\ without the optional size argument (see below) - // TODO: provide helpful error when \cr is used outside array environment - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - } - if (addEqnNum) { - parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag") - } - - // Get current arraystretch if it's not set by the environment - if (arraystretch === undefined || Number.isNaN(arraystretch)) { - const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); - if (stretch == null) { - // Default \arraystretch from lttab.dtx - arraystretch = 1 - } else { - arraystretch = parseFloat(stretch); - if (!arraystretch || arraystretch < 0) { - throw new ParseError(`Invalid \\arraystretch: ${stretch}`); - } - } - } - - // Start group for first cell - parser.gullet.beginGroup(); - - let row = []; - const body = [row]; - const rowGaps = []; - const tags = []; - let rowTag; - const hLinesBeforeRow = []; - - // Test for \hline at the top of the array. - hLinesBeforeRow.push(getHLines(parser)); - - // eslint-disable-next-line no-constant-condition - while (true) { - // Parse each cell in its own group (namespace) - let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\"); - - if (addEqnNum && !rowTag) { - // Check if the author wrote a \tag{} inside this cell. - for (let i = 0; i < cell.length; i++) { - if (cell[i].type === "envTag" || cell[i].type === "noTag") { - // Get the contents of the \text{} nested inside the \env@Tag{} - rowTag = cell[i].type === "envTag" - ? cell.splice(i, 1)[0].body.body[0] - : { body: null }; - break - } - } - } - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - - cell = { - type: "ordgroup", - mode: parser.mode, - body: cell - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (colSeparationType === "split") { - throw new ParseError("The split environment accepts no more than two columns", - parser.nextToken); - } else if (colSeparationType === "array") { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else { - throw new ParseError("The equation environment accepts only one column", - parser.nextToken) - } - } - parser.consume(); - } else if (next === "\\end") { - // Arrays terminate newlines with `\crcr` which consumes a `\cr` if - // the last line is empty. However, AMS environments keep the - // empty row if it's the only one. - // NOTE: Currently, `cell` is the last item added into `row`. - if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) { - body.pop(); - } - if (hLinesBeforeRow.length < body.length + 1) { - hLinesBeforeRow.push([]); - } - break; - } else if (next === "\\\\") { - parser.consume(); - let size; - // \def\Let@{\let\\\math@cr} - // \def\math@cr{...\math@cr@} - // \def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}} - // \def\math@cr@@[#1]{...\math@cr@@@...} - // \def\math@cr@@@{\cr} - if (parser.gullet.future().text !== " ") { - size = parser.parseSizeGroup(true); - } - rowGaps.push(size ? size.value : null); - - tags.push(rowTag) - - // check for \hline(s) following the row separator - hLinesBeforeRow.push(getHLines(parser)); - - row = []; - rowTag = null; - body.push(row); - } else { - throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); - } - } - - // End cell group - parser.gullet.endGroup(); - // End array group defining \cr - parser.gullet.endGroup(); - - tags.push(rowTag) - - return { - type: "array", - mode: parser.mode, - addJot, - arraystretch, - body, - cols, - rowGaps, - hskipBeforeAndAfter, - hLinesBeforeRow, - colSeparationType, - addEqnNum, - scriptLevel, - tags, - leqno, - preventTagLap: parser.settings.preventTagLap - }; -} - -// Decides on a scriptLevel for cells in an array according to whether the given -// environment name starts with the letter 'd'. -function dCellStyle(envName) { - return envName.slice(0, 1) === "d" ? "display" : "text" -} - -const alignMap = { - c: "center ", - l: "left ", - r: "right " -}; - -const mathmlBuilder = function(group, style) { - const tbl = []; - const numRows = group.body.length - let glue - if (group.addEqnNum) { - glue = new mathMLTree.MathNode("mtd", [], []) - const glueStyle = "padding: 0;width: " + - (group.colSeparationType === "multline" ? "7.5%" : "50%") - glue.setAttribute("style", glueStyle) - } - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellStyle = group.scriptLevel === "text" - ? StyleLevel.TEXT - : group.scriptLevel === "script" - ? StyleLevel.SCRIPT - : StyleLevel.DISPLAY - - for (let j = 0; j < rw.length; j++) { - const mtd = new mathMLTree.MathNode( - "mtd", - [mml.buildGroup(rw[j], style.withLevel(cellStyle))] - ) - if (group.colSeparationType === "multline") { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center" - mtd.setAttribute("columnalign", align) - } - row.push(mtd) - } - if (group.addEqnNum) { - row.unshift(glue); - row.push(glue); - const tag = getTag(group, style.withLevel(cellStyle), i) - if (group.leqno) { - row.unshift(tag) - } else { - row.push(tag) - } - } - // If group.addEqnNum, insert a breadcrumb to be found by temmlPostProcess(). - tbl.push(new mathMLTree.MathNode("mtr", row, group.addEqnNum ? ["tml-tageqn"] : [] )); - } - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true") } - - // Set column alignment, row spacing, column spacing, and - // array lines by setting attributes on the table element. - - // Set the row spacing. In MathML, we specify a gap distance. - // We do not use rowGap[] because MathML automatically increases - // cell height with the height/depth of the element content. - - // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. - // We simulate this by adding (arraystretch - 1)em to the gap. This - // does a reasonable job of adjusting arrays containing 1 em tall content. - - // The 0.16 and 0.09 values are found emprically. They produce an array - // similar to LaTeX and in which content does not interfere with \hines. - const gap = - group.arraystretch === 0 - ? 0 // {subarray} - : group.arraystretch === 0.5 - ? 0.1 // {smallmatrix} - : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); - table.setAttribute("rowspacing", utils.round(gap) + "em") - - if (group.addEqnNum || group.colSeparationType === "multline") { - table.setAttribute("width", "100%") - } - - // MathML table lines go only between cells. - // To place a line on an edge we'll use , if necessary. - let menclose = ""; - let align = ""; - - if (group.cols && group.cols.length > 0) { - // Find column alignment, column spacing, and vertical lines. - const cols = group.cols; - let columnLines = ""; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - if (cols[0].type === "separator") { - menclose += "left "; - iStart = 1; - } - if (cols[cols.length - 1].type === "separator") { - menclose += "right "; - iEnd -= 1; - } - - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - align += alignMap[cols[i].align]; - - if (prevTypeWasAlign) { - columnLines += "none "; - } - prevTypeWasAlign = true; - } else if (cols[i].type === "separator") { - // MathML accepts only single lines between cells. - // So we read only the first of consecutive separators. - if (prevTypeWasAlign) { - columnLines += cols[i].separator === "|" ? "solid " : "dashed "; - prevTypeWasAlign = false; - } - } - } - if (group.addEqnNum) { - align = "left " + align + "right " // allow for glue cells on each side - align = group.leqno ? "left " + align : align += "right" // eqn num cell - } - - table.setAttribute("columnalign", align.trim()); - - if (/[sd]/.test(columnLines)) { - table.setAttribute("columnlines", columnLines.trim()); - } - } - - // Set column spacing. - switch (group.colSeparationType) { - case "gather": - case "gathered": - case "alignedat": - case "alignat": - case "alignat*": - table.setAttribute("columnspacing", "0em"); - break - case "small": - table.setAttribute("columnspacing", "0.2778em"); - break - case "CD": - table.setAttribute("columnspacing", "0.5em"); - break - case "align": - case "align*": { - const cols = group.cols || []; - let spacing = group.addEqnNum ? "0em " : "" - for (let i = 1; i < cols.length; i++) { - spacing += i % 2 ? "0em " : "1em " - } - if (group.addEqnNum) { spacing += "0em" } - table.setAttribute("columnspacing", spacing.trim()); - break - } - default: - table.setAttribute("columnspacing", "1em"); - } - - // Address \hline and \hdashline - let rowLines = ""; - const hlines = group.hLinesBeforeRow; - - menclose += hlines[0].length > 0 ? "top " : ""; - menclose += hlines[hlines.length - 1].length > 0 ? "bottom " : ""; - - for (let i = 1; i < hlines.length - 1; i++) { - rowLines += - hlines[i].length === 0 - ? "none " - : // MathML accepts only a single line between rows. Read one element. - hlines[i][0] - ? "dashed " - : "solid "; - } - if (/[sd]/.test(rowLines)) { - table.setAttribute("rowlines", rowLines.trim()); - } - - if (menclose !== "") { - table = new mathMLTree.MathNode("menclose", [table]); - table.setAttribute("notation", menclose.trim()); - } - - if (!Number.isNaN(group.arraystretch) && group.arraystretch < 1) { - // A small array. Wrap in scriptstyle so row gap is not too large. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table; -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addJot: true, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - colSeparationType: context.envName, - maxNumCols: context.envName === "split" ? 2 : undefined, - leqno: context.parser.settings.leqno - }, - "display" - ); - - // Determining number of columns. - // 1. If the first argument is given, we use it as a number of columns, - // and makes sure that each row doesn't exceed that number. - // 2. Otherwise, just count number of columns = maximum number - // of cells in each row ("aligned" mode -- isAligned will be true). - // - // At the same time, prepend empty group {} at beginning of every second - // cell in each row (starting with second cell) so that operators become - // binary. This behavior is implemented in amsmath's \start@aligned. - let numMaths; - let numCols = 0; - if (args[0] && args[0].type === "ordgroup") { - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - const isAligned = !numCols; - res.body.forEach(function(row) { - if (!isAligned) { - // Case 1 - const curMaths = row.length / 2; - if (numMaths < curMaths) { - throw new ParseError( - "Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, - row[0] - ); - } - } else if (numCols < row.length) { - // Case 2 - numCols = row.length; - } - }); - - // Adjusting alignment. - // In aligned mode, we add one \qquad between columns; - // otherwise we add nothing. - for (let i = 0; i < numCols; ++i) { - let align = "r"; - if (i % 2 === 1) { - align = "l"; - } - cols[i] = { - type: "align", - align: align - }; - } - res.colSeparationType = isAligned ? "align" : "alignat"; - return res; -}; - -// Arrays are part of LaTeX, defined in lttab.dtx so its documentation -// is part of the source2e.pdf file of LaTeX2e source documentation. -// {darray} is an {array} environment where cells are set in \displaystyle, -// as defined in nccmath.sty. -defineEnvironment({ - type: "array", - names: ["array", "darray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Since no types are specified above, the two possibilities are - // - The argument is wrapped in {} or [], in which case Parser's - // parseGroup() returns an "ordgroup" wrapping some symbol node. - // - The argument is a bare symbol node. - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - if ("lcr".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } else if (ca === "|") { - return { - type: "separator", - separator: "|" - }; - } else if (ca === ":") { - return { - type: "separator", - separator: ":" - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - const res = { - cols, - colSeparationType: "array", - hskipBeforeAndAfter: true, // \@preamble in lttab.dtx - maxNumCols: cols.length - }; - return parseArray(context.parser, res, dCellStyle(context.envName)); - }, - mathmlBuilder -}); - -// The matrix environments of amsmath builds on the array environment -// of LaTeX, which is discussed above. -// The mathtools package adds starred versions of the same environments. -// These have an optional argument to choose left|center|right justification. -defineEnvironment({ - type: "array", - names: [ - "matrix", - "pmatrix", - "bmatrix", - "Bmatrix", - "vmatrix", - "Vmatrix", - "matrix*", - "pmatrix*", - "bmatrix*", - "Bmatrix*", - "vmatrix*", - "Vmatrix*" - ], - props: { - numArgs: 0 - }, - handler(context) { - const delimiters = { - matrix: null, - pmatrix: ["(", ")"], - bmatrix: ["[", "]"], - Bmatrix: ["\\{", "\\}"], - vmatrix: ["|", "|"], - Vmatrix: ["\\Vert", "\\Vert"] - }[context.envName.replace("*", "")]; - // \hskip -\arraycolsep in amsmath - let colAlign = "c"; - const payload = { - hskipBeforeAndAfter: false, - colSeparationType: "matrix", - cols: [{ type: "align", align: colAlign }] - }; - if (context.envName.charAt(context.envName.length - 1) === "*") { - // It's one of the mathtools starred functions. - // Parse the optional alignment argument. - const parser = context.parser; - parser.consumeSpaces(); - if (parser.fetch().text === "[") { - parser.consume(); - parser.consumeSpaces(); - colAlign = parser.fetch().text; - if ("lcr".indexOf(colAlign) === -1) { - throw new ParseError("Expected l or c or r", parser.nextToken); - } - parser.consume(); - parser.consumeSpaces(); - parser.expect("]"); - parser.consume(); - payload.cols = [{ type: "align", align: colAlign }]; - } - } - const res = parseArray(context.parser, payload, "text"); - // Populate cols with the correct number of column alignment specs. - const numCols = Math.max(0, ...res.body.map((row) => row.length)); - res.cols = new Array(numCols).fill({ type: "align", align: colAlign }) - return delimiters - ? { - type: "leftright", - mode: context.mode, - body: [res], - left: delimiters[0], - right: delimiters[1], - rightColor: undefined // \right uninfluenced by \color in array - } - : res; - }, - mathmlBuilder -}); - -defineEnvironment({ - type: "array", - names: ["smallmatrix"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { arraystretch: 0.5 }; - const res = parseArray(context.parser, payload, "script"); - res.colSeparationType = "small"; - return res; - }, - mathmlBuilder -}); - -defineEnvironment({ - type: "array", - names: ["subarray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Parsing of {subarray} is similar to {array} - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - // {subarray} only recognizes "l" & "c" - if ("lc".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - if (cols.length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - let res = { - cols, - hskipBeforeAndAfter: false, - colSeparationType: "array", - arraystretch: 0 - }; - res = parseArray(context.parser, res, "script"); - if (res.body.length > 0 && res.body[0].length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - return res; - }, - mathmlBuilder -}); - -// A cases environment (in amsmath.sty) is almost equivalent to -// \def -// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. -// {dcases} is a {cases} environment where cells are set in \displaystyle, -// as defined in mathtools.sty. -// {rcases} is another mathtools environment. It's brace is on the right side. -defineEnvironment({ - type: "array", - names: ["cases", "dcases", "rcases", "drcases"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { - cols: [ - { - type: "align", - align: "l" - }, - { - type: "align", - align: "l" - } - ], - colSeparationType: "cases" - }; - const res = parseArray(context.parser, payload, dCellStyle(context.envName)); - return { - type: "leftright", - mode: context.mode, - body: [res], - left: context.envName.indexOf("r") > -1 ? "." : "\\{", - right: context.envName.indexOf("r") > -1 ? "\\}" : ".", - rightColor: undefined - }; - }, - mathmlBuilder -}); - -// In the align environment, one uses ampersands, &, to specify number of -// columns in each row, and to locate spacing between each column. -// align gets automatic numbering. align* and aligned do not. -// The alignedat environment can be used in math mode. -// Note that we assume \nomallineskiplimit to be zero, -// so that \strut@ is the same as \strut. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - mathmlBuilder -}); - -// A gathered environment is like an array environment with one centered -// column, but where rows are considered lines so get \jot line spacing -// and contents are set in \displaystyle. -defineEnvironment({ - type: "array", - names: ["gathered", "gather", "gather*"], - props: { - numArgs: 0 - }, - handler(context) { - if (utils.contains(["gather", "gather*"], context.envName)) { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [ - { - type: "align", - align: "c" - } - ], - addJot: true, - colSeparationType: "gather", - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder -}); - -// alignat environment is like an align environment, but one must explicitly -// specify maximum number of columns in each row, and can adjust spacing between -// each columns. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - handler: alignedHandler, - mathmlBuilder -}); - -defineEnvironment({ - type: "array", - names: ["equation", "equation*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "equation", - emptySingleRow: true, - singleRow: true, - maxNumCols: 1, - colSeparationType: "gather", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder -}); - -defineEnvironment({ - type: "array", - names: ["multline", "multline*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "multline", - maxNumCols: 1, - colSeparationType: "multline", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder -}); - -defineEnvironment({ - type: "array", - names: ["CD"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - return parseCD(context.parser); - }, - mathmlBuilder -}); - -// Catch \hline outside array environment -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\hline", "\\hdashline"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: true - }, - handler(context, args) { - throw new ParseError(`${context.funcName} valid only within array environment`); - } -}); diff --git a/src/environments/cd.js b/src/environments/cd.js deleted file mode 100644 index 9bb550de..00000000 --- a/src/environments/cd.js +++ /dev/null @@ -1,260 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; -import { assertSymbolNodeType } from "../parseNode"; -import ParseError from "../ParseError"; - -const cdArrowFunctionName = { - ">": "\\\\cdrightarrow", - "<": "\\\\cdleftarrow", - "=": "\\\\cdlongequal", - A: "\\uparrow", - V: "\\downarrow", - "|": "\\Vert", - ".": "no arrow" -}; - -const newCell = () => { - // Create an empty cell, to be filled below with parse nodes. - return { type: "styling", body: [], mode: "math", scriptLevel: "display" }; -}; - -const isStartOfArrow = (node) => { - return node.type === "textord" && node.text === "@"; -}; - -const isLabelEnd = (node, endChar) => { - return (node.type === "mathord" || node.type === "atom") && node.text === endChar; -}; - -function cdArrow(arrowChar, labels, parser) { - // Return a parse tree of an arrow and its labels. - // This acts in a way similar to a macro expansion. - const funcName = cdArrowFunctionName[arrowChar]; - switch (funcName) { - case "\\\\cdrightarrow": - case "\\\\cdleftarrow": - return parser.callFunction(funcName, [labels[0]], [labels[1]]); - case "\\uparrow": - case "\\downarrow": { - const leftLabel = parser.callFunction("\\\\cdleft", [labels[0]], []); - const bareArrow = { - type: "atom", - text: funcName, - mode: "math", - family: "rel" - }; - const sizedArrow = parser.callFunction("\\Big", [bareArrow], []); - const rightLabel = parser.callFunction("\\\\cdright", [labels[1]], []); - const arrowGroup = { - type: "ordgroup", - mode: "math", - body: [leftLabel, sizedArrow, rightLabel] - }; - return parser.callFunction("\\\\cdparent", [arrowGroup], []); - } - case "\\\\cdlongequal": - return parser.callFunction("\\\\cdlongequal", [], []); - case "\\Vert": { - const arrow = { type: "textord", text: "\\Vert", mode: "math" }; - return parser.callFunction("\\Big", [arrow], []); - } - default: - return { type: "textord", text: " ", mode: "math" }; - } -} - -export function parseCD(parser) { - // Get the array's parse nodes with \\ temporarily mapped to \cr. - const parsedRows = []; - parser.gullet.beginGroup(); - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - parser.gullet.beginGroup(); - while (true) { // eslint-disable-line no-constant-condition - // Get the parse nodes for the next row. - parsedRows.push(parser.parseExpression(false, "\\\\")); - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - const next = parser.fetch().text; - if (next === "&" || next === "\\\\") { - parser.consume(); - } else if (next === "\\end") { - if (parsedRows[parsedRows.length - 1].length === 0) { - parsedRows.pop(); // final row ended in \\ - } - break; - } else { - throw new ParseError("Expected \\\\ or \\cr or \\end", parser.nextToken); - } - } - - let row = []; - const body = [row]; - - // Loop thru the parse nodes. Collect them into cells and arrows. - for (let i = 0; i < parsedRows.length; i++) { - // Start a new row. - const rowNodes = parsedRows[i]; - // Create the first cell. - let cell = newCell(); - - for (let j = 0; j < rowNodes.length; j++) { - if (!isStartOfArrow(rowNodes[j])) { - // If a parseNode is not an arrow, it goes into a cell. - cell.body.push(rowNodes[j]); - } else { - // Parse node j is an "@", the start of an arrow. - // Before starting on the arrow, push the cell into `row`. - row.push(cell); - - // Now collect parseNodes into an arrow. - // The character after "@" defines the arrow type. - j += 1; - const arrowChar = assertSymbolNodeType(rowNodes[j]).text; - - // Create two empty label nodes. We may or may not use them. - const labels = new Array(2); - labels[0] = { type: "ordgroup", mode: "math", body: [] }; - labels[1] = { type: "ordgroup", mode: "math", body: [] }; - - // Process the arrow. - if ("=|.".indexOf(arrowChar) > -1) { - // Three "arrows", ``@=`, `@|`, and `@.`, do not take labels. - // Do nothing here. - } else if ("<>AV".indexOf(arrowChar) > -1) { - // Four arrows, `@>>>`, `@<<<`, `@AAA`, and `@VVV`, each take - // two optional labels. E.g. the right-point arrow syntax is - // really: @>{optional label}>{optional label}> - // Collect parseNodes into labels. - for (let labelNum = 0; labelNum < 2; labelNum++) { - let inLabel = true; - for (let k = j + 1; k < rowNodes.length; k++) { - if (isLabelEnd(rowNodes[k], arrowChar)) { - inLabel = false; - j = k; - break; - } - if (isStartOfArrow(rowNodes[k])) { - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[k] - ); - } - - labels[labelNum].body.push(rowNodes[k]); - } - if (inLabel) { - // isLabelEnd never returned a true. - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[j] - ); - } - } - } else { - throw new ParseError(`Expected one of "<>AV=|." after @.`); - } - - // Now join the arrow to its labels. - const arrow = cdArrow(arrowChar, labels, parser); - - // Wrap the arrow in a styling node - row.push(arrow); - // In CD's syntax, cells are implicit. That is, everything that - // is not an arrow gets collected into a cell. So create an empty - // cell now. It will collect upcoming parseNodes. - cell = newCell(); - } - } - if (i % 2 === 0) { - // Even-numbered rows consist of: cell, arrow, cell, arrow, ... cell - // The last cell is not yet pushed into `row`, so: - row.push(cell); - } else { - // Odd-numbered rows consist of: vert arrow, empty cell, ... vert arrow - // Remove the empty cell that was placed at the beginning of `row`. - row.shift(); - } - row = []; - body.push(row); - } - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - // define column separation. - const cols = new Array(body[0].length).fill({ - type: "align", - align: "c" - }); - - return { - type: "array", - mode: "math", - body, - arraystretch: 1, - addJot: true, - rowGaps: [null], - cols, - colSeparationType: "CD", - hLinesBeforeRow: new Array(body.length + 1).fill([]) - }; -} - -// The functions below are not available for general use. -// They are here only for internal use by the {CD} environment in placing labels -// next to vertical arrows. - -// We don't need any such functions for horizontal arrows because we can reuse -// the functionality that already exists for extensible arrows. - -defineFunction({ - type: "cdlabel", - names: ["\\\\cdleft", "\\\\cdright"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "cdlabel", - mode: parser.mode, - side: funcName.slice(4), - label: args[0] - }; - }, - mathmlBuilder(group, style) { - let label = new mathMLTree.MathNode("mrow", [mml.buildGroup(group.label, style)]); - label = new mathMLTree.MathNode("mpadded", [label]); - label.setAttribute("width", "0"); - if (group.side === "left") { - label.setAttribute("lspace", "-1width"); - } - // We have to guess at vertical alignment. We know the arrow is 1.8em tall, - // But we don't know the height or depth of the label. - label.setAttribute("voffset", "0.7em"); - label = new mathMLTree.MathNode("mstyle", [label]); - label.setAttribute("displaystyle", "false"); - label.setAttribute("scriptlevel", "1"); - return label; - } -}); - -defineFunction({ - type: "cdlabelparent", - names: ["\\\\cdparent"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - return { - type: "cdlabelparent", - mode: parser.mode, - fragment: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow", [mml.buildGroup(group.fragment, style)]); - } -}); diff --git a/src/functions.js b/src/functions.js deleted file mode 100644 index 72e8e5b5..00000000 --- a/src/functions.js +++ /dev/null @@ -1,59 +0,0 @@ -/** Include this to ensure that all functions are defined. */ -import { _functions } from "./defineFunction"; - -const functions = _functions; -export default functions; - -// TODO(kevinb): have functions return an object and call defineFunction with -// that object in this file instead of relying on side-effects. -import "./functions/accent"; -import "./functions/accentunder"; -import "./functions/arrow"; -import "./functions/cancelto"; -import "./environments/cd"; -import "./functions/char"; -import "./functions/color"; -import "./functions/cr"; -import "./functions/def"; -import "./functions/delimsizing"; -import "./functions/enclose"; -import "./functions/environment"; -import "./functions/envTag"; -import "./functions/font"; -import "./functions/genfrac"; -import "./functions/horizBrace"; -import "./functions/href"; -import "./functions/html"; -import "./functions/includegraphics"; -import "./functions/kern"; -import "./functions/label"; -import "./functions/lap"; -import "./functions/math"; -import "./functions/mathchoice"; -import "./functions/mclass"; -import "./functions/multiscript"; -import "./functions/not"; -import "./functions/op"; -import "./functions/operatorname"; -import "./functions/ordgroup"; -import "./functions/overline"; -import "./functions/phantom"; -import "./functions/pmb"; -import "./functions/raise"; -import "./functions/ref"; -import "./functions/relax"; -import "./functions/rule"; -import "./functions/sizing"; -import "./functions/smash"; -import "./functions/sqrt"; -import "./functions/styling"; -import "./functions/supsub"; -import "./functions/symbolsOp"; -import "./functions/symbolsOrd"; -import "./functions/symbolsSpacing"; -import "./functions/tag"; -import "./functions/text"; -import "./functions/tip"; -import "./functions/toggle"; -import "./functions/underline"; -import "./functions/verb"; diff --git a/src/functions/accent.js b/src/functions/accent.js deleted file mode 100644 index 051d0b8d..00000000 --- a/src/functions/accent.js +++ /dev/null @@ -1,128 +0,0 @@ -import defineFunction, { normalizeArgument } from "../defineFunction" -import mathMLTree from "../mathMLTree" -import stretchy from "../stretchy" -import * as mml from "../buildMathML" - -const mathmlBuilder = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.mathMLnode(group.label) - : new mathMLTree.MathNode("mo", [mml.makeText(group.label, group.mode)]); - - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false") - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [mml.buildGroup(group.base, style), accentNode] - ); - - node.setAttribute("accent", "true"); - return node; -}; - -const NON_STRETCHY_ACCENT_REGEX = new RegExp( - [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" - ] - .map((accent) => `\\${accent}`) - .join("|") -); - -// Accents -defineFunction({ - type: "accent", - names: [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring", - "\\overparen", - "\\widecheck", - "\\widehat", - "\\wideparen", - "\\widetilde", - "\\overrightarrow", - "\\overleftarrow", - "\\Overrightarrow", - "\\overleftrightarrow", - "\\overgroup", - "\\overleftharpoon", - "\\overrightharpoon" - ], - props: { - numArgs: 1 - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - - const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); - const isShifty = - !isStretchy || - context.funcName === "\\widehat" || - context.funcName === "\\widetilde" || - context.funcName === "\\widecheck"; - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - isShifty: isShifty, - base: base - }; - }, - mathmlBuilder -}); - -// Text-mode accents -defineFunction({ - type: "accent", - names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\c", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"], - props: { - numArgs: 1, - allowedInText: true, - allowedInMath: true, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - const mode = context.parser.mode; - - if (mode === "math" && context.parser.settings.strict) { - // LaTeX only writes a warning. It doesn't stop. We'll issue the same warning. - // eslint-disable-next-line no-console - console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`) - } - - return { - type: "accent", - mode: mode, - label: context.funcName, - isStretchy: false, - isShifty: true, - base: base - }; - }, - mathmlBuilder -}); diff --git a/src/functions/accentunder.js b/src/functions/accentunder.js deleted file mode 100644 index 6ac3cbff..00000000 --- a/src/functions/accentunder.js +++ /dev/null @@ -1,38 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import stretchy from "../stretchy"; - -import * as mml from "../buildMathML"; - -defineFunction({ - type: "accentUnder", - names: [ - "\\underleftarrow", - "\\underrightarrow", - "\\underleftrightarrow", - "\\undergroup", - "\\underparen", - "\\utilde" - ], - props: { - numArgs: 1 - }, - handler: ({ parser, funcName }, args) => { - const base = args[0]; - return { - type: "accentUnder", - mode: parser.mode, - label: funcName, - base: base - }; - }, - mathmlBuilder: (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - const node = new mathMLTree.MathNode("munder", [ - mml.buildGroup(group.base, style), - accentNode - ]); - node.setAttribute("accentunder", "true"); - return node; - } -}); diff --git a/src/functions/arrow.js b/src/functions/arrow.js deleted file mode 100644 index b5412c4a..00000000 --- a/src/functions/arrow.js +++ /dev/null @@ -1,192 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import stretchy from "../stretchy"; -import { emScale } from "../units"; -import * as mml from "../buildMathML"; - -// Helper functions -const paddedNode = (group, width, lspace = "0.3em") => { - const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); - node.setAttribute("width", width) - node.setAttribute("lspace", lspace) - return node; -}; - -const labelSize = (size, scriptLevel) => (size / emScale(scriptLevel)).toFixed(4) + "em" - -const munderoverNode = (name, body, below, style) => { - const arrowNode = stretchy.mathMLnode(name); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = name.slice(1, 3) === "eq" - const minWidth = name.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are 1.75em long - : name.slice(2, 4) === "cd" - ? "3.0" // cd package arrows - : isEq - ? "1.0" // The shorter harpoon of a mhchem equilibrium arrow - : "2.0"; // other mhchem arrows - arrowNode.setAttribute("minsize", String(minWidth) + "em"); - arrowNode.setAttribute("lspace", "0") - arrowNode.setAttribute("rspace", (isEq ? "0.5em" : "0")) - - // upper and lower labels are set to scriptlevel by MathML - // So we have to adjust our dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3) - const emptyLabelWidth = labelSize(minWidth, labelStyle.level) - const lspace = labelSize((isEq ? 0 : 0.3), labelStyle.level) - let widthAdder = labelSize((isEq ? -0.4 : 0.6), labelStyle.level) - if (widthAdder.charAt(0) !== "-") { widthAdder = "+" + widthAdder } - - const upperNode = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)) - ? paddedNode(mml.buildGroup(body, labelStyle), widthAdder, lspace) - // Since Firefox does not recognize minsize set on the arrow, - // create an upper node w/correct width. - : paddedNode(null, emptyLabelWidth, "0") - const lowerNode = (below && below.body && - (below.body.body || below.body.length > 0)) - ? paddedNode(mml.buildGroup(below, labelStyle), widthAdder, lspace) - : paddedNode(null, emptyLabelWidth, "0") - const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - return node -} - -// Stretchy arrows with an optional argument -defineFunction({ - type: "xArrow", - names: [ - "\\xleftarrow", - "\\xrightarrow", - "\\xLeftarrow", - "\\xRightarrow", - "\\xleftrightarrow", - "\\xLeftrightarrow", - "\\xhookleftarrow", - "\\xhookrightarrow", - "\\xmapsto", - "\\xrightharpoondown", - "\\xrightharpoonup", - "\\xleftharpoondown", - "\\xleftharpoonup", - "\\xlongequal", - "\\xtwoheadrightarrow", - "\\xtwoheadleftarrow", - // The next 7 functions are here only to support mhchem - "\\yields", - "\\yieldsLeft", - "\\mesomerism", - "\\longrightharpoonup", - "\\longleftharpoondown", - // The next 3 functions are here only to support the {CD} environment. - "\\\\cdrightarrow", - "\\\\cdleftarrow", - "\\\\cdlongequal" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - return { - type: "xArrow", - mode: parser.mode, - name: funcName, - body: args[0], - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - // Build the arrow and its labels. - const node = munderoverNode(group.name, group.body, group.below, style) - // Create operator spacing for a relation. - const wrapper = new mathMLTree.MathNode("mpadded", [node]) - wrapper.setAttribute("lspace", "0.2778em") - wrapper.setAttribute("width", "+0.5556em") - return wrapper - } -}); - -const arrowComponent = { - "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"], - "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"], - "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"], - "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"], - // The next three all get the same harpoon glyphs. Only the lengths and paddings differ. - "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"], - "\\equilibriumRight": ["\\longrightharpoonup", "\\eqleftharpoondown"], - "\\equilibriumLeft": ["\\eqrightharpoonup", "\\longleftharpoondown"] -} - -// Browsers are not good at stretching a glyph that contains a pair of stacked arrows such as ⇄. -// So we stack a pair of single arrows. -defineFunction({ - type: "stackedArrow", - names: [ - "\\xtofrom", // expfeil - "\\xleftrightharpoons", // mathtools - "\\xrightleftharpoons", // mathtools - "\\yieldsLeftRight", // mhchem - "\\equilibrium", // mhchem - "\\equilibriumRight", - "\\equilibriumLeft" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - const lowerArrowBody = args[0] - ? { - type: "hphantom", - mode: parser.mode, - body: args[0] - } - : null; - const upperArrowBelow = optArgs[0] - ? { - type: "hphantom", - mode: parser.mode, - body: optArgs[0] - } - : null; - return { - type: "stackedArrow", - mode: parser.mode, - name: funcName, - body: args[0], - upperArrowBelow, - lowerArrowBody, - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - const topLabel = arrowComponent[group.name][0] - const botLabel = arrowComponent[group.name][1] - const topArrow = munderoverNode(topLabel, group.body, group.upperArrowBelow, style) - const botArrow = munderoverNode(botLabel, group.lowerArrowBody, group.below, style) - let wrapper - - const raiseNode = new mathMLTree.MathNode("mpadded", [topArrow]) - raiseNode.setAttribute("voffset", "0.3em") - raiseNode.setAttribute("height", "+0.3em") - raiseNode.setAttribute("depth", "-0.3em") - // One of the arrows is given ~zero width. so the other has the same horzontal alignment. - if (group.name === "\\equilibriumLeft") { - const botNode = new mathMLTree.MathNode("mpadded", [botArrow]) - botNode.setAttribute("width", "0.5em") - wrapper = new mathMLTree.MathNode("mpadded", [botNode, raiseNode]) - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")) - wrapper = new mathMLTree.MathNode("mpadded", [raiseNode, botArrow]) - } - - wrapper.setAttribute("voffset", "-0.18em") - wrapper.setAttribute("width", "+0.5556em") - wrapper.setAttribute("height", "-0.18em") - wrapper.setAttribute("depth", "+0.18em") - wrapper.setAttribute("lspace", "0.2778em") - return wrapper - } -}); - diff --git a/src/functions/cancelto.js b/src/functions/cancelto.js deleted file mode 100644 index 1b418a24..00000000 --- a/src/functions/cancelto.js +++ /dev/null @@ -1,36 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -defineFunction({ - type: "cancelto", - names: ["\\cancelto"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "cancelto", - mode: parser.mode, - value: args[0], - expression: args[1] - }; - }, - mathmlBuilder(group, style) { - const value = new mathMLTree.MathNode( - "mpadded", - [mml.buildGroup(group.value, style)] - ) - value.setAttribute("depth", `-0.1em`) - value.setAttribute("height", `+0.1em`) - value.setAttribute("voffset", `0.1em`) - - const expression = new mathMLTree.MathNode( - "menclose", - [mml.buildGroup(group.expression, style)] - ) - expression.setAttribute("notation", `updiagonalarrow`) - - return new mathMLTree.MathNode("msup", [expression, value]) - } -}) diff --git a/src/functions/char.js b/src/functions/char.js deleted file mode 100644 index b2355c0b..00000000 --- a/src/functions/char.js +++ /dev/null @@ -1,33 +0,0 @@ -import defineFunction from "../defineFunction" -import ParseError from "../ParseError" -import { assertNodeType } from "../parseNode" - -// \@char is an internal function that takes a grouped decimal argument like -// {123} and converts into symbol with code 123. It is used by the *macro* -// \char defined in macros.js. -defineFunction({ - type: "textord", - names: ["\\@char"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser, token }, args) { - const arg = assertNodeType(args[0], "ordgroup") - const group = arg.body - let number = "" - for (let i = 0; i < group.length; i++) { - const node = assertNodeType(group[i], "textord") - number += node.text - } - const code = parseInt(number) - if (isNaN(code)) { - throw new ParseError(`\\@char has non-numeric argument ${number}`, token) - } - return { - type: "textord", - mode: parser.mode, - text: String.fromCodePoint(code) - } - } -}) diff --git a/src/functions/color.js b/src/functions/color.js deleted file mode 100644 index eb15c6aa..00000000 --- a/src/functions/color.js +++ /dev/null @@ -1,254 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction" -import mathMLTree, { wrapWithMstyle } from "../mathMLTree" -import { assertNodeType } from "../parseNode" -import ParseError from "../ParseError" -import * as mml from "../buildMathML" - -// Helpers -const htmlRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6})$/i -const htmlOrNameRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i -const RGBregEx = /^ *\d{1,3} *(?:, *\d{1,3} *){2}$/ -const rgbRegEx = /^ *[10](?:\.\d*)? *(?:, *[10](?:\.\d*)? *){2}$/ -const xcolorHtmlRegEx = /^[a-f0-9]{6}$/i -const toHex = num => { - let str = num.toString(16) - if (str.length === 1) { str = "0" + str } - return str -} - -// Colors from Tables 4.1 and 4.2 of the xcolor package. -// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx. -// Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable -// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274. -const xcolors = JSON.parse(`{ - "Apricot": "#ffb484", - "Aquamarine": "#08b4bc", - "Bittersweet": "#c84c14", - "blue": "#0000FF", - "Blue": "#303494", - "BlueGreen": "#08b4bc", - "BlueViolet": "#503c94", - "BrickRed": "#b8341c", - "brown": "#BF8040", - "Brown": "#802404", - "BurntOrange": "#f8941c", - "CadetBlue": "#78749c", - "CarnationPink": "#f884b4", - "Cerulean": "#08a4e4", - "CornflowerBlue": "#40ace4", - "cyan": "#00FFFF", - "Cyan": "#08acec", - "Dandelion": "#ffbc44", - "darkgray": "#404040", - "DarkOrchid": "#a8548c", - "Emerald": "#08ac9c", - "ForestGreen": "#089c54", - "Fuchsia": "#90348c", - "Goldenrod": "#ffdc44", - "gray": "#808080", - "Gray": "#98949c", - "green": "#00FF00", - "Green": "#08a44c", - "GreenYellow": "#e0e474", - "JungleGreen": "#08ac9c", - "Lavender": "#f89cc4", - "lightgray": "#c0c0c0", - "lime": "#BFFF00", - "LimeGreen": "#90c43c", - "magenta": "#FF00FF", - "Magenta": "#f0048c", - "Mahogany": "#b0341c", - "Maroon": "#b03434", - "Melon": "#f89c7c", - "MidnightBlue": "#086494", - "Mulberry": "#b03c94", - "NavyBlue": "#086cbc", - "olive": "#7F7F00", - "OliveGreen": "#407c34", - "orange": "#FF8000", - "Orange": "#f8843c", - "OrangeRed": "#f0145c", - "Orchid": "#b074ac", - "Peach": "#f8945c", - "Periwinkle": "#8074bc", - "PineGreen": "#088c74", - "pink": "#ff7f7f", - "Plum": "#98248c", - "ProcessBlue": "#08b4ec", - "purple": "#BF0040", - "Purple": "#a0449c", - "RawSienna": "#983c04", - "red": "#ff0000", - "Red": "#f01c24", - "RedOrange": "#f86434", - "RedViolet": "#a0246c", - "Rhodamine": "#f0549c", - "Royallue": "#0874bc", - "RoyalPurple": "#683c9c", - "RubineRed": "#f0047c", - "Salmon": "#f8948c", - "SeaGreen": "#30bc9c", - "Sepia": "#701404", - "SkyBlue": "#48c4dc", - "SpringGreen": "#c8dc64", - "Tan": "#e09c74", - "teal": "#007F7F", - "TealBlue": "#08acb4", - "Thistle": "#d884b4", - "Turquoise": "#08b4cc", - "violet": "#800080", - "Violet": "#60449c", - "VioletRed": "#f054a4", - "WildStrawberry": "#f0246c", - "yellow": "#FFFF00", - "Yellow": "#fff404", - "YellowGreen": "#98cc6c", - "YellowOrange": "#ffa41c" -}`) - -export const colorFromSpec = (model, spec) => { - let color = "" - if (model === "HTML") { - if (!htmlRegEx.test(spec)) { - throw new ParseError("Invalid HTML input.") - } - color = spec - } else if (model === "RGB") { - if (!RGBregEx.test(spec)) { - throw new ParseError("Invalid RGB input.") - } - spec.split(",").map(e => { color += toHex(Number(e.trim())) }) - } else { - if (!rgbRegEx.test(spec)) { - throw new ParseError("Invalid rbg input.") - } - spec.split(",").map(e => { - const num = Number(e.trim()) - if (num > 1) { throw new ParseError("Color rgb input must be < 1.") } - color += toHex((num * 255)) - }) - } - if (color.charAt(0) !== "#") { color = "#" + color } - return color -} - -export const validateColor = (color, macros, token) => { - const macroName = `\\\\color@${color}` // from \defineColor. - const match = htmlOrNameRegEx.exec(color); - if (!match) { throw new ParseError("Invalid color: '" + color + "'", token) } - // We allow a 6-digit HTML color spec without a leading "#". - // This follows the xcolor package's HTML color model. - // Predefined color names are all missed by this RegEx pattern. - if (xcolorHtmlRegEx.test(color)) { - return "#" + color - } else if (color.charAt(0) === "#") { - return color - } else if (macros.has(macroName)) { - color = macros.get(macroName).tokens[0].text - } else if (xcolors[color]) { - color = xcolors[color] - } - return color -} - -const mathmlBuilder = (group, style) => { - const inner = mml.buildExpression(group.body, style.withColor(group.color)) - // Wrap with an element. - const node = wrapWithMstyle(inner) - node.setAttribute("mathcolor", group.color) - // Wrap w/. We get better operator spacing that way. - return new mathMLTree.MathNode("mrow", [node]) -} - -defineFunction({ - type: "color", - names: ["\\textcolor"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "original"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string - let color = "" - if (model) { - const spec = assertNodeType(args[0], "raw").string - color = colorFromSpec(model, spec) - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token) - } - const body = args[1]; - return { - type: "color", - mode: parser.mode, - color, - body: ordargument(body) - } - }, - mathmlBuilder -}) - -defineFunction({ - type: "color", - names: ["\\color"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string - let color = "" - if (model) { - const spec = assertNodeType(args[0], "raw").string - color = colorFromSpec(model, spec) - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token) - } - - // Set macro \current@color in current namespace to store the current - // color, mimicking the behavior of color.sty. - // This is currently used just to correctly color a \right - // that follows a \color command. - parser.gullet.macros.set("\\current@color", color) - - // Parse out the implicit body that should be colored. - // Since \color nodes should not be nested, break on \color. - const body = parser.parseExpression(true, "\\color") - - return { - type: "color", - mode: parser.mode, - color, - body - } - }, - mathmlBuilder -}) - -defineFunction({ - type: "color", - names: ["\\definecolor"], - props: { - numArgs: 3, - allowedInText: true, - argTypes: ["raw", "raw", "raw"] - }, - handler({ parser, funcName, token }, args) { - const name = assertNodeType(args[0], "raw").string - if (!/^[A-Za-z]+$/.test(name)) { - throw new ParseError("Color name must be latin letters.", token) - } - const model = assertNodeType(args[1], "raw").string - if (!["HTML", "RGB", "rgb"].includes(model)) { - throw new ParseError("Color model must be HTML, RGB, or rgb.", token) - } - const spec = assertNodeType(args[2], "raw").string - const color = colorFromSpec(model, spec) - parser.gullet.macros.set(`\\\\color@${name}`, { tokens: [{ text: color }], numArgs: 0 }) - return { type: "internal", mode: parser.mode } - } - // No mathmlBuilder. The point of \definecolor is to set a macro. -}) diff --git a/src/functions/cr.js b/src/functions/cr.js deleted file mode 100644 index 18de4655..00000000 --- a/src/functions/cr.js +++ /dev/null @@ -1,46 +0,0 @@ -// Row breaks within tabular environments, and line breaks at top level - -import defineFunction from "../defineFunction" -import mathMLTree from "../mathMLTree" -import { calculateSize } from "../units" -import { assertNodeType } from "../parseNode" - -// \DeclareRobustCommand\\{...\@xnewline} -defineFunction({ - type: "cr", - names: ["\\\\"], - props: { - numArgs: 0, - numOptionalArgs: 1, - argTypes: ["size"], - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = optArgs[0]; - const newLine = !parser.settings.displayMode; - return { - type: "cr", - mode: parser.mode, - newLine, - size: size && assertNodeType(size, "size").value - } - }, - - // The following builder is called only at the top level, - // not within tabular/array environments. - - mathmlBuilder(group, style) { - // MathML 3.0 calls for newline to occur in an or an . - // Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.linebreaking - const node = new mathMLTree.MathNode("mo") - if (group.newLine) { - node.setAttribute("linebreak", "newline") - if (group.size) { - const size = calculateSize(group.size, style) - node.setAttribute("height", size.number + size.unit) - } - } - return node - } -}) diff --git a/src/functions/def.js b/src/functions/def.js deleted file mode 100644 index 072611bb..00000000 --- a/src/functions/def.js +++ /dev/null @@ -1,203 +0,0 @@ -import defineFunction from "../defineFunction"; -import ParseError from "../ParseError"; - -const checkControlSequence = (tok) => { - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - return name; -}; - -const getRHS = (parser) => { - let tok = parser.gullet.popToken(); - if (tok.text === "=") { - // consume optional equals - tok = parser.gullet.popToken(); - if (tok.text === " ") { - // consume one optional space - tok = parser.gullet.popToken(); - } - } - return tok; -}; - -const letCommand = (parser, name, tok) => { - let macro = parser.gullet.macros.get(tok.text); - if (macro == null) { - // don't expand it later even if a macro with the same name is defined - // e.g., \let\foo=\frac \def\frac{\relax} \frac12 - tok.noexpand = true; - macro = { - tokens: [tok], - numArgs: 0, - // reproduce the same behavior in expansion - unexpandable: !parser.gullet.isExpandable(tok.text) - }; - } - parser.gullet.macros.set(name, macro); -}; - -// Basic support for macro definitions: \def -// -> -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\edef"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let tok = parser.gullet.popToken(); - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - - let numArgs = 0; - let insert; - const delimiters = [[]]; - // contains no braces - while (parser.gullet.future().text !== "{") { - tok = parser.gullet.popToken(); - if (tok.text === "#") { - // If the very last character of the is #, so that - // this # is immediately followed by {, TeX will behave as if the { - // had been inserted at the right end of both the parameter text - // and the replacement text. - if (parser.gullet.future().text === "{") { - insert = parser.gullet.future(); - delimiters[numArgs].push("{"); - break; - } - - // A parameter, the first appearance of # must be followed by 1, - // the next by 2, and so on; up to nine #’s are allowed - tok = parser.gullet.popToken(); - if (!/^[1-9]$/.test(tok.text)) { - throw new ParseError(`Invalid argument number "${tok.text}"`); - } - if (parseInt(tok.text) !== numArgs + 1) { - throw new ParseError(`Argument number "${tok.text}" out of order`); - } - numArgs++; - delimiters.push([]); - } else if (tok.text === "EOF") { - throw new ParseError("Expected a macro definition"); - } else { - delimiters[numArgs].push(tok.text); - } - } - // replacement text, enclosed in '{' and '}' and properly nested - let { tokens } = parser.gullet.consumeArg(); - if (insert) { - tokens.unshift(insert); - } - - if (funcName === "\\edef") { - tokens = parser.gullet.expandTokens(tokens); - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set(name, { tokens, numArgs, delimiters } - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: ["\\let"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.consumeSpaces(); - const tok = getRHS(parser); - letCommand(parser, name, tok); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: ["\\futurelet"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - const middle = parser.gullet.popToken(); - const tok = parser.gullet.popToken(); - letCommand(parser, name, tok); - parser.gullet.pushToken(tok); - parser.gullet.pushToken(middle); - return { type: "internal", mode: parser.mode }; - } -}); - -defineFunction({ - type: "internal", - names: ["\\newcommand", "\\renewcommand", "\\providecommand"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let name = "" - const tok = parser.gullet.popToken() - if (tok.text === "{") { - name = checkControlSequence(parser.gullet.popToken()) - parser.gullet.popToken() - } else { - name = checkControlSequence(tok) - } - - const exists = parser.gullet.isDefined(name); - if (exists && funcName === "\\newcommand") { - throw new ParseError( - `\\newcommand{${name}} attempting to redefine ${name}; use \\renewcommand` - ); - } - if (!exists && funcName === "\\renewcommand") { - throw new ParseError( - `\\renewcommand{${name}} when command ${name} does not yet exist; use \\newcommand` - ); - } - - let numArgs = 0; - if (parser.gullet.future().text === "[") { - let tok = parser.gullet.popToken(); - tok = parser.gullet.popToken(); - if (!/^[0-9]$/.test(tok.text)) { - throw new ParseError(`Invalid number of arguments: "${tok.text}"`); - } - numArgs = parseInt(tok.text); - tok = parser.gullet.popToken(); - if (tok.text !== "]") { - throw new ParseError(`Invalid argument "${tok.text}"`); - } - } - - // replacement text, enclosed in '{' and '}' and properly nested - const { tokens } = parser.gullet.consumeArg(); - - parser.gullet.macros.set(name, { tokens, numArgs }) - - return { type: "internal", mode: parser.mode }; - - } -}); diff --git a/src/functions/delimsizing.js b/src/functions/delimsizing.js deleted file mode 100644 index 953aa2b0..00000000 --- a/src/functions/delimsizing.js +++ /dev/null @@ -1,296 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import ParseError from "../ParseError"; -import utils from "../utils"; -import { assertNodeType, checkSymbolNodeType } from "../parseNode"; - -import * as mml from "../buildMathML"; - -// Extra data needed for the delimiter handler down below -export const delimiterSizes = { - "\\bigl": { mclass: "mopen", size: 1 }, - "\\Bigl": { mclass: "mopen", size: 2 }, - "\\biggl": { mclass: "mopen", size: 3 }, - "\\Biggl": { mclass: "mopen", size: 4 }, - "\\bigr": { mclass: "mclose", size: 1 }, - "\\Bigr": { mclass: "mclose", size: 2 }, - "\\biggr": { mclass: "mclose", size: 3 }, - "\\Biggr": { mclass: "mclose", size: 4 }, - "\\bigm": { mclass: "mrel", size: 1 }, - "\\Bigm": { mclass: "mrel", size: 2 }, - "\\biggm": { mclass: "mrel", size: 3 }, - "\\Biggm": { mclass: "mrel", size: 4 }, - "\\big": { mclass: "mord", size: 1 }, - "\\Big": { mclass: "mord", size: 2 }, - "\\bigg": { mclass: "mord", size: 3 }, - "\\Bigg": { mclass: "mord", size: 4 } -}; - -export const delimiters = [ - "(", - "\\lparen", - ")", - "\\rparen", - "[", - "\\lbrack", - "]", - "\\rbrack", - "\\{", - "\\lbrace", - "\\}", - "\\rbrace", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lt", - "\\gt", - "\\lvert", - "\\rvert", - "\\lVert", - "\\rVert", - "\\lgroup", - "\\rgroup", - "\u27ee", - "\u27ef", - "\\lmoustache", - "\\rmoustache", - "\u23b0", - "\u23b1", - "\\llbracket", - "\\rrbracket", - "\u27e6", - "\u27e6", - "\\lBrace", - "\\rBrace", - "\u2983", - "\u2984", - "/", - "\\backslash", - "|", - "\\vert", - "\\|", - "\\Vert", - "\\uparrow", - "\\Uparrow", - "\\downarrow", - "\\Downarrow", - "\\updownarrow", - "\\Updownarrow", - "." -]; - -// Metrics of the different sizes. Found by looking at TeX's output of -// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ -// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. -const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; - -// Delimiter functions -function checkDelimiter(delim, context) { - if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") { - // Recover "/" from the zero spacing group. (See macros.js) - delim = { type: "textord", text: "/", mode: "math" } - } - const symDelim = checkSymbolNodeType(delim) - if (symDelim && utils.contains(delimiters, symDelim.text)) { - // If a character is not in the MathML operator dictionary, it will not stretch. - // Replace such characters w/characters that will stretch. - if (utils.contains(["<", "\\lt"], symDelim.text)) { symDelim.text = "⟨" } - if (utils.contains([">", "\\gt"], symDelim.text)) { symDelim.text = "⟩" } - if (symDelim.text === "/") { symDelim.text = "\u2215" } - if (symDelim.text === "\\backslash") { symDelim.text = "\u2216" } - return symDelim; - } else if (symDelim) { - throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim); - } else { - throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim); - } -} - -defineFunction({ - type: "delimsizing", - names: [ - "\\bigl", - "\\Bigl", - "\\biggl", - "\\Biggl", - "\\bigr", - "\\Bigr", - "\\biggr", - "\\Biggr", - "\\bigm", - "\\Bigm", - "\\biggm", - "\\Biggm", - "\\big", - "\\Big", - "\\bigg", - "\\Bigg" - ], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - return { - type: "delimsizing", - mode: context.parser.mode, - size: delimiterSizes[context.funcName].size, - mclass: delimiterSizes[context.funcName].mclass, - delim: delim.text - }; - }, - mathmlBuilder: (group) => { - const children = []; - - if (group.delim === ".") { group.delim = "" } - children.push(mml.makeText(group.delim, group.mode)); - - const node = new mathMLTree.MathNode("mo", children); - - if (group.mclass === "mopen" || group.mclass === "mclose") { - // Only some of the delimsizing functions act as fences, and they - // return "mopen" or "mclose" mclass. - node.setAttribute("fence", "true"); - } else { - // Explicitly disable fencing if it's not a fence, to override the - // defaults. - node.setAttribute("fence", "false"); - } - if (group.delim === "\u2216") { - // \backslash is not in the operator dictionary, - // so we have to explicitly set stretchy to true. - node.setAttribute("stretchy", "true") - } - - node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox. - node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em"); - node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em"); - - return node; - } -}); - -function assertParsed(group) { - if (!group.body) { - throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); - } -} - -defineFunction({ - type: "leftright-right", - names: ["\\right"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - // \left case below triggers parsing of \right in - // `const right = parser.parseFunction();` - // uses this return value. - const color = context.parser.gullet.macros.get("\\current@color"); - if (color && typeof color !== "string") { - throw new ParseError("\\current@color set to non-string in \\right"); - } - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text, - color // undefined if not set via \color - }; - } -}); - -defineFunction({ - type: "leftright", - names: ["\\left"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - const parser = context.parser; - // Parse out the implicit body - ++parser.leftrightDepth; - // parseExpression stops before '\\right' - const body = parser.parseExpression(false); - --parser.leftrightDepth; - // Check the next token - parser.expect("\\right", false); - const right = assertNodeType(parser.parseFunction(), "leftright-right"); - return { - type: "leftright", - mode: parser.mode, - body, - left: delim.text, - right: right.delim, - rightColor: right.color - }; - }, - mathmlBuilder: (group, style) => { - assertParsed(group); - const inner = mml.buildExpression(group.body, style); - - if (group.left === ".") { group.left = "" } - const leftNode = new mathMLTree.MathNode("mo", [mml.makeText(group.left, group.mode)]); - leftNode.setAttribute("fence", "true") - leftNode.setAttribute("form", "prefix") - if (group.left === "\u2216") { leftNode.setAttribute("stretchy", "true") } - inner.unshift(leftNode) - - if (group.right === ".") { group.right = "" } - const rightNode = new mathMLTree.MathNode("mo", [mml.makeText(group.right, group.mode)]); - rightNode.setAttribute("fence", "true") - rightNode.setAttribute("form", "postfix") - if (group.right === "\u2216") { rightNode.setAttribute("stretchy", "true") } - if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor) } - inner.push(rightNode) - - return mml.makeRow(inner); - } -}); - -defineFunction({ - type: "middle", - names: ["\\middle"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - if (!context.parser.leftrightDepth) { - throw new ParseError("\\middle without preceding \\left", delim); - } - - return { - type: "middle", - mode: context.parser.mode, - delim: delim.text - }; - }, - mathmlBuilder: (group, style) => { - const textNode = mml.makeText(group.delim, group.mode); - const middleNode = new mathMLTree.MathNode("mo", [textNode]); - middleNode.setAttribute("fence", "true"); - // MathML gives 5/18em spacing to each element. - // \middle should get delimiter spacing instead. - middleNode.setAttribute("lspace", "0.05em"); - middleNode.setAttribute("rspace", "0.05em"); - return middleNode; - } -}); diff --git a/src/functions/enclose.js b/src/functions/enclose.js deleted file mode 100644 index 8816f951..00000000 --- a/src/functions/enclose.js +++ /dev/null @@ -1,158 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import { assertNodeType } from "../parseNode"; -import { colorFromSpec, validateColor } from "./color" -import * as mml from "../buildMathML"; - -const mathmlBuilder = (group, style) => { - const node = new mathMLTree.MathNode( - group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", - [mml.buildGroup(group.body, style)] - ); - switch (group.label) { - case "\\cancel": - node.setAttribute("notation", "updiagonalstrike"); - break; - case "\\bcancel": - node.setAttribute("notation", "downdiagonalstrike"); - break; - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break; - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break; - case "\\sout": - node.setAttribute("notation", "horizontalstrike"); - break; - case "\\fbox": - node.setAttribute("notation", "box"); - break; - case "\\angl": - node.setAttribute("notation", "actuarial"); - break; - case "\\fcolorbox": - case "\\colorbox": { - // doesn't have a good notation option for \colorbox. - // So use instead. Set some attributes that come - // included with . - const fboxsep = 3; // 3 pt from LaTeX source2e - node.setAttribute("width", `+${2 * fboxsep}pt`); - node.setAttribute("height", `+${2 * fboxsep}pt`); - node.setAttribute("lspace", `${fboxsep}pt`); // - node.setAttribute("voffset", `${fboxsep}pt`); - if (group.label === "\\fcolorbox") { - node.setAttribute("style", "border: 0.06em solid " + String(group.borderColor)); - } - break; - } - case "\\xcancel": - node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); - break; - } - if (group.backgroundColor) { - node.setAttribute("mathbackground", group.backgroundColor); - } - return node; -}; - -defineFunction({ - type: "enclose", - names: ["\\colorbox"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string - let color = "" - if (model) { - const spec = assertNodeType(args[0], "raw").string - color = colorFromSpec(model, spec) - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros) - } - const body = args[1]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor: color, - body - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "enclose", - names: ["\\fcolorbox"], - props: { - numArgs: 3, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string - let borderColor = "" - let backgroundColor - if (model) { - const borderSpec = assertNodeType(args[0], "raw").string - const backgroundSpec = assertNodeType(args[0], "raw").string - borderColor = colorFromSpec(model, borderSpec) - backgroundColor = colorFromSpec(model, backgroundSpec) - } else { - borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros) - backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros) - } - const body = args[2]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor, - borderColor, - body - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "enclose", - names: ["\\fbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "enclose", - mode: parser.mode, - label: "\\fbox", - body: args[0] - }; - } -}); - -defineFunction({ - type: "enclose", - names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\angl", "\\phase", "\\longdiv"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - body - }; - }, - mathmlBuilder -}); diff --git a/src/functions/envTag.js b/src/functions/envTag.js deleted file mode 100644 index 6a035ad0..00000000 --- a/src/functions/envTag.js +++ /dev/null @@ -1,38 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; - -defineFunction({ - type: "envTag", - names: ["\\env@tag"], - props: { - numArgs: 1, - argTypes: ["math"] - }, - handler({ parser }, args) { - return { - type: "envTag", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -defineFunction({ - type: "noTag", - names: ["\\env@notag"], - props: { - numArgs: 0 - }, - handler({ parser }) { - return { - type: "noTag", - mode: parser.mode - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); diff --git a/src/functions/environment.js b/src/functions/environment.js deleted file mode 100644 index ced5acd0..00000000 --- a/src/functions/environment.js +++ /dev/null @@ -1,59 +0,0 @@ -import defineFunction from "../defineFunction"; -import ParseError from "../ParseError"; -import { assertNodeType } from "../parseNode"; -import environments from "../environments"; - -// Environment delimiters. HTML/MathML rendering is defined in the corresponding -// defineEnvironment definitions. -defineFunction({ - type: "environment", - names: ["\\begin", "\\end"], - props: { - numArgs: 1, - argTypes: ["text"] - }, - handler({ parser, funcName }, args) { - const nameGroup = args[0]; - if (nameGroup.type !== "ordgroup") { - throw new ParseError("Invalid environment name", nameGroup); - } - let envName = ""; - for (let i = 0; i < nameGroup.body.length; ++i) { - envName += assertNodeType(nameGroup.body[i], "textord").text; - } - - if (funcName === "\\begin") { - // begin...end is similar to left...right - if (!Object.prototype.hasOwnProperty.call(environments, envName )) { - throw new ParseError("No such environment: " + envName, nameGroup); - } - // Build the environment object. Arguments and other information will - // be made available to the begin and end methods using properties. - const env = environments[envName]; - const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env); - const context = { - mode: parser.mode, - envName, - parser - }; - const result = env.handler(context, args, optArgs); - parser.expect("\\end", false); - const endNameToken = parser.nextToken; - const end = assertNodeType(parser.parseFunction(), "environment"); - if (end.name !== envName) { - throw new ParseError( - `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, - endNameToken - ); - } - return result; - } - - return { - type: "environment", - mode: parser.mode, - name: envName, - nameGroup - }; - } -}); diff --git a/src/functions/font.js b/src/functions/font.js deleted file mode 100644 index bd984261..00000000 --- a/src/functions/font.js +++ /dev/null @@ -1,123 +0,0 @@ -import defineFunction, { normalizeArgument } from "../defineFunction" -import * as mml from "../buildMathML" -import mathMLTree from "../mathMLTree" - -const mathmlBuilder = (group, style) => { - const font = group.font - const newStyle = style.withFont(font) - const mathGroup = mml.buildGroup(group.body, newStyle) - - if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{} - if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold" - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - let canConsolidate = mathGroup.children[0].type === "mo" - for (let i = 1; i < mathGroup.children.length; i++) { - if (mathGroup.children[i].type === "mo" && font === "boldsymbol") { - mathGroup.children[i].style.fontWeight = "bold" - } - if (mathGroup.children[i].type !== "mi") { canConsolidate = false } - const localVariant = mathGroup.children[i].attributes && - mathGroup.children[i].attributes.mathvariant || "" - if (localVariant !== "normal") { canConsolidate = false } - } - if (!canConsolidate) { return mathGroup } - // Consolidate the elements. - const mi = mathGroup.children[0] - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children.push(mathGroup.children[i].children[0]) - } - if (mathGroup.attributes.mathcolor) { mi.attributes.mathcolor = mathGroup.attributes.mathcolor } - if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") { - // Workaround for a Firefox bug that renders spurious space around - // a - // Ref: https://bugs.webkit.org/show_bug.cgi?id=129097 - // We insert a text node that contains a zero-width space and wrap in an mrow. - // TODO: Get rid of this workaround when the Firefox bug is fixed. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")) - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - return mi -}; - -const fontAliases = { - "\\Bbb": "\\mathbb", - "\\bold": "\\mathbf", - "\\frak": "\\mathfrak", - "\\bm": "\\boldsymbol" -}; - -defineFunction({ - type: "font", - names: [ - // styles - "\\mathrm", - "\\mathit", - "\\mathbf", - "\\mathnormal", - "\\up@greek", - "\\boldsymbol", - - // families - "\\mathbb", - "\\mathcal", - "\\mathfrak", - "\\mathscr", - "\\mathsf", - "\\mathtt", - "\\oldstylenums", - - // aliases - "\\Bbb", - "\\bm", - "\\bold", - "\\frak" - ], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = normalizeArgument(args[0]); - let func = funcName; - if (func in fontAliases) { - func = fontAliases[func]; - } - return { - type: "font", - mode: parser.mode, - font: func.slice(1), - body - }; - }, - mathmlBuilder -}); - -// Old font changing functions -defineFunction({ - type: "font", - names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ parser, funcName, breakOnTokenText }, args) => { - const { mode } = parser; - const body = parser.parseExpression(true, breakOnTokenText); - const fontStyle = `math${funcName.slice(1)}`; - - return { - type: "font", - mode: mode, - font: fontStyle, - body: { - type: "ordgroup", - mode: parser.mode, - body - } - }; - }, - mathmlBuilder -}); diff --git a/src/functions/genfrac.js b/src/functions/genfrac.js deleted file mode 100644 index 37dd41d3..00000000 --- a/src/functions/genfrac.js +++ /dev/null @@ -1,333 +0,0 @@ -import defineFunction, { normalizeArgument } from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import { StyleLevel } from "../constants" -import { assertNodeType } from "../parseNode"; -import { assert } from "../utils"; -import * as mml from "../buildMathML"; -import { calculateSize } from "../units"; - -const stylArray = ["display", "text", "script", "scriptscript"]; -const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 }; - -const mathmlBuilder = (group, style) => { - // Track the scriptLevel of the numerator and denominator. - // We may need that info for \mathchoice or for adjusting em dimensions. - const childOptions = group.scriptLevel === "auto" - ? style.incrementLevel() - : group.scriptLevel === "display" - ? style.withLevel(StyleLevel.TEXT) - : group.scriptLevel === "text" - ? style.withLevel(StyleLevel.SCRIPT) - : style.withLevel(StyleLevel.SCRIPTSCRIPT); - - let node = new mathMLTree.MathNode("mfrac", [ - mml.buildGroup(group.numer, childOptions), - mml.buildGroup(group.denom, childOptions) - ]); - - if (!group.hasBarLine) { - node.setAttribute("linethickness", "0px"); - } else if (group.barSize) { - const ruleWidth = calculateSize(group.barSize, style); - node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit); - } - - if (group.leftDelim != null || group.rightDelim != null) { - const withDelims = []; - - if (group.leftDelim != null) { - const leftOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.leftDelim.replace("\\", "")) - ]); - leftOp.setAttribute("fence", "true"); - withDelims.push(leftOp); - } - - withDelims.push(node); - - if (group.rightDelim != null) { - const rightOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.rightDelim.replace("\\", "")) - ]); - rightOp.setAttribute("fence", "true"); - withDelims.push(rightOp); - } - - node = mml.makeRow(withDelims); - } - - if (group.scriptLevel !== "auto") { - node = new mathMLTree.MathNode("mstyle", [node]); - node.setAttribute("displaystyle", String(group.scriptLevel === "display")); - node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]); - } - - return node; -}; - -defineFunction({ - type: "genfrac", - names: [ - "\\dfrac", - "\\frac", - "\\tfrac", - "\\dbinom", - "\\binom", - "\\tbinom", - "\\\\atopfrac", // can’t be entered directly - "\\\\bracefrac", - "\\\\brackfrac" // ditto - ], - props: { - numArgs: 2, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - let hasBarLine = false; - let leftDelim = null; - let rightDelim = null; - let scriptLevel = "auto"; - - switch (funcName) { - case "\\dfrac": - case "\\frac": - case "\\tfrac": - hasBarLine = true; - break; - case "\\\\atopfrac": - hasBarLine = false; - break; - case "\\dbinom": - case "\\binom": - case "\\tbinom": - leftDelim = "("; - rightDelim = ")"; - break; - case "\\\\bracefrac": - leftDelim = "\\{"; - rightDelim = "\\}"; - break; - case "\\\\brackfrac": - leftDelim = "["; - rightDelim = "]"; - break; - default: - throw new Error("Unrecognized genfrac command"); - } - - switch (funcName) { - case "\\dfrac": - case "\\dbinom": - scriptLevel = "display"; - break; - case "\\tfrac": - case "\\tbinom": - scriptLevel = "text"; - break; - } - - return { - type: "genfrac", - mode: parser.mode, - continued: false, - numer, - denom, - hasBarLine, - leftDelim, - rightDelim, - scriptLevel, - barSize: null - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "genfrac", - names: ["\\cfrac"], - props: { - numArgs: 2 - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - - return { - type: "genfrac", - mode: parser.mode, - continued: true, - numer, - denom, - hasBarLine: true, - leftDelim: null, - rightDelim: null, - scriptLevel: "display", - barSize: null - }; - } -}); - -// Infix generalized fractions -- these are not rendered directly, but replaced -// immediately by one of the variants above. -defineFunction({ - type: "infix", - names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], - props: { - numArgs: 0, - infix: true - }, - handler({ parser, funcName, token }) { - let replaceWith; - switch (funcName) { - case "\\over": - replaceWith = "\\frac"; - break; - case "\\choose": - replaceWith = "\\binom"; - break; - case "\\atop": - replaceWith = "\\\\atopfrac"; - break; - case "\\brace": - replaceWith = "\\\\bracefrac"; - break; - case "\\brack": - replaceWith = "\\\\brackfrac"; - break; - default: - throw new Error("Unrecognized infix genfrac command"); - } - return { - type: "infix", - mode: parser.mode, - replaceWith, - token - }; - } -}); - -const delimFromValue = function(delimString) { - let delim = null; - if (delimString.length > 0) { - delim = delimString; - delim = delim === "." ? null : delim; - } - return delim; -}; - -defineFunction({ - type: "genfrac", - names: ["\\genfrac"], - props: { - numArgs: 6, - allowedInArgument: true, - argTypes: ["math", "math", "size", "text", "math", "math"] - }, - handler({ parser }, args) { - const numer = args[4]; - const denom = args[5]; - - // Look into the parse nodes to get the desired delimiters. - const leftNode = normalizeArgument(args[0]); - const leftDelim = leftNode.type === "atom" && leftNode.family === "open" - ? delimFromValue(leftNode.text) - : null; - const rightNode = normalizeArgument(args[1]); - const rightDelim = - rightNode.type === "atom" && rightNode.family === "close" - ? delimFromValue(rightNode.text) - : null; - - const barNode = assertNodeType(args[2], "size"); - let hasBarLine; - let barSize = null; - if (barNode.isBlank) { - // \genfrac acts differently than \above. - // \genfrac treats an empty size group as a signal to use a - // standard bar size. \above would see size = 0 and omit the bar. - hasBarLine = true; - } else { - barSize = barNode.value; - hasBarLine = barSize.number > 0; - } - - // Find out if we want displaystyle, textstyle, etc. - let scriptLevel = "auto"; - let styl = args[3]; - if (styl.type === "ordgroup") { - if (styl.body.length > 0) { - const textOrd = assertNodeType(styl.body[0], "textord"); - scriptLevel = stylArray[Number(textOrd.text)]; - } - } else { - styl = assertNodeType(styl, "textord"); - scriptLevel = stylArray[Number(styl.text)]; - } - - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim, - rightDelim, - scriptLevel - }; - }, - mathmlBuilder -}); - -// \above is an infix fraction that also defines a fraction bar size. -defineFunction({ - type: "infix", - names: ["\\above"], - props: { - numArgs: 1, - argTypes: ["size"], - infix: true - }, - handler({ parser, funcName, token }, args) { - return { - type: "infix", - mode: parser.mode, - replaceWith: "\\\\abovefrac", - barSize: assertNodeType(args[0], "size").value, - token - }; - } -}); - -defineFunction({ - type: "genfrac", - names: ["\\\\abovefrac"], - props: { - numArgs: 3, - argTypes: ["math", "size", "math"] - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const barSize = assert(assertNodeType(args[1], "infix").barSize); - const denom = args[2]; - - const hasBarLine = barSize.number > 0; - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim: null, - rightDelim: null, - scriptLevel: "auto" - }; - }, - - mathmlBuilder -}); diff --git a/src/functions/hbox.js b/src/functions/hbox.js deleted file mode 100644 index e871d38b..00000000 --- a/src/functions/hbox.js +++ /dev/null @@ -1,29 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import { StyleLevel } from "../constants" -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -// \hbox is provided for compatibility with LaTeX functions that act on a box. -// This function by itself doesn't do anything but prevent a soft line break. - -defineFunction({ - type: "hbox", - names: ["\\hbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInArgument: true, - allowedInText: false - }, - handler({ parser }, args) { - return { - type: "hbox", - mode: parser.mode, - body: ordargument(args[0]) - }; - }, - mathmlBuilder(group, style) { - const newOptions = style.withLevel(StyleLevel.TEXT) - return new mathMLTree.MathNode("mrow", mml.buildExpression(group.body, newOptions)); - } -}); diff --git a/src/functions/horizBrace.js b/src/functions/horizBrace.js deleted file mode 100644 index 554021cb..00000000 --- a/src/functions/horizBrace.js +++ /dev/null @@ -1,31 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import stretchy from "../stretchy"; -import * as mml from "../buildMathML"; - -const mathmlBuilder = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [ - mml.buildGroup(group.base, style), - accentNode - ]); -}; - -// Horizontal stretchy braces -defineFunction({ - type: "horizBrace", - names: ["\\overbrace", "\\underbrace"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "horizBrace", - mode: parser.mode, - label: funcName, - isOver: /^\\over/.test(funcName), - base: args[0] - }; - }, - mathmlBuilder -}); diff --git a/src/functions/href.js b/src/functions/href.js deleted file mode 100644 index 7c35d50c..00000000 --- a/src/functions/href.js +++ /dev/null @@ -1,90 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import { assertNodeType } from "../parseNode"; -import { MathNode } from "../mathMLTree"; -import * as mml from "../buildMathML"; -import ParseError from "../ParseError"; - -defineFunction({ - type: "href", - names: ["\\href"], - props: { - numArgs: 2, - argTypes: ["url", "original"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const body = args[1]; - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\href", - url: href - }) - ) { - throw new ParseError(`Function "\\href" is not trusted`, token) - } - - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - let math = mml.buildExpressionRow(group.body, style); - if (!(math instanceof MathNode)) { - math = new MathNode("mrow", [math]); - } - math.setAttribute("href", group.href); - return math; - } -}); - -defineFunction({ - type: "href", - names: ["\\url"], - props: { - numArgs: 1, - argTypes: ["url"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\url", - url: href - }) - ) { - throw new ParseError(`Function "\\url" is not trusted`, token) - } - - const chars = []; - for (let i = 0; i < href.length; i++) { - let c = href[i]; - if (c === "~") { - c = "\\textasciitilde"; - } - chars.push({ - type: "textord", - mode: "text", - text: c - }); - } - const body = { - type: "text", - mode: parser.mode, - font: "\\texttt", - body: chars - }; - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - } -}); diff --git a/src/functions/html.js b/src/functions/html.js deleted file mode 100644 index 4b4124ba..00000000 --- a/src/functions/html.js +++ /dev/null @@ -1,95 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import { assertNodeType } from "../parseNode"; -import ParseError from "../ParseError"; - -import * as mml from "../buildMathML"; - -defineFunction({ - type: "html", - names: ["\\class", "\\id", "\\style", "\\data"], - props: { - numArgs: 2, - argTypes: ["raw", "original"], - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - const value = assertNodeType(args[0], "raw").string; - const body = args[1]; - - if (parser.settings.strict) { - throw new ParseError(`Function "${funcName}" is disabled in strict mode`, token) - } - - let trustContext; - const attributes = {}; - - switch (funcName) { - case "\\class": - attributes.class = value; - trustContext = { - command: "\\class", - class: value - }; - break; - case "\\id": - attributes.id = value; - trustContext = { - command: "\\id", - id: value - }; - break; - case "\\style": - attributes.style = value; - trustContext = { - command: "\\style", - style: value - }; - break; - case "\\data": { - const data = value.split(","); - for (let i = 0; i < data.length; i++) { - const keyVal = data[i].split("="); - if (keyVal.length !== 2) { - throw new ParseError("Error parsing key-value for \\data"); - } - attributes["data-" + keyVal[0].trim()] = keyVal[1].trim(); - } - - trustContext = { - command: "\\data", - attributes - }; - break; - } - default: - throw new Error("Unrecognized html command"); - } - - if (!parser.settings.isTrusted(trustContext)) { - throw new ParseError(`Function "${funcName}" is not trusted`, token) - } - return { - type: "html", - mode: parser.mode, - attributes, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const element = mml.buildExpressionRow(group.body, style); - - const classes = []; - if (group.attributes.class) { - classes.push(...group.attributes.class.trim().split(/\s+/)); - } - element.classes = classes; - - for (const attr in group.attributes) { - if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) { - element.setAttribute(attr, group.attributes[attr]); - } - } - - return element; - } -}); diff --git a/src/functions/includegraphics.js b/src/functions/includegraphics.js deleted file mode 100644 index 574b53e1..00000000 --- a/src/functions/includegraphics.js +++ /dev/null @@ -1,131 +0,0 @@ -import defineFunction from "../defineFunction" -import { calculateSize, validUnit } from "../units" -import ParseError from "../ParseError" -import { Img } from "../domTree" -import mathMLTree from "../mathMLTree" -import { assertNodeType } from "../parseNode" - -const sizeData = function(str) { - if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { - // str is a number with no unit specified. - // default unit is bp, per graphix package. - return { number: +str, unit: "bp" } - } else { - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); - if (!match) { - throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - } - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); - } - return data - } -} - -defineFunction({ - type: "includegraphics", - names: ["\\includegraphics"], - props: { - numArgs: 1, - numOptionalArgs: 1, - argTypes: ["raw", "url"], - allowedInText: false - }, - handler: ({ parser, token }, args, optArgs) => { - let width = { number: 0, unit: "em" } - let height = { number: 0.9, unit: "em" } // sorta character sized. - let totalheight = { number: 0, unit: "em" } - let alt = "" - - if (optArgs[0]) { - const attributeStr = assertNodeType(optArgs[0], "raw").string - - // Parser.js does not parse key/value pairs. We get a string. - const attributes = attributeStr.split(",") - for (let i = 0; i < attributes.length; i++) { - const keyVal = attributes[i].split("=") - if (keyVal.length === 2) { - const str = keyVal[1].trim() - switch (keyVal[0].trim()) { - case "alt": - alt = str - break - case "width": - width = sizeData(str) - break - case "height": - height = sizeData(str) - break - case "totalheight": - totalheight = sizeData(str) - break - default: - throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics.") - } - } - } - } - - const src = assertNodeType(args[0], "url").url - - if (alt === "") { - // No alt given. Use the file name. Strip away the path. - alt = src - alt = alt.replace(/^.*[\\/]/, "") - alt = alt.substring(0, alt.lastIndexOf(".")) - } - - if ( - !parser.settings.isTrusted({ - command: "\\includegraphics", - url: src - }) - ) { - throw new ParseError(`Function "\\includegraphics" is not trusted`, token) - } - - return { - type: "includegraphics", - mode: parser.mode, - alt: alt, - width: width, - height: height, - totalheight: totalheight, - src: src - } - }, - mathmlBuilder: (group, style) => { - const height = calculateSize(group.height, style) - const depth = { number: 0, unit: "em" } - - if (group.totalheight.number > 0) { - if (group.totalheight.unit === height.unit && - group.totalheight.number > height.number) { - depth.number = group.totalheight.number - height.number - depth.unit = height.unit - } - } - - let width = 0 - if (group.width.number > 0) { - width = calculateSize(group.width, style) - } - - const graphicStyle = { height: height.number + depth.number + "em" } - if (width.number > 0) { - graphicStyle.width = width.number + width.unit - } - if (depth.number > 0) { - graphicStyle.verticalAlign = -depth.number + depth.unit - } - - const node = new Img(group.src, group.alt, graphicStyle) - node.height = height - node.depth = depth - return new mathMLTree.MathNode("mtext", [node]) - } -}) diff --git a/src/functions/kern.js b/src/functions/kern.js deleted file mode 100644 index f67075f5..00000000 --- a/src/functions/kern.js +++ /dev/null @@ -1,72 +0,0 @@ -// Horizontal spacing commands - -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import { calculateSize } from "../units"; -import { assertNodeType } from "../parseNode"; -import ParseError from "../ParseError" - -// TODO: \hskip and \mskip should support plus and minus in lengths - -defineFunction({ - type: "kern", - names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], - props: { - numArgs: 1, - argTypes: ["size"], - primitive: true, - allowedInText: true - }, - handler({ parser, funcName, token }, args) { - const size = assertNodeType(args[0], "size"); - if (parser.settings.strict) { - const mathFunction = funcName[1] === "m"; // \mkern, \mskip - const muUnit = size.value.unit === "mu"; - if (mathFunction) { - if (!muUnit) { - throw new ParseError(`LaTeX's ${funcName} supports only mu units, ` + - `not ${size.value.unit} units`, token) - } - if (parser.mode !== "math") { - throw new ParseError(`LaTeX's ${funcName} works only in math mode`, token) - } - } else { - // !mathFunction - if (muUnit) { - throw new ParseError(`LaTeX's ${funcName} doesn't support mu units`, token) - } - } - } - return { - type: "kern", - mode: parser.mode, - dimension: size.value - }; - }, - mathmlBuilder(group, style) { - const dimension = calculateSize(group.dimension, style); - const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : ""; - if (group.mode === "text" && ch.length > 0) { - const character = new mathMLTree.TextNode(ch); - return new mathMLTree.MathNode("mtext", [character]); - } else { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", dimension.number + dimension.unit); - return node; - } - } -}); - -export const spaceCharacter = function(width) { - if (width >= 0.05555 && width <= 0.05556) { - return "\u200a"; //   - } else if (width >= 0.1666 && width <= 0.1667) { - return "\u2009"; //   - } else if (width >= 0.2222 && width <= 0.2223) { - return "\u2005"; //   - } else if (width >= 0.2777 && width <= 0.2778) { - return "\u2005\u200a"; //    - } else { - return ""; - } -}; diff --git a/src/functions/label.js b/src/functions/label.js deleted file mode 100644 index 458cabee..00000000 --- a/src/functions/label.js +++ /dev/null @@ -1,29 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; - -// Limit valid characters to a small set, for safety. -export const invalidIdRegEx = /[^A-Za-z_0-9-]/g - -defineFunction({ - type: "label", - names: ["\\label"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser }, args) { - return { - type: "label", - mode: parser.mode, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Return a no-width, no-ink element with an HTML id. - const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]) - if (group.string.length > 0) { - node.setAttribute("id", group.string) - } - return node - } -}); diff --git a/src/functions/lap.js b/src/functions/lap.js deleted file mode 100644 index db0133d9..00000000 --- a/src/functions/lap.js +++ /dev/null @@ -1,50 +0,0 @@ -// Horizontal overlap functions -import defineFunction from "../defineFunction" -import mathMLTree from "../mathMLTree" -import * as mml from "../buildMathML" -import ParseError from "../ParseError"; - -const textModeLap = ["\\clap", "\\llap", "\\rlap"] - -defineFunction({ - type: "lap", - names: ["\\mathllap", "\\mathrlap", "\\mathclap", "\\clap", "\\llap", "\\rlap"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - if (textModeLap.includes(funcName)) { - if (parser.settings.strict && parser.mode !== "text") { - throw new ParseError(`{${funcName}} can be used only in text mode. - Try \\math${funcName.slice(1)}`, token) - } - funcName = funcName.slice(1) - } else { - funcName = funcName.slice(5) - } - const body = args[0] - return { - type: "lap", - mode: parser.mode, - alignment: funcName, - body - } - }, - mathmlBuilder: (group, style) => { - // mathllap, mathrlap, mathclap - const node = new mathMLTree.MathNode("mpadded", [mml.buildGroup(group.body, style)]) - - if (group.alignment === "rlap") { - if (group.body.body.length > 0 && group.body.body[0].type === "genfrac") { - // In Firefox, a squashes the 3/18em padding of a child \frac. Put it back. - node.setAttribute("lspace", "0.16667em") - } - } else { - const offset = group.alignment === "llap" ? "-1" : "-0.5" - node.setAttribute("lspace", offset + "width") - } - node.setAttribute("width", "0px") - return node - } -}) diff --git a/src/functions/math.js b/src/functions/math.js deleted file mode 100644 index 0f036018..00000000 --- a/src/functions/math.js +++ /dev/null @@ -1,40 +0,0 @@ -import defineFunction from "../defineFunction"; -import ParseError from "../ParseError"; - -// Switching from text mode back to math mode -defineFunction({ - type: "ordgroup", - names: ["\\(", "$"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler({ funcName, parser }, args) { - const outerMode = parser.mode; - parser.switchMode("math"); - const close = funcName === "\\(" ? "\\)" : "$"; - const body = parser.parseExpression(false, close); - parser.expect(close); - parser.switchMode(outerMode); - return { - type: "ordgroup", - mode: parser.mode, - body - }; - } -}); - -// Check for extra closing math delimiters -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\)", "\\]"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler(context, token) { - throw new ParseError(`Mismatched ${context.funcName}`, token); - } -}); diff --git a/src/functions/mathchoice.js b/src/functions/mathchoice.js deleted file mode 100644 index 1bb2390b..00000000 --- a/src/functions/mathchoice.js +++ /dev/null @@ -1,41 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import { StyleLevel } from "../constants"; -import * as mml from "../buildMathML"; - -const chooseStyle = (group, style) => { - switch (style.level) { - case StyleLevel.DISPLAY: // 0 - return group.display; - case StyleLevel.TEXT: // 1 - return group.text; - case StyleLevel.SCRIPT: // 2 - return group.script; - case StyleLevel.SCRIPTSCRIPT: // 3 - return group.scriptscript; - default: - return group.text; - } -}; - -defineFunction({ - type: "mathchoice", - names: ["\\mathchoice"], - props: { - numArgs: 4, - primitive: true - }, - handler: ({ parser }, args) => { - return { - type: "mathchoice", - mode: parser.mode, - display: ordargument(args[0]), - text: ordargument(args[1]), - script: ordargument(args[2]), - scriptscript: ordargument(args[3]) - }; - }, - mathmlBuilder: (group, style) => { - const body = chooseStyle(group, style); - return mml.buildExpressionRow(body, style); - } -}); diff --git a/src/functions/mclass.js b/src/functions/mclass.js deleted file mode 100644 index 5ff0dc36..00000000 --- a/src/functions/mclass.js +++ /dev/null @@ -1,174 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import utils from "../utils"; - -import * as mml from "../buildMathML"; - -const textAtomTypes = ["text", "textord", "mathord", "atom"] - -function mathmlBuilder(group, style) { - let node; - const inner = mml.buildExpression(group.body, style); - - if (group.mclass === "minner") { - node = new mathMLTree.MathNode("mpadded", inner) - } else if (group.mclass === "mord") { - if (group.isCharacterBox || inner[0].type === "mathord") { - node = inner[0]; - node.type = "mi"; - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - if (group.mustPromote) { - node = inner[0]; - node.type = "mo"; - if (group.isCharacterBox && group.body[0].text && /[A-Za-z]/.test(group.body[0].text)) { - node.setAttribute("mathvariant", "italic") - } - } else { - node = new mathMLTree.MathNode("mo", inner); - } - - // Set spacing based on what is the most likely adjacent atom type. - // See TeXbook p170. - const doSpacing = style.level < 2 // Operator spacing is zero inside a (sub|super)script. - if (group.mclass === "mbin") { - // medium space - node.attributes.lspace = (doSpacing ? "0.2222em" : "0") - node.attributes.rspace = (doSpacing ? "0.2222em" : "0") - } else if (group.mclass === "mrel") { - // thickspace - node.attributes.lspace = (doSpacing ? "0.2778em" : "0") - node.attributes.rspace = (doSpacing ? "0.2778em" : "0") - } else if (group.mclass === "mpunct") { - node.attributes.lspace = "0em"; - node.attributes.rspace = (doSpacing ? "0.1667em" : "0") - } else if (group.mclass === "mopen" || group.mclass === "mclose") { - node.attributes.lspace = "0em" - node.attributes.rspace = "0em" - } else if (group.mclass === "minner" && doSpacing) { - node.attributes.lspace = "0.0556em" // 1 mu is the most likely option - node.attributes.width = "+0.1111em" - } - if (!(group.mclass === "mopen" || group.mclass === "mclose")) { - delete node.attributes.stretchy - delete node.attributes.form - } - } - return node; -} - -// Math class commands except \mathop -defineFunction({ - type: "mclass", - names: [ - "\\mathord", - "\\mathbin", - "\\mathrel", - "\\mathopen", - "\\mathclose", - "\\mathpunct", - "\\mathinner" - ], - props: { - numArgs: 1, - primitive: true - }, - handler({ parser, funcName }, args) { - const body = args[0] - const isCharacterBox = utils.isCharacterBox(body) - // We should not wrap a around a or . That would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - let mustPromote = true - const mord = { type: "mathord", text: "", mode: parser.mode } - const arr = (body.body) ? body.body : [body]; - for (const arg of arr) { - if (textAtomTypes.includes(arg.type)) { - if (arg.text) { - mord.text += arg.text - } else if (arg.body) { - arg.body.map(e => { mord.text += e.text }) - } - } else { - mustPromote = false - break - } - } - return { - type: "mclass", - mode: parser.mode, - mclass: "m" + funcName.slice(5), - body: ordargument(mustPromote ? mord : body), - isCharacterBox, - mustPromote - }; - }, - mathmlBuilder -}); - -export const binrelClass = (arg) => { - // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. - // (by rendering separately and with {}s before and after, and measuring - // the change in spacing). We'll do roughly the same by detecting the - // atom type directly. - const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; - if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { - return "m" + atom.family; - } else { - return "mord"; - } -}; - -// \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. -// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. -defineFunction({ - type: "mclass", - names: ["\\@binrel"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "mclass", - mode: parser.mode, - mclass: binrelClass(args[0]), - body: ordargument(args[1]), - isCharacterBox: utils.isCharacterBox(args[1]) - }; - } -}); - -// Build a relation or stacked op by placing one symbol on top of another -defineFunction({ - type: "mclass", - names: ["\\stackrel", "\\overset", "\\underset"], - props: { - numArgs: 2 - }, - handler({ parser, funcName }, args) { - const baseArg = args[1]; - const shiftedArg = args[0]; - - const baseOp = { - type: "op", - mode: baseArg.mode, - limits: true, - alwaysHandleSupSub: true, - parentIsSupSub: false, - symbol: false, - stack: true, - suppressBaseShift: funcName !== "\\stackrel", - body: ordargument(baseArg) - }; - - return { - type: "supsub", - mode: shiftedArg.mode, - base: baseOp, - sup: funcName === "\\underset" ? null : shiftedArg, - sub: funcName === "\\underset" ? shiftedArg : null - }; - }, - mathmlBuilder -}); diff --git a/src/functions/multiscript.js b/src/functions/multiscript.js deleted file mode 100644 index ce3da76e..00000000 --- a/src/functions/multiscript.js +++ /dev/null @@ -1,91 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML" -import ParseError from "../ParseError"; - -// Helper function -export const buildGroup = (el, style, noneNode) => { - if (!el) { return noneNode } - const node = mml.buildGroup(el, style) - if (node.type === "mrow" && node.children.length === 0) { return noneNode } - return node -} - -defineFunction({ - type: "multiscript", - names: ["\\sideset", "\\pres@cript"], // See macros.js for \prescript - props: { - numArgs: 3 - }, - handler({ parser, funcName, token }, args) { - if (args[2].body.length === 0) { - throw new ParseError(funcName + `cannot parse an empty base.`) - } - const base = args[2].body[0] - if (parser.settings.strict && funcName === "\\sideset" && !base.symbol) { - throw new ParseError(`The base of \\sideset must be a big operator. Try \\prescript.`) - } - - if ((args[0].body.length > 0 && args[0].body[0].type !== "supsub") || - (args[1].body.length > 0 && args[1].body[0].type !== "supsub")) { - throw new ParseError("\\sideset can parse only subscripts and " + - "superscripts in its first two arguments", token) - } - - // The prescripts and postscripts come wrapped in a supsub. - const prescripts = args[0].body.length > 0 ? args[0].body[0] : null - const postscripts = args[1].body.length > 0 ? args[1].body[0] : null - - if (!prescripts && !postscripts) { - return base - } else if (!prescripts) { - // It's not a multi-script. Get a \textstyle supsub. - return { - type: "styling", - mode: parser.mode, - scriptLevel: "text", - body: [{ - type: "supsub", - mode: parser.mode, - base, - sup: postscripts.sup, - sub: postscripts.sub - }] - } - } else { - return { - type: "multiscript", - mode: parser.mode, - isSideset: funcName === "\\sideset", - prescripts, - postscripts, - base - } - } - }, - mathmlBuilder(group, style) { - const base = mml.buildGroup(group.base, style) - - const prescriptsNode = new mathMLTree.MathNode("mprescripts") - const noneNode = new mathMLTree.MathNode("none") - let children = [] - - const preSub = buildGroup(group.prescripts.sub, style, noneNode) - const preSup = buildGroup(group.prescripts.sup, style, noneNode) - if (group.isSideset) { - // This seems silly, but LaTeX does this. Firefox ignores it, which does not make me sad. - preSub.setAttribute("style", "text-align: left;") - preSup.setAttribute("style", "text-align: left;") - } - - if (group.postscripts) { - const postSub = buildGroup(group.postscripts.sub, style, noneNode) - const postSup = buildGroup(group.postscripts.sup, style, noneNode) - children = [base, postSub, postSup, prescriptsNode, preSub, preSup] - } else { - children = [base, prescriptsNode, preSub, preSup] - } - - return new mathMLTree.MathNode("mmultiscripts", children); - } -}); diff --git a/src/functions/not.js b/src/functions/not.js deleted file mode 100644 index 32f8d3f9..00000000 --- a/src/functions/not.js +++ /dev/null @@ -1,46 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import symbols from "../symbols"; -import * as mml from "../buildMathML"; -import utils from "../utils" - -defineFunction({ - type: "not", - names: ["\\not"], - props: { - numArgs: 1, - primitive: true, - allowedInText: false - }, - handler({ parser }, args) { - const isCharacterBox = utils.isCharacterBox(args[0]) - let body - if (isCharacterBox) { - body = ordargument(args[0]) - if (body[0].text.charAt(0) === "\\") { - body[0].text = symbols.math[body[0].text].replace - } - // \u0338 is the Unicode Combining Long Solidus Overlay - body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1) - } else { - // When the argument is not a character box, TeX does an awkward, poorly placed overlay. - // We'll do the same. - const notNode = { type: "textord", mode: "math", text: "\u0338" } - const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } } - body = [notNode, kernNode, args[0]] - } - return { - type: "not", - mode: parser.mode, - body, - isCharacterBox - }; - }, - mathmlBuilder(group, style) { - if (group.isCharacterBox) { - const inner = mml.buildExpression(group.body, style); - return inner[0] - } else { - return mml.buildExpressionRow(group.body, style, true) - } - } -}); diff --git a/src/functions/op.js b/src/functions/op.js deleted file mode 100644 index 7b10eab9..00000000 --- a/src/functions/op.js +++ /dev/null @@ -1,335 +0,0 @@ -// Limits, symbols -import defineFunction, { ordargument } from "../defineFunction"; -import * as mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; -import utils from "../utils"; -import { delimiters, delimiterSizes } from "./delimsizing" - -// Some helpers - -const ordAtomTypes = ["textord", "mathord", "atom"] - -// Most operators have a large successor symbol, but these don't. -const noSuccessor = ["\\smallint"]; - -// Math operators (e.g. \sin) need a space between these types and themselves: -export const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"]; - -const dels = ["}", "\\left", "\\middle", "\\right"] -const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)) - -// NOTE: Unlike most `builders`s, this one handles not only "op", but also -// "supsub" since some of them (like \int) can affect super/subscripting. - -const mathmlBuilder = (group, style) => { - let node; - - if (group.symbol) { - // This is a symbol. Just add the symbol. - node = new mathMLTree.MathNode("mo", [mml.makeText(group.name, group.mode)]); - if (utils.contains(noSuccessor, group.name)) { - node.setAttribute("largeop", "false") - } else { - node.setAttribute("movablelimits", "false") - } - } else if (group.body) { - // This is an operator with children. Add them. - node = new mathMLTree.MathNode("mo", mml.buildExpression(group.body, style)); - } else { - // This is a text operator. Add all of the characters from the operator's name. - node = new mathMLTree.MathNode("mi", [new mathMLTree.TextNode(group.name.slice(1))]); - - if (!group.parentIsSupSub) { - // Append an invisible . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")]); - node = new mathMLTree.MathNode("mpadded", [node, operator]) - const lSpace = group.needsLeadingSpace ? 0.1667 : 0 - const rSpace = group.isFollowedByDelimiter ? 0 : 0.1666 - if (group.needsLeadingSpace) { - node.setAttribute("lspace", "0.1667em") // thin space. - } - if ((lSpace + rSpace) > 0) { - node.setAttribute("width", `+${lSpace + rSpace}em`) - } - } - } - - return node; -}; - -const singleCharBigOps = { - "\u220F": "\\prod", - "\u2210": "\\coprod", - "\u2211": "\\sum", - "\u22c0": "\\bigwedge", - "\u22c1": "\\bigvee", - "\u22c2": "\\bigcap", - "\u22c3": "\\bigcup", - "\u2a00": "\\bigodot", - "\u2a01": "\\bigoplus", - "\u2a02": "\\bigotimes", - "\u2a04": "\\biguplus", - "\u2a05": "\\bigsqcap", - "\u2a06": "\\bigsqcup" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\smallint", - "\u220F", - "\u2210", - "\u2211", - "\u22c0", - "\u22c1", - "\u22c2", - "\u22c3", - "\u2a00", - "\u2a01", - "\u2a02", - "\u2a04", - "\u2a06" - ], - props: { - numArgs: 0 - }, - handler: ({ parser, funcName }, args) => { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharBigOps[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: true, - stack: false, // This is true for \stackrel{}, not here. - name: fName - }; - }, - mathmlBuilder -}); - -// Note: calling defineFunction with a type that's already been defined only -// works because the same mathmlBuilder is being used. -defineFunction({ - type: "op", - names: ["\\mathop"], - props: { - numArgs: 1, - primitive: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - // It would be convienient to just wrap a around the argument. - // But if the argument is a or , that would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - const arr = (body.body) ? body.body : [body]; - const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type) - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: isSymbol, - stack: false, - name: isSymbol ? arr[0].text : null, - body: isSymbol ? null : ordargument(body) - }; - }, - mathmlBuilder -}); - -// There are 2 flags for operators; whether they produce limits in -// displaystyle, and whether they are symbols and should grow in -// displaystyle. These four groups cover the four possible choices. - -const singleCharIntegrals = { - "\u222b": "\\int", - "\u222c": "\\iint", - "\u222d": "\\iiint", - "\u222e": "\\oint", - "\u222f": "\\oiint", - "\u2230": "\\oiiint", - "\u2231": "\\intclockwise", - "\u2232": "\\varointclockwise", - "\u2a0c": "\\iiiint", - "\u2a0d": "\\intbar", - "\u2a0e": "\\intBar", - "\u2a0f": "\\fint", - "\u2a12": "\\rppolint", - "\u2a13": "\\scpolint", - "\u2a15": "\\pointint", - "\u2a16": "\\sqint", - "\u2a17": "\\intlarhk", - "\u2a18": "\\intx", - "\u2a19": "\\intcap", - "\u2a1a": "\\intcup" -}; - -// No limits, not symbols -defineFunction({ - type: "op", - names: [ - "\\arcsin", - "\\arccos", - "\\arctan", - "\\arctg", - "\\arcctg", - "\\arg", - "\\ch", - "\\cos", - "\\cosec", - "\\cosh", - "\\cot", - "\\cotg", - "\\coth", - "\\csc", - "\\ctg", - "\\cth", - "\\deg", - "\\dim", - "\\exp", - "\\hom", - "\\ker", - "\\lg", - "\\ln", - "\\log", - "\\sec", - "\\sin", - "\\sinh", - "\\sh", - "\\sgn", - "\\tan", - "\\tanh", - "\\tg", - "\\th" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType - const next = parser.gullet.future().text - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder -}); - -// Limits, not symbols -defineFunction({ - type: "op", - names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType - const next = parser.gullet.future().text - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder -}); - -// No limits, symbols -defineFunction({ - type: "op", - names: [ - "\\int", - "\\iint", - "\\iiint", - "\\iiiint", - "\\oint", - "\\oiint", - "\\oiiint", - "\\intclockwise", - "\\varointclockwise", - "\\intbar", - "\\intBar", - "\\fint", - "\\rppolint", - "\\scpolint", - "\\pointint", - "\\sqint", - "\\intlarhk", - "\\intx", - "\\intcap", - "\\intcup", - "\u222b", - "\u222c", - "\u222d", - "\u222e", - "\u222f", - "\u2230", - "\u2231", - "\u2232", - "\u2a0c", - "\u2a0d", - "\u2a0e", - "\u2a0f", - "\u2a12", - "\u2a13", - "\u2a15", - "\u2a16", - "\u2a17", - "\u2a18", - "\u2a19", - "\u2a1a" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharIntegrals[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: true, - stack: false, - name: fName - }; - }, - mathmlBuilder -}); diff --git a/src/functions/operatorname.js b/src/functions/operatorname.js deleted file mode 100644 index 1c2e36c1..00000000 --- a/src/functions/operatorname.js +++ /dev/null @@ -1,128 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction" -import defineMacro from "../defineMacro"; -import mathMLTree from "../mathMLTree" -import { spaceCharacter } from "./kern" -import { ordTypes } from "./op" -import utils from "../utils" - -import * as mml from "../buildMathML" - -// NOTE: Unlike most builders, this one handles not only -// "operatorname", but also "supsub" since \operatorname* can -// affect super/subscripting. - -const mathmlBuilder = (group, style) => { - let expression = mml.buildExpression(group.body, style.withFont("mathrm")) - - // Is expression a string or has it something like a fraction? - let isAllString = true; // default - for (let i = 0; i < expression.length; i++) { - const node = expression[i] - if (node instanceof mathMLTree.MathNode) { - switch (node.type) { - case "mi": - case "mn": - case "ms": - case "mtext": - break; // Do nothing yet. - case "mspace": - { - if (node.attributes.width) { - const width = node.attributes.width.replace("em", "") - const ch = spaceCharacter(Number(width)) - if (ch === "") { - isAllString = false - } else { - expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)]) - } - } - } - break - case "mo": { - const child = node.children[0] - if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { - child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*") - } else { - isAllString = false - } - break - } - default: - isAllString = false - } - } else { - isAllString = false - } - } - - if (isAllString) { - // Write a single TextNode instead of multiple nested tags. - const word = expression.map((node) => node.toText()).join("") - expression = [new mathMLTree.TextNode(word)] - } else if ( - expression.length === 1 - && utils.contains(["mover", "munder"], expression[0].type) && - (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext") - ) { - expression[0].children[0].type = "mi" - if (group.parentIsSupSub) { - return new mathMLTree.MathNode("mrow", expression) - } else { - const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")]) - return mathMLTree.newDocumentFragment([expression[0], operator]) - } - } - - let wrapper; - if (isAllString) { - wrapper = new mathMLTree.MathNode("mi", expression) - wrapper.setAttribute("mathvariant", "normal") - } else { - wrapper = new mathMLTree.MathNode("mrow", expression) - } - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")]) - if (group.needsLeadingSpace) { - // LaTeX gives operator spacing, but a gets ord spacing. - // So add a leading space. - const space = new mathMLTree.MathNode("mspace") - space.setAttribute("width", "0.1667em") // thin space. - return mathMLTree.newDocumentFragment([space, wrapper, operator]) - } else { - return mathMLTree.newDocumentFragment([wrapper, operator]) - } - } - - return wrapper -}; - -// \operatorname -// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ -defineFunction({ - type: "operatorname", - names: ["\\operatorname@", "\\operatornamewithlimits"], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = args[0] - const prevAtomType = parser.prevAtomType - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType) - }; - }, - mathmlBuilder -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); diff --git a/src/functions/ordgroup.js b/src/functions/ordgroup.js deleted file mode 100644 index 52c2196c..00000000 --- a/src/functions/ordgroup.js +++ /dev/null @@ -1,9 +0,0 @@ -import { defineFunctionBuilders } from "../defineFunction"; -import * as mml from "../buildMathML"; - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return mml.buildExpressionRow(group.body, style, true); - } -}); diff --git a/src/functions/overline.js b/src/functions/overline.js deleted file mode 100644 index e6c54e19..00000000 --- a/src/functions/overline.js +++ /dev/null @@ -1,31 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -defineFunction({ - type: "overline", - names: ["\\overline"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - const body = args[0]; - return { - type: "overline", - mode: parser.mode, - body - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005F")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode( - "mover", - [mml.buildGroup(group.body, style), operator] - ); - node.setAttribute("accent", "true"); - - return node; - } -}); diff --git a/src/functions/phantom.js b/src/functions/phantom.js deleted file mode 100644 index 24ed1624..00000000 --- a/src/functions/phantom.js +++ /dev/null @@ -1,73 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -defineFunction({ - type: "phantom", - names: ["\\phantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "phantom", - mode: parser.mode, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const inner = mml.buildExpression(group.body, style); - return new mathMLTree.MathNode("mphantom", inner); - } -}); - -defineFunction({ - type: "hphantom", - names: ["\\hphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "hphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = mml.buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("height", "0px"); - node.setAttribute("depth", "0px"); - return node; - } -}); - -defineFunction({ - type: "vphantom", - names: ["\\vphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "vphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = mml.buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("width", "0px"); - return node; - } -}); diff --git a/src/functions/pmb.js b/src/functions/pmb.js deleted file mode 100644 index 4af78962..00000000 --- a/src/functions/pmb.js +++ /dev/null @@ -1,31 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction" -import { wrapWithMstyle } from "../mathMLTree" -import * as mml from "../buildMathML" - -// \pmb is a simulation of bold font. -// The version of \pmb in ambsy.sty works by typesetting three copies of the argument -// with small offsets. We use CSS text-shadow. -// It's a hack. Not as good as a real bold font. Better than nothing. - -defineFunction({ - type: "pmb", - names: ["\\pmb"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "pmb", - mode: parser.mode, - body: ordargument(args[0]) - } - }, - mathmlBuilder(group, style) { - const inner = mml.buildExpression(group.body, style) - // Wrap with an element. - const node = wrapWithMstyle(inner) - node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px") - return node - } -}) diff --git a/src/functions/raise.js b/src/functions/raise.js deleted file mode 100644 index d8ecd51b..00000000 --- a/src/functions/raise.js +++ /dev/null @@ -1,66 +0,0 @@ -import defineFunction from "../defineFunction" -import { StyleLevel } from "../constants" -import mathMLTree from "../mathMLTree" -import { assertNodeType } from "../parseNode" -import { calculateSize } from "../units" -import * as mml from "../buildMathML" - -const sign = num => num >= 0 ? "+" : "-" - -// \raise, \lower, and \raisebox - -const mathmlBuilder = (group, style) => { - const newStyle = style.withLevel(StyleLevel.TEXT) - const node = new mathMLTree.MathNode("mpadded", [mml.buildGroup(group.body, newStyle)]) - const dy = calculateSize(group.dy, style) - node.setAttribute("voffset", dy.number + dy.unit) - const dyAbs = Math.abs(dy.number) - node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit) - node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit) - return node -} - -defineFunction({ - type: "raise", - names: ["\\raise", "\\lower"], - props: { - numArgs: 2, - argTypes: ["size", "primitive"], - primitive: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - if (funcName === "\\lower") { amount.number *= -1 } - const body = args[1] - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder -}) - - -defineFunction({ - type: "raise", - names: ["\\raisebox"], - props: { - numArgs: 2, - argTypes: ["size", "hbox"], - allowedInText: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value - const body = args[1] - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder -}) - diff --git a/src/functions/ref.js b/src/functions/ref.js deleted file mode 100644 index 12ef6024..00000000 --- a/src/functions/ref.js +++ /dev/null @@ -1,28 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import { invalidIdRegEx } from "./label"; - -defineFunction({ - type: "ref", - names: ["\\ref", "\\eqref"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser, funcName }, args) { - return { - type: "ref", - mode: parser.mode, - funcName, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Create an empty text node. Set a class and an href. - // The post-processor will populate with the target's tag or equation number. - const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"] - const node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("")], classes) - node.setAttribute("href", "#" + group.string) - return node - } -}); diff --git a/src/functions/relax.js b/src/functions/relax.js deleted file mode 100644 index 5527cfab..00000000 --- a/src/functions/relax.js +++ /dev/null @@ -1,16 +0,0 @@ -import defineFunction from "../defineFunction" - -defineFunction({ - type: "internal", - names: ["\\relax"], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser }) { - return { - type: "internal", - mode: parser.mode - }; - } -}) diff --git a/src/functions/rule.js b/src/functions/rule.js deleted file mode 100644 index 96230e87..00000000 --- a/src/functions/rule.js +++ /dev/null @@ -1,52 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import { assertNodeType } from "../parseNode"; -import { calculateSize } from "../units"; - -defineFunction({ - type: "rule", - names: ["\\rule"], - props: { - numArgs: 2, - numOptionalArgs: 1, - argTypes: ["size", "size", "size"] - }, - handler({ parser }, args, optArgs) { - const shift = optArgs[0]; - const width = assertNodeType(args[0], "size"); - const height = assertNodeType(args[1], "size"); - return { - type: "rule", - mode: parser.mode, - shift: shift && assertNodeType(shift, "size").value, - width: width.value, - height: height.value - }; - }, - mathmlBuilder(group, style) { - const width = calculateSize(group.width, style); - const height = calculateSize(group.height, style); - const shift = group.shift - ? calculateSize(group.shift, style) - : { number: 0, unit: "em" }; - const color = (style.color && style.getColor()) || "black"; - - const rule = new mathMLTree.MathNode("mspace"); - if (width.number > 0 && height.number > 0) { - rule.setAttribute("mathbackground", color); - } - rule.setAttribute("width", width.number + width.unit); - rule.setAttribute("height", height.number + height.unit); - if (shift.number === 0) { return rule } - - const wrapper = new mathMLTree.MathNode("mpadded", [rule]); - if (shift.number >= 0) { - wrapper.setAttribute("height", "+" + shift.number + shift.unit); - } else { - wrapper.setAttribute("height", shift.number + shift.unit); - wrapper.setAttribute("depth", "+" + -shift.number + shift.unit); - } - wrapper.setAttribute("voffset", shift.number + shift.unit); - return wrapper; - } -}); diff --git a/src/functions/sizing.js b/src/functions/sizing.js deleted file mode 100644 index 9d51d4e1..00000000 --- a/src/functions/sizing.js +++ /dev/null @@ -1,64 +0,0 @@ -import defineFunction from "../defineFunction"; -import { wrapWithMstyle } from "../mathMLTree" -import * as mml from "../buildMathML"; - -// The size mappings are taken from TeX with \normalsize=10pt. -// We don't have to track script level. MathML does that. -const sizeMap = { - "\\tiny": 0.5, - "\\sixptsize": 0.6, - "\\Tiny": 0.6, - "\\scriptsize": 0.7, - "\\footnotesize": 0.8, - "\\small": 0.9, - "\\normalsize": 1.0, - "\\large": 1.2, - "\\Large": 1.44, - "\\LARGE": 1.728, - "\\huge": 2.074, - "\\Huge": 2.488 -}; - -defineFunction({ - type: "sizing", - names: [ - "\\tiny", - "\\sixptsize", - "\\Tiny", - "\\scriptsize", - "\\footnotesize", - "\\small", - "\\normalsize", - "\\large", - "\\Large", - "\\LARGE", - "\\huge", - "\\Huge" - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ breakOnTokenText, funcName, parser }, args) => { - if (parser.settings.strict && parser.mode === "math") { - // eslint-disable-next-line no-console - console.log(`Temml strict-mode warning: Command ${funcName} is invalid in math mode.`) - } - const body = parser.parseExpression(false, breakOnTokenText); - return { - type: "sizing", - mode: parser.mode, - funcName, - body - }; - }, - mathmlBuilder: (group, style) => { - const newStyle = style.withFontSize(sizeMap[group.funcName]); - const inner = mml.buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner) - const factor = (sizeMap[group.funcName] / style.fontSize).toFixed(4) - node.setAttribute("mathsize", factor + "em"); - return node; - } -}); diff --git a/src/functions/smash.js b/src/functions/smash.js deleted file mode 100644 index 71890a62..00000000 --- a/src/functions/smash.js +++ /dev/null @@ -1,66 +0,0 @@ -// smash, with optional [tb], as in AMS -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import { assertNodeType } from "../parseNode"; - -import * as mml from "../buildMathML"; - -defineFunction({ - type: "smash", - names: ["\\smash"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args, optArgs) => { - let smashHeight = false; - let smashDepth = false; - const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); - if (tbArg) { - // Optional [tb] argument is engaged. - // ref: amsmath: \renewcommand{\smash}[1][tb]{% - // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% - let letter = ""; - for (let i = 0; i < tbArg.body.length; ++i) { - const node = tbArg.body[i]; - // TODO: Write an AssertSymbolNode - letter = node.text; - if (letter === "t") { - smashHeight = true; - } else if (letter === "b") { - smashDepth = true; - } else { - smashHeight = false; - smashDepth = false; - break; - } - } - } else { - smashHeight = true; - smashDepth = true; - } - - const body = args[0]; - return { - type: "smash", - mode: parser.mode, - body, - smashHeight, - smashDepth - }; - }, - mathmlBuilder: (group, style) => { - const node = new mathMLTree.MathNode("mpadded", [mml.buildGroup(group.body, style)]); - - if (group.smashHeight) { - node.setAttribute("height", "0px"); - } - - if (group.smashDepth) { - node.setAttribute("depth", "0px"); - } - - return node; - } -}); diff --git a/src/functions/sqrt.js b/src/functions/sqrt.js deleted file mode 100644 index fd54ce52..00000000 --- a/src/functions/sqrt.js +++ /dev/null @@ -1,31 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -defineFunction({ - type: "sqrt", - names: ["\\sqrt"], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser }, args, optArgs) { - const index = optArgs[0]; - const body = args[0]; - return { - type: "sqrt", - mode: parser.mode, - body, - index - }; - }, - mathmlBuilder(group, style) { - const { body, index } = group; - return index - ? new mathMLTree.MathNode("mroot", [ - mml.buildGroup(body, style), - mml.buildGroup(index, style.incrementLevel()) - ]) - : new mathMLTree.MathNode("msqrt", [mml.buildGroup(body, style)]); - } -}); diff --git a/src/functions/styling.js b/src/functions/styling.js deleted file mode 100644 index 23f65d06..00000000 --- a/src/functions/styling.js +++ /dev/null @@ -1,58 +0,0 @@ -import defineFunction from "../defineFunction"; -import { wrapWithMstyle } from "../mathMLTree" -import * as mml from "../buildMathML"; - -const styleMap = { - display: 0, - text: 1, - script: 2, - scriptscript: 3 -}; - -const styleAttributes = { - display: ["0", "true"], - text: ["0", "false"], - script: ["1", "false"], - scriptscript: ["2", "false"] -}; - -defineFunction({ - type: "styling", - names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ breakOnTokenText, funcName, parser }, args) { - // parse out the implicit body - const body = parser.parseExpression(true, breakOnTokenText); - - const scriptLevel = funcName.slice(1, funcName.length - 5); - return { - type: "styling", - mode: parser.mode, - // Figure out what scriptLevel to use by pulling out the scriptLevel from - // the function name - scriptLevel, - body - }; - }, - mathmlBuilder(group, style) { - // Figure out what scriptLevel we're changing to. - const newStyle = style.withLevel(styleMap[group.scriptLevel]); - // The style argument in the next line does NOT directly set a MathML script level. - // It just tracks the style level, in case we need to know it for supsub or mathchoice. - const inner = mml.buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner) - - const attr = styleAttributes[group.scriptLevel]; - - // Here is where we set the MathML script level. - node.setAttribute("scriptlevel", attr[0]); - node.setAttribute("displaystyle", attr[1]); - - return node; - } -}); diff --git a/src/functions/supsub.js b/src/functions/supsub.js deleted file mode 100644 index 80b9c7f2..00000000 --- a/src/functions/supsub.js +++ /dev/null @@ -1,135 +0,0 @@ -import { defineFunctionBuilders } from "../defineFunction" -import { StyleLevel } from "../constants" -import mathMLTree from "../mathMLTree" -import * as mml from "../buildMathML" - -/** - * Sometimes, groups perform special rules when they have superscripts or - * subscripts attached to them. This function lets the `supsub` group know that - * Sometimes, groups perform special rules when they have superscripts or - * its inner element should handle the superscripts and subscripts instead of - * handling them itself. - */ - -// Helpers -const symbolRegEx = /^m(over|under|underover)$/ - -// Super scripts and subscripts, whose precise placement can depend on other -// functions that precede them. -defineFunctionBuilders({ - type: "supsub", - mathmlBuilder(group, style) { - // Is the inner group a relevant horizonal brace? - let isBrace = false - let isOver - let isSup - let appendApplyFunction = false - let needsLeadingSpace = false - - if (group.base && group.base.type === "horizBrace") { - isSup = !!group.sup - if (isSup === group.base.isOver) { - isBrace = true - isOver = group.base.isOver - } - } - - if (group.base && !group.base.stack && - (group.base.type === "op" || group.base.type === "operatorname")) { - group.base.parentIsSupSub = true - appendApplyFunction = !group.base.symbol - needsLeadingSpace = group.base.needsLeadingSpace - } - - const children = group.base && group.base.stack - ? [mml.buildGroup(group.base.body[0], style)] - : [mml.buildGroup(group.base, style)] - - const childStyle = style.inSubOrSup() - if (group.sub) { - children.push(mml.buildGroup(group.sub, childStyle)) - } - - if (group.sup) { - children.push(mml.buildGroup(group.sup, childStyle)) - } - - let nodeType; - if (isBrace) { - nodeType = isOver ? "mover" : "munder" - } else if (!group.sub) { - const base = group.base - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "mover" - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "mover" - } else { - nodeType = "msup" - } - } else if (!group.sup) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munder"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "munder" - } else { - nodeType = "msub" - } - } else { - const base = group.base; - if (base && ((base.type === "op" && base.limits) || base.type === "multiscript") && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munderover" - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (style.level === StyleLevel.DISPLAY || base.limits) - ) { - nodeType = "munderover" - } else { - nodeType = "msubsup" - } - } - - let node = new mathMLTree.MathNode(nodeType, children) - if (appendApplyFunction) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")]) - if (needsLeadingSpace) { - const space = new mathMLTree.MathNode("mspace") - space.setAttribute("width", "0.1667em") // thin space. - node = mathMLTree.newDocumentFragment([space, node, operator]) - } else { - node = mathMLTree.newDocumentFragment([node, operator]) - } - } else if (symbolRegEx.test(nodeType)) { - // Wrap in a . Otherwise Firefox stretchy parens will not stretch to include limits. - node = new mathMLTree.MathNode("mrow", [node]) - } - - return node - } -}); diff --git a/src/functions/symbolsOp.js b/src/functions/symbolsOp.js deleted file mode 100644 index 3a56de43..00000000 --- a/src/functions/symbolsOp.js +++ /dev/null @@ -1,41 +0,0 @@ -import { defineFunctionBuilders } from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -// Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js. - -const short = ["\\shortmid", "\\nshortmid", "\\shortparallel", - "\\nshortparallel", "\\smallsetminus"] - -defineFunctionBuilders({ - type: "atom", - mathmlBuilder(group, style) { - const node = new mathMLTree.MathNode("mo", [mml.makeText(group.text, group.mode)]); - if (group.family === "punct") { - node.setAttribute("separator", "true"); - } else if (group.family === "open" || group.family === "close") { - // Delims built here should not stretch vertically. - // See delimsizing.js for stretchy delims. - if (group.family === "open") { - node.setAttribute("form", "prefix") - // Set an explicit attribute for stretch. Otherwise Firefox may do it wrong. - node.setAttribute("stretchy", "false") - } else if (group.family === "close") { - node.setAttribute("form", "postfix"); - node.setAttribute("stretchy", "false") - } - } else if (group.text === "\\mid") { - // Firefox messes up this spacing if at the end of an . See it explicitly. - node.setAttribute("lspace", "0.22em") // medium space - node.setAttribute("rspace", "0.22em") - node.setAttribute("stretchy", "false") - } else if (short.includes(group.text)) { - node.setAttribute("mathsize", "70%") - } else if (group.text === ":") { - // ":" is not in the MathML operator dictionary. Give it BIN spacing. - node.attributes.lspace = "0.2222em" - node.attributes.rspace = "0.2222em" - } - return node; - } -}); diff --git a/src/functions/symbolsOrd.js b/src/functions/symbolsOrd.js deleted file mode 100644 index 9b5cebf2..00000000 --- a/src/functions/symbolsOrd.js +++ /dev/null @@ -1,103 +0,0 @@ -import { defineFunctionBuilders } from "../defineFunction" -import { getVariant } from "../variant" -import { variantChar, smallCaps } from "../replace" -import mathMLTree from "../mathMLTree" -import * as mml from "../buildMathML" - -// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in -// src/symbols.js. - -const numberRegEx = /^\d(?:[\d,.]*\d)?$/ // Keep in sync with numberRegEx in Parser.js - -const latinRegEx = /[A-Ba-z]/ - -const italicNumber = (text, variant) => { - const mn = new mathMLTree.MathNode("mn", [text]) - const wrapper = new mathMLTree.MathNode("mstyle", [mn]) - wrapper.style["font-style"] = "italic" - wrapper.style["font-family"] = "Cambria, 'Times New Roman', serif" - if (variant === "bold-italic") { wrapper.style["font-weight"] = "bold" } - return wrapper -} - -defineFunctionBuilders({ - type: "mathord", - mathmlBuilder(group, style) { - const text = mml.makeText(group.text, group.mode, style) - const codePoint = text.text.codePointAt(0) - // Test for upper-case Greek - const defaultVariant = (0x0390 < codePoint && codePoint < 0x03aa) ? "normal" : "italic" - const variant = getVariant(group, style) || defaultVariant - if (variant === "script") { - text.text = variantChar(text.text, variant) - return new mathMLTree.MathNode("mi", [text], [style.font]) - } else if (variant !== "italic") { - text.text = variantChar(text.text, variant) - } - let node = new mathMLTree.MathNode("mi", [text]) - // TODO: Handle U+1D49C - U+1D4CF per https://www.unicode.org/charts/PDF/U1D400.pdf - if (variant === "normal") { - node.setAttribute("mathvariant", "normal") - if (text.text.length === 1) { - // A Firefox bug will apply spacing here, but there should be none. Fix it. - node = new mathMLTree.MathNode("mpadded", [node]) - node.setAttribute("lspace", "0") - node.setAttribute("width", "+0em") - } - } - return node - } -}) - -defineFunctionBuilders({ - type: "textord", - mathmlBuilder(group, style) { - let ch = group.text - const codePoint = ch.codePointAt(0) - if (style.fontFamily === "textsc") { - // Convert small latin letters to small caps. - if (96 < codePoint && codePoint < 123) { - ch = smallCaps[ch] - } - } - const text = mml.makeText(ch, group.mode, style) - const variant = getVariant(group, style) || "normal" - - let node - if (group.mode === "text") { - if (variant === "italic" || variant === "bold-italic") { - if (numberRegEx.test(group.text)) { - return italicNumber(text, variant) - } - } - if (variant !== "normal") { - text.text = variantChar(text.text, variant) - } - node = new mathMLTree.MathNode("mtext", [text]) - } else if (numberRegEx.test(group.text)) { - if (variant === "oldstylenums") { - const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]) - node = new mathMLTree.MathNode("mn", [ms]) - } else if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join("") - } - node = new mathMLTree.MathNode("mn", [text]) - } - } else if (group.text === "\\prime") { - node = new mathMLTree.MathNode("mo", [text]) - } else { - const origText = text.text - if (variant !== "italic") { - text.text = variantChar(text.text, variant) - } - node = new mathMLTree.MathNode("mi", [text]) - if (text.text === origText && latinRegEx.test(origText)) { - node.setAttribute("mathvariant", "italic") - } - } - return node - } -}) diff --git a/src/functions/symbolsSpacing.js b/src/functions/symbolsSpacing.js deleted file mode 100644 index 85518b52..00000000 --- a/src/functions/symbolsSpacing.js +++ /dev/null @@ -1,53 +0,0 @@ -import { defineFunctionBuilders } from "../defineFunction" -import mathMLTree from "../mathMLTree" -import ParseError from "../ParseError" - -// A map of CSS-based spacing functions to their CSS class. -const cssSpace = { - "\\nobreak": "nobreak", - "\\allowbreak": "allowbreak" -} - -// A lookup table to determine whether a spacing function/symbol should be -// treated like a regular space character. If a symbol or command is a key -// in this table, then it should be a regular space character. Furthermore, -// the associated value may have a `className` specifying an extra CSS class -// to add to the created `span`. -const regularSpace = { - " ": {}, - "\\ ": {}, - "~": { - className: "nobreak" - }, - "\\space": {}, - "\\nobreakspace": { - className: "nobreak" - } -} - -// ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in -// src/symbols.js. -defineFunctionBuilders({ - type: "spacing", - mathmlBuilder(group, style) { - let node - - if (Object.prototype.hasOwnProperty.call(regularSpace, group.text)) { - // Firefox does not render a space in a . So write a no-break space. - // TODO: If Firefox fixes that bug, uncomment the next line and write ch into the node. - //const ch = (regularSpace[group.text].className === "nobreak") ? "\u00a0" : " " - node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]) - } else if (Object.prototype.hasOwnProperty.call(cssSpace, group.text)) { - // MathML 3.0 calls for nobreak to occur in an , not an - // Ref: https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs - node = new mathMLTree.MathNode("mo") - if (group.text === "\\nobreak") { - node.setAttribute("linebreak", "nobreak") - } - } else { - throw new ParseError(`Unknown type of space "${group.text}"`) - } - - return node - } -}) diff --git a/src/functions/tag.js b/src/functions/tag.js deleted file mode 100644 index ddb86ec5..00000000 --- a/src/functions/tag.js +++ /dev/null @@ -1,8 +0,0 @@ -import { defineFunctionBuilders } from "../defineFunction"; - -defineFunctionBuilders({ - type: "tag" -}); - -// For a \tag, the work usually done in a mathmlBuilder is instead done in buildMathML.js. -// That way, a \tag can be pulled out of the parse tree and wrapped around the outer node. diff --git a/src/functions/text.js b/src/functions/text.js deleted file mode 100644 index ad7b2393..00000000 --- a/src/functions/text.js +++ /dev/null @@ -1,76 +0,0 @@ -import defineFunction, { ordargument } from "../defineFunction"; -import * as mml from "../buildMathML"; -import utils from "../utils" - -// Non-mathy text, possibly in a font -const textFontFamilies = { - "\\text": undefined, - "\\textrm": "textrm", - "\\textsf": "textsf", - "\\texttt": "texttt", - "\\textnormal": "textrm", - "\\textsc": "textsc" // small caps -}; - -const textFontWeights = { - "\\textbf": "textbf", - "\\textmd": "textmd" -}; - -const textFontShapes = { - "\\textit": "textit", - "\\textup": "textup" -}; - -const styleWithFont = (group, style) => { - const font = group.font; - // Checks if the argument is a font family or a font style. - if (!font) { - return style; - } else if (textFontFamilies[font]) { - return style.withTextFontFamily(textFontFamilies[font]); - } else if (textFontWeights[font]) { - return style.withTextFontWeight(textFontWeights[font]); - } else { - return style.withTextFontShape(textFontShapes[font]); - } -}; - -defineFunction({ - type: "text", - names: [ - // Font families - "\\text", - "\\textrm", - "\\textsf", - "\\texttt", - "\\textnormal", - "\\textsc", - // Font weights - "\\textbf", - "\\textmd", - // Font Shapes - "\\textit", - "\\textup" - ], - props: { - numArgs: 1, - argTypes: ["text"], - allowedInArgument: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "text", - mode: parser.mode, - body: ordargument(body), - font: funcName - }; - }, - mathmlBuilder(group, style) { - const newStyle = styleWithFont(group, style) - const mrow = mml.buildExpressionRow(group.body, newStyle) - return utils.consolidateText(mrow) - } -}); diff --git a/src/functions/tip.js b/src/functions/tip.js deleted file mode 100644 index 714f7248..00000000 --- a/src/functions/tip.js +++ /dev/null @@ -1,63 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -// Two functions included to enable migration from Mathjax. - -defineFunction({ - type: "tip", - names: ["\\mathtip"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = mml.buildGroup(group.body, style) - const tip = mml.buildGroup(group.tip, style) - // Browsers don't support the tooltip actiontype. - // TODO: Come back and fix \mathtip when it can be done via CSS w/o a JS event. - const node = new mathMLTree.MathNode("maction", [math, tip], ["tml-tip"]) - node.setAttribute("actiontype", "tooltip") - return node - } -}) - -defineFunction({ - type: "tip", - names: ["\\texttip"], - props: { - numArgs: 2, - argTypes: ["math", "text"] - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = mml.buildGroup(group.body, style) - const tip = mml.buildGroup(group.tip, style) - // args[1] only accepted text, so tip is a element or a of them. - let str = "" - if (tip.type === "mtext") { - str = tip.children[0].text - } else { - for (const child of tip.children) { - str += child.children[0].text - } - } - // Implement \texttip via a title attribute. - math.setAttribute("title", str) - return math - } -}) diff --git a/src/functions/toggle.js b/src/functions/toggle.js deleted file mode 100644 index 5f0179c7..00000000 --- a/src/functions/toggle.js +++ /dev/null @@ -1,13 +0,0 @@ -import { defineFunctionBuilders } from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -defineFunctionBuilders({ - type: "toggle", - mathmlBuilder(group, style) { - const expression = mml.buildExpression(group.body, style) - const node = new mathMLTree.MathNode("maction", expression, [], { cursor: "default" }) - node.setAttribute("actiontype", "toggle") - return node - } -}) diff --git a/src/functions/underline.js b/src/functions/underline.js deleted file mode 100644 index 63c444f3..00000000 --- a/src/functions/underline.js +++ /dev/null @@ -1,30 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import * as mml from "../buildMathML"; - -defineFunction({ - type: "underline", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "underline", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005f")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode("munder", - [mml.buildGroup(group.body, style), operator] - ); - node.setAttribute("accentunder", "true"); - - return node; - } -}); diff --git a/src/functions/verb.js b/src/functions/verb.js deleted file mode 100644 index da6a67a6..00000000 --- a/src/functions/verb.js +++ /dev/null @@ -1,33 +0,0 @@ -import defineFunction from "../defineFunction"; -import mathMLTree from "../mathMLTree"; -import ParseError from "../ParseError"; - -defineFunction({ - type: "verb", - names: ["\\verb"], - props: { - numArgs: 0, - allowedInText: true - }, - handler(context, args, optArgs) { - // \verb and \verb* are dealt with directly in Parser.js. - // If we end up here, it's because of a failure to match the two delimiters - // in the regex in Lexer.js. LaTeX raises the following error when \verb is - // terminated by end of line (or file). - throw new ParseError("\\verb ended by end of line instead of matching delimiter"); - }, - mathmlBuilder(group, style) { - const text = new mathMLTree.TextNode(makeVerb(group)); - const node = new mathMLTree.MathNode("mtext", [text]); - node.setAttribute("mathvariant", "monospace"); - return node; - } -}); - -/** - * Converts verb group into body string. - * - * \verb* replaces each space with an open box \u2423 - * \verb replaces each space with a no-break space \xA0 - */ -const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0"); diff --git a/src/linebreaking.js b/src/linebreaking.js deleted file mode 100644 index f76b0c21..00000000 --- a/src/linebreaking.js +++ /dev/null @@ -1,145 +0,0 @@ -import mathMLTree from "./mathMLTree" - -/* - * Neither Firefox nor Chrome support hard line breaks or soft line breaks. - * (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs) - * So Temml has work-arounds for both hard and soft breaks. - * The work-arounds sadly do not work simultaneously. Any top-level hard - * break makes soft line breaks impossible. - * - * Hard breaks are simulated by creating a and putting each line in its own . - * - * To create soft line breaks, Temml avoids using the and tags. - * Then the top level of a element can be occupied by elements, and the browser - * will break after a if the expression extends beyond the container limit. - * - * We want the expression to render with soft line breaks after each top-level binary or - * relational operator, per TeXbook p. 173. So we gather the expression into s so that - * each ends in a binary or relational operator. - * - * Soft line breaks will not work in Chromium and Safari, only Firefox. - * - * Hopefully browsers will someday do their own linebreaking and we will be able to delete - * much of this module. - */ - -export default function setLineBreaks(expression, isDisplayMode, isAnnotated, color = undefined) { - if (color === undefined) { - // First, make one pass through the expression and split any color nodes. - const upperLimit = expression.length - 1 - for (let i = upperLimit; i >= 0; i--) { - const node = expression[i]; - if (node.type === "mstyle" && node.attributes.mathcolor) { - const color = node.attributes.mathcolor - const fragment = setLineBreaks(node.children, isDisplayMode, isAnnotated, color) - if (!(fragment.type && fragment.type !== "mtable")) { - expression.splice(i, 1, ...fragment.children) - - } - } - } - } - - const tagName = color ? "mstyle" : "mrow" - - const mtrs = []; - let mrows = []; - let block = []; - let canBeBIN = false // The first node cannot be an infix binary operator. - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type && node.type === "mstyle" && node.attributes.mathcolor) { - // Start a new block. (Insert a soft linebreak.) - mrows.push(new mathMLTree.MathNode(tagName, block)) - // Insert the mstyle - mrows.push(node) - block = []; - continue - } - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block) - if (color) { element.setAttribute("mathcolor", color) } - mrows.push(new mathMLTree.MathNode(tagName, block)) - } - mrows.push(node) - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows) - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])) - mrows = []; - continue - } - block.push(node); - if (node.type && node.type === "mo" && !isDisplayMode && !isAnnotated) { - // This may be a place for a soft line break. - if (canBeBIN && !node.attributes.form) { - // Check if the following node is a \nobreak text node, e.g. "~"" - const next = i < expression.length - 1 ? expression[i + 1] : null; - let glueIsFreeOfNobreak = true; - if ( - !( - next && - next.type === "mtext" && - next.attributes.linebreak && - next.attributes.linebreak === "nobreak" - ) - ) { - // We may need to start a new block. - // First, put any post-operator glue on same line as operator. - for (let j = i + 1; j < expression.length; j++) { - const nd = expression[j]; - if ( - nd.type && - nd.type === "mspace" && - !(nd.attributes.linebreak && nd.attributes.linebreak === "newline") - ) { - block.push(nd); - i += 1; - if ( - nd.attributes && - nd.attributes.linebreak && - nd.attributes.linebreak === "nobreak" - ) { - glueIsFreeOfNobreak = false; - } - } else { - break; - } - } - } - if (glueIsFreeOfNobreak) { - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode(tagName, block) - if (color) { element.setAttribute("mathcolor", color) } - mrows.push(element) - block = []; - } - canBeBIN = false; - } - const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"; - // Any operator that follows an open delimiter is unary. - canBeBIN = !(node.attributes.separator || isOpenDelimiter); - } else { - canBeBIN = true; - } - } - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block) - if (color) { element.setAttribute("mathcolor", color) } - mrows.push(element) - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows) - const mtr = new mathMLTree.MathNode("mtr", [mtd]) - mtrs.push(mtr) - const mtable = new mathMLTree.MathNode("mtable", mtrs) - if (!isDisplayMode) { - mtable.setAttribute("columnalign", "left") - mtable.setAttribute("rowspacing", "0em") - } - return mtable - } - return mathMLTree.newDocumentFragment(mrows); -} diff --git a/src/macros.js b/src/macros.js deleted file mode 100644 index bffd6c92..00000000 --- a/src/macros.js +++ /dev/null @@ -1,709 +0,0 @@ -/** - * Predefined macros for Temml. - * This can be used to define some commands in terms of others. - */ - -// Export global macros object from defineMacro -import defineMacro, { _macros } from "./defineMacro"; -const macros = _macros; -export default macros; - -import symbols from "./symbols"; -import utils from "./utils"; -import ParseError from "./ParseError"; - -////////////////////////////////////////////////////////////////////// -// macro tools - -defineMacro("\\noexpand", function(context) { - // The expansion is the token itself; but that token is interpreted - // as if its meaning were ‘\relax’ if it is a control sequence that - // would ordinarily be expanded by TeX’s expansion rules. - const t = context.popToken(); - if (context.isExpandable(t.text)) { - t.noexpand = true; - t.treatAsRelax = true; - } - return { tokens: [t], numArgs: 0 }; -}); - -defineMacro("\\expandafter", function(context) { - // TeX first reads the token that comes immediately after \expandafter, - // without expanding it; let’s call this token t. Then TeX reads the - // token that comes after t (and possibly more tokens, if that token - // has an argument), replacing it by its expansion. Finally TeX puts - // t back in front of that expansion. - const t = context.popToken(); - context.expandOnce(true); // expand only an expandable token - return { tokens: [t], numArgs: 0 }; -}); - -// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 -// TeX source: \long\def\@firstoftwo#1#2{#1} -defineMacro("\\@firstoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[0], numArgs: 0 }; -}); - -// LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 -// TeX source: \long\def\@secondoftwo#1#2{#2} -defineMacro("\\@secondoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[1], numArgs: 0 }; -}); - -// LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) -// symbol that isn't a space, consuming any spaces but not consuming the -// first nonspace character. If that nonspace character matches #1, then -// the macro expands to #2; otherwise, it expands to #3. -defineMacro("\\@ifnextchar", function(context) { - const args = context.consumeArgs(3); // symbol, if, else - context.consumeSpaces(); - const nextToken = context.future(); - if (args[0].length === 1 && args[0][0].text === nextToken.text) { - return { tokens: args[1], numArgs: 0 }; - } else { - return { tokens: args[2], numArgs: 0 }; - } -}); - -// LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. -// If it is `*`, then it consumes the symbol, and the macro expands to #1; -// otherwise, the macro expands to #2 (without consuming the symbol). -// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} -defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); - -// LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode -defineMacro("\\TextOrMath", function(context) { - const args = context.consumeArgs(2); - if (context.mode === "text") { - return { tokens: args[0], numArgs: 0 }; - } else { - return { tokens: args[1], numArgs: 0 }; - } -}); - -const stringFromArg = arg => { - // Reverse the order of the arg and return a string. - let str = "" - for (let i = arg.length - 1; i > -1; i--) { - str += arg[i].text - } - return str -} - -// Lookup table for parsing numbers in base 8 through 16 -const digitToNumber = { - 0: 0, - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - a: 10, - A: 10, - b: 11, - B: 11, - c: 12, - C: 12, - d: 13, - D: 13, - e: 14, - E: 14, - f: 15, - F: 15 -}; - -const nextCharNumber = context => { - const numStr = context.future().text - if (numStr === "EOF") { return [null, ""] } - return [digitToNumber[numStr.charAt(0)], numStr] -} - -const appendCharNumbers = (number, numStr, base) => { - for (let i = 1; i < numStr.length; i++) { - const digit = digitToNumber[numStr.charAt(i)] - number *= base; - number += digit; - } - return number -} - -// TeX \char makes a literal character (catcode 12) using the following forms: -// (see The TeXBook, p. 43) -// \char123 -- decimal -// \char'123 -- octal -// \char"123 -- hex -// \char`x -- character that can be written (i.e. isn't active) -// \char`\x -- character that cannot be written (e.g. %) -// These all refer to characters from the font, so we turn them into special -// calls to a function \@char dealt with in the Parser. -defineMacro("\\char", function(context) { - let token = context.popToken(); - let base; - let number = ""; - if (token.text === "'") { - base = 8; - token = context.popToken(); - } else if (token.text === '"') { - base = 16; - token = context.popToken(); - } else if (token.text === "`") { - token = context.popToken(); - if (token.text[0] === "\\") { - number = token.text.charCodeAt(1); - } else if (token.text === "EOF") { - throw new ParseError("\\char` missing argument"); - } else { - number = token.text.charCodeAt(0); - } - } else { - base = 10; - } - if (base) { - // Parse a number in the given base, starting with first `token`. - let numStr = token.text - number = digitToNumber[numStr.charAt(0)]; - if (number == null || number >= base) { - throw new ParseError(`Invalid base-${base} digit ${token.text}`); - } - number = appendCharNumbers(number, numStr, base) - let digit; - [digit, numStr] = nextCharNumber(context) - while (digit != null && digit < base) { - number *= base; - number += digit; - number = appendCharNumbers(number, numStr, base) - context.popToken(); - [digit, numStr] = nextCharNumber(context) - } - } - return `\\@char{${number}}`; -}); - -// The Latin Modern font renders at the wrong vertical alignment. -// This macro provides a better rendering. -defineMacro("\\surd", "\\sqrt{}") - -defineMacro("\\hbox", "\\text{#1}"); - -// Per TeXbook p.122, "/" gets zero operator spacing. -// And MDN recommends using U+2044 instead of / for inline -defineMacro("/", "{\u2044}") - -// Since Temml has no \par, ignore \long. -defineMacro("\\long", "") - -////////////////////////////////////////////////////////////////////// -// Grouping -// \let\bgroup={ \let\egroup=} -defineMacro("\\bgroup", "{"); -defineMacro("\\egroup", "}"); - -// Symbols from latex.ltx: -// \def~{\nobreakspace{}} -// \def\lq{`} -// \def\rq{'} -// \def \aa {\r a} -defineMacro("~", "\\nobreakspace"); -defineMacro("\\lq", "`"); -defineMacro("\\rq", "'"); -defineMacro("\\aa", "\\r a"); - -defineMacro("\\Bbbk", "\\Bbb{k}"); - -// \mathstrut from the TeXbook, p 360 -defineMacro("\\mathstrut", "\\vphantom{(}"); - -// \underbar from TeXbook p 353 -defineMacro("\\underbar", "\\underline{\\text{#1}}"); - -////////////////////////////////////////////////////////////////////// -// LaTeX_2ε - -// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ -// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} -// We'll call \varvdots, which gets a glyph from symbols.js. -// The zero-width rule gets us an equivalent to the vertical 6pt kern. -defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); -defineMacro("\u22ee", "\\vdots"); - -////////////////////////////////////////////////////////////////////// -// amsmath.sty -// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf - -//\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} -defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); - -// \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} -defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); - -// \def\iff{\DOTSB\;\Longleftrightarrow\;} -// \def\implies{\DOTSB\;\Longrightarrow\;} -// \def\impliedby{\DOTSB\;\Longleftarrow\;} -defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); -defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); -defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); - -// AMSMath's automatic \dots, based on \mdots@@ macro. -const dotsByToken = { - ",": "\\dotsc", - "\\not": "\\dotsb", - // \keybin@ checks for the following: - "+": "\\dotsb", - "=": "\\dotsb", - "<": "\\dotsb", - ">": "\\dotsb", - "-": "\\dotsb", - "*": "\\dotsb", - ":": "\\dotsb", - // Symbols whose definition starts with \DOTSB: - "\\DOTSB": "\\dotsb", - "\\coprod": "\\dotsb", - "\\bigvee": "\\dotsb", - "\\bigwedge": "\\dotsb", - "\\biguplus": "\\dotsb", - "\\bigcap": "\\dotsb", - "\\bigcup": "\\dotsb", - "\\prod": "\\dotsb", - "\\sum": "\\dotsb", - "\\bigotimes": "\\dotsb", - "\\bigoplus": "\\dotsb", - "\\bigodot": "\\dotsb", - "\\bigsqcap": "\\dotsb", - "\\bigsqcup": "\\dotsb", - "\\And": "\\dotsb", - "\\longrightarrow": "\\dotsb", - "\\Longrightarrow": "\\dotsb", - "\\longleftarrow": "\\dotsb", - "\\Longleftarrow": "\\dotsb", - "\\longleftrightarrow": "\\dotsb", - "\\Longleftrightarrow": "\\dotsb", - "\\mapsto": "\\dotsb", - "\\longmapsto": "\\dotsb", - "\\hookrightarrow": "\\dotsb", - "\\doteq": "\\dotsb", - // Symbols whose definition starts with \mathbin: - "\\mathbin": "\\dotsb", - // Symbols whose definition starts with \mathrel: - "\\mathrel": "\\dotsb", - "\\relbar": "\\dotsb", - "\\Relbar": "\\dotsb", - "\\xrightarrow": "\\dotsb", - "\\xleftarrow": "\\dotsb", - // Symbols whose definition starts with \DOTSI: - "\\DOTSI": "\\dotsi", - "\\int": "\\dotsi", - "\\oint": "\\dotsi", - "\\iint": "\\dotsi", - "\\iiint": "\\dotsi", - "\\iiiint": "\\dotsi", - "\\idotsint": "\\dotsi", - // Symbols whose definition starts with \DOTSX: - "\\DOTSX": "\\dotsx" -}; - -defineMacro("\\dots", function(context) { - // TODO: If used in text mode, should expand to \textellipsis. - // However, in Temml, \textellipsis and \ldots behave the same - // (in text mode), and it's unlikely we'd see any of the math commands - // that affect the behavior of \dots when in text mode. So fine for now - // (until we support \ifmmode ... \else ... \fi). - let thedots = "\\dotso"; - const next = context.expandAfterFuture().text; - if (next in dotsByToken) { - thedots = dotsByToken[next]; - } else if (next.slice(0, 4) === "\\not") { - thedots = "\\dotsb"; - } else if (next in symbols.math) { - if (utils.contains(["bin", "rel"], symbols.math[next].group)) { - thedots = "\\dotsb"; - } - } - return thedots; -}); - -const spaceAfterDots = { - // \rightdelim@ checks for the following: - ")": true, - "]": true, - "\\rbrack": true, - "\\}": true, - "\\rbrace": true, - "\\rangle": true, - "\\rceil": true, - "\\rfloor": true, - "\\rgroup": true, - "\\rmoustache": true, - "\\right": true, - "\\bigr": true, - "\\biggr": true, - "\\Bigr": true, - "\\Biggr": true, - // \extra@ also tests for the following: - $: true, - // \extrap@ checks for the following: - ";": true, - ".": true, - ",": true -}; - -defineMacro("\\dotso", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\dotsc", function(context) { - const next = context.future().text; - // \dotsc uses \extra@ but not \extrap@, instead specially checking for - // ';' and '.', but doesn't check for ','. - if (next in spaceAfterDots && next !== ",") { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\cdots", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\@cdots\\,"; - } else { - return "\\@cdots"; - } -}); - -defineMacro("\\dotsb", "\\cdots"); -defineMacro("\\dotsm", "\\cdots"); -defineMacro("\\dotsi", "\\!\\cdots"); -defineMacro("\\idotsint", "\\dotsi"); -// amsmath doesn't actually define \dotsx, but \dots followed by a macro -// starting with \DOTSX implies \dotso, and then \extra@ detects this case -// and forces the added `\,`. -defineMacro("\\dotsx", "\\ldots\\,"); - -// \let\DOTSI\relax -// \let\DOTSB\relax -// \let\DOTSX\relax -defineMacro("\\DOTSI", "\\relax"); -defineMacro("\\DOTSB", "\\relax"); -defineMacro("\\DOTSX", "\\relax"); - -// Spacing, based on amsmath.sty's override of LaTeX defaults -// \DeclareRobustCommand{\tmspace}[3]{% -// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} -defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); -// \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\,", "{\\tmspace+{3mu}{.1667em}}"); -// \let\thinspace\, -defineMacro("\\thinspace", "\\,"); -// \def\>{\mskip\medmuskip} -// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} -// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\>", "\\mskip{4mu}"); -defineMacro("\\:", "{\\tmspace+{4mu}{.2222em}}"); -// \let\medspace\: -defineMacro("\\medspace", "\\:"); -// \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip = 5mu plus 5mu -defineMacro("\\;", "{\\tmspace+{5mu}{.2777em}}"); -// \let\thickspace\; -defineMacro("\\thickspace", "\\;"); -// \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\!", "{\\tmspace-{3mu}{.1667em}}"); -// \let\negthinspace\! -defineMacro("\\negthinspace", "\\!"); -// \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} -// TODO: math mode should use \medmuskip -defineMacro("\\negmedspace", "{\\tmspace-{4mu}{.2222em}}"); -// \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip -defineMacro("\\negthickspace", "{\\tmspace-{5mu}{.277em}}"); -// \def\enspace{\kern.5em } -defineMacro("\\enspace", "\\kern.5em "); -// \def\enskip{\hskip.5em\relax} -defineMacro("\\enskip", "\\hskip.5em\\relax"); -// \def\quad{\hskip1em\relax} -defineMacro("\\quad", "\\hskip1em\\relax"); -// \def\qquad{\hskip2em\relax} -defineMacro("\\qquad", "\\hskip2em\\relax"); - -// \tag@in@display form of \tag -defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); -defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); -defineMacro("\\tag@literal", (context) => { - if (context.macros.get("\\df@tag")) { - throw new ParseError("Multiple \\tag"); - } - return "\\def\\df@tag{\\text{#1}}"; -}); - -// \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin -// {\operator@font mod}\penalty900 -// \mkern5mu\nonscript\mskip-\medmuskip} -// \newcommand{\pod}[1]{\allowbreak -// \if@display\mkern18mu\else\mkern8mu\fi(#1)} -// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} -// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu -// \else\mkern12mu\fi{\operator@font mod}\,\,#1} -// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\bmod", "\\mathbin{\\text{mod}}"); -defineMacro( - "\\pod", - "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)" -); -defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); -defineMacro( - "\\mod", - "\\allowbreak" + - "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + - "{\\rm mod}\\,\\,#1" -); - -////////////////////////////////////////////////////////////////////// -// LaTeX source2e - -// \expandafter\let\expandafter\@normalcr -// \csname\expandafter\@gobble\string\\ \endcsname -// \DeclareRobustCommand\newline{\@normalcr\relax} -defineMacro("\\newline", "\\\\\\relax"); - -// \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} -// TODO: Doesn't normally work in math mode because \@ fails. -defineMacro("\\TeX", "\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"); - -defineMacro( - "\\LaTeX", - "\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX" -); - -defineMacro( - "\\Temml", - // eslint-disable-next-line max-len - "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}" -); - -// \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} -// \def\@hspace#1{\hskip #1\relax} -// \def\@hspacer#1{\vrule \@width\z@\nobreak -// \hskip #1\hskip \z@skip} -defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); -defineMacro("\\@hspace", "\\hskip #1\\relax"); -defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); - -defineMacro("\\colon", `\\mathpunct{\\char"3a}`) - -////////////////////////////////////////////////////////////////////// -// mathtools.sty - -defineMacro("\\prescript", "\\pres@cript{_{#1}^{#2}}{}{#3}") - -//\providecommand\ordinarycolon{:} -defineMacro("\\ordinarycolon", `\\char"3a`); -// Raise to center on the math axis, as closely as possible. -defineMacro("\\vcentcolon", "\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}}"); -// \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\coloneq", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2212}'); -// \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\Coloneq", '\\mathrel{\\char"2237\\char"2212}'); -// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqqcolon", '\\mathrel{\\char"3d\\char"2237}'); -// \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqcolon", '\\mathrel{\\char"2212\\char"2237}'); -// \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\colonapprox", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2248}'); -// \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\Colonapprox", '\\mathrel{\\char"2237\\char"2248}'); -// \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); -// \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\Colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); - -////////////////////////////////////////////////////////////////////// -// colonequals.sty - -// Alternate names for mathtools's macros: -defineMacro("\\ratio", "\\vcentcolon"); -defineMacro("\\coloncolon", "\\dblcolon"); -defineMacro("\\colonequals", "\\coloneqq"); -defineMacro("\\coloncolonequals", "\\Coloneqq"); -defineMacro("\\equalscolon", "\\eqqcolon"); -defineMacro("\\equalscoloncolon", "\\Eqqcolon"); -defineMacro("\\colonminus", "\\coloneq"); -defineMacro("\\coloncolonminus", "\\Coloneq"); -defineMacro("\\minuscolon", "\\eqcolon"); -defineMacro("\\minuscoloncolon", "\\Eqcolon"); -// \colonapprox name is same in mathtools and colonequals. -defineMacro("\\coloncolonapprox", "\\Colonapprox"); -// \colonsim name is same in mathtools and colonequals. -defineMacro("\\coloncolonsim", "\\Colonsim"); - -// Present in newtxmath, pxfonts and txfonts -defineMacro("\\notni", "\\mathrel{\\char`\u220C}"); -defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); -defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); - -////////////////////////////////////////////////////////////////////// -// From amsopn.sty -defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}"); -defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}"); -defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"); -defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"); -defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"); -defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"); - -defineMacro("\\centerdot", "{\\medspace\\rule{0.167em}{0.189em}\\medspace}") - -////////////////////////////////////////////////////////////////////// -// statmath.sty -// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf - -defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); -defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); -defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}"); - -////////////////////////////////////////////////////////////////////// -// braket.sty -// http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf - -defineMacro("\\bra", "\\mathinner{\\langle{#1}|}"); -defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}"); -defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}"); -defineMacro("\\Bra", "\\left\\langle#1\\right|"); -defineMacro("\\Ket", "\\left|#1\\right\\rangle"); -const braketHelper = (one) => (context) => { - const left = context.consumeArg().tokens; - const middle = context.consumeArg().tokens; - const middleDouble = context.consumeArg().tokens; - const right = context.consumeArg().tokens; - const oldMiddle = context.macros.get("|"); - const oldMiddleDouble = context.macros.get("\\|"); - context.macros.beginGroup(); - const midMacro = (double) => (context) => { - if (one) { - // Only modify the first instance of | or \| - context.macros.set("|", oldMiddle); - if (middleDouble.length) { - context.macros.set("\\|", oldMiddleDouble); - } - } - let doubled = double; - if (!double && middleDouble.length) { - // Mimic \@ifnextchar - const nextToken = context.future(); - if (nextToken.text === "|") { - context.popToken(); - doubled = true; - } - } - return { - tokens: doubled ? middleDouble : middle, - numArgs: 0 - }; - }; - context.macros.set("|", midMacro(false)); - if (middleDouble.length) { - context.macros.set("\\|", midMacro(true)); - } - const arg = context.consumeArg().tokens; - const expanded = context.expandTokens([...right, ...arg, ...left]); // reversed - context.macros.endGroup(); - return { - tokens: expanded.reverse(), - numArgs: 0 - }; -}; -defineMacro("\\bra@ket", braketHelper(false)); -defineMacro("\\bra@set", braketHelper(true)); -defineMacro("\\Braket", "\\bra@ket{\\left\\langle}" + - "{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"); -defineMacro("\\Set", "\\bra@set{\\left\\{\\:}" + - "{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"); -defineMacro("\\set", "\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"); - // has no support for special || or \| - -////////////////////////////////////////////////////////////////////// -// actuarialangle.dtx -defineMacro("\\angln", "{\\angl n}"); - -////////////////////////////////////////////////////////////////////// -// derivative.sty -defineMacro("\\odv", "\\@ifstar\\odv@next\\odv@numerator"); -defineMacro("\\odv@numerator", "\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}") -defineMacro("\\odv@next", "\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1") -defineMacro("\\pdv", "\\@ifstar\\pdv@next\\pdv@numerator"); - -const pdvHelper = args => { - const numerator = args[0][0].text - const denoms = stringFromArg(args[1]).split(",") - const power = String(denoms.length) - const numOp = power === "1" ? "\\partial" : `\\partial^${power}` - let denominator = "" - denoms.map(e => { denominator += "\\partial " + e.trim() + "\\,"}) - return [numerator, numOp, denominator.replace(/\\,$/, "")] -} -defineMacro("\\pdv@numerator", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)) - return `\\frac{${numOp} ${numerator}}{${denominator}}` -}) -defineMacro("\\pdv@next", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)) - return `\\frac{${numOp}}{${denominator}} ${numerator}` -}) - -////////////////////////////////////////////////////////////////////// -// upgreek.dtx -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\upbeta", "\\up@greek{\\beta}"); -defineMacro("\\upgamma", "\\up@greek{\\gamma}"); -defineMacro("\\updelta", "\\up@greek{\\delta}"); -defineMacro("\\upepsilon", "\\up@greek{\\epsilon}"); -defineMacro("\\upzeta", "\\up@greek{\\zeta}"); -defineMacro("\\upeta", "\\up@greek{\\eta}"); -defineMacro("\\uptheta", "\\up@greek{\\theta}"); -defineMacro("\\upiota", "\\up@greek{\\iota}"); -defineMacro("\\upkappa", "\\up@greek{\\kappa}"); -defineMacro("\\uplambda", "\\up@greek{\\lambda}"); -defineMacro("\\upmu", "\\up@greek{\\mu}"); -defineMacro("\\upnu", "\\up@greek{\\nu}"); -defineMacro("\\upxi", "\\up@greek{\\xi}"); -defineMacro("\\upomicron", "\\up@greek{\\omicron}"); -defineMacro("\\uppi", "\\up@greek{\\pi}"); -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\uprho", "\\up@greek{\\rho}"); -defineMacro("\\upsigma", "\\up@greek{\\sigma}"); -defineMacro("\\uptau", "\\up@greek{\\tau}"); -defineMacro("\\upupsilon", "\\up@greek{\\upsilon}"); -defineMacro("\\upphi", "\\up@greek{\\phi}"); -defineMacro("\\upchi", "\\up@greek{\\chi}"); -defineMacro("\\uppsi", "\\up@greek{\\psi}"); -defineMacro("\\upomega", "\\up@greek{\\omega}"); - -////////////////////////////////////////////////////////////////////// -// cmll package -defineMacro("\\invamp", '\\mathbin{\\char"214b}') -defineMacro("\\parr", '\\mathbin{\\char"214b}') -defineMacro("\\with", '\\mathbin{\\char"26}') -defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}') -defineMacro("\\multimapboth", '\\mathrel{\\char"29df}') -defineMacro("\\scoh", '{\\mkern5mu\\char"2322\\mkern5mu}') -defineMacro("\\sincoh", '{\\mkern5mu\\char"2323\\mkern5mu}') -defineMacro("\\coh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2322}}} -{\\smash{\\lower4mu{\\char"2323}}}\\mkern5mu}`) -defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2323}}} -{\\smash{\\lower4mu{\\char"2322}}}\\mkern5mu}`) - - -////////////////////////////////////////////////////////////////////// -// chemstyle package -defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}"); diff --git a/src/mathMLTree.js b/src/mathMLTree.js deleted file mode 100644 index 4c7bc707..00000000 --- a/src/mathMLTree.js +++ /dev/null @@ -1,175 +0,0 @@ -// -/** - * These objects store data about MathML nodes. - * The `toNode` and `toMarkup` functions create namespaced DOM nodes and - * HTML text markup respectively. - */ - -import utils from "./utils"; -import { DocumentFragment } from "./tree"; -import { createClass } from "./domTree"; - -export function newDocumentFragment(children) { - return new DocumentFragment(children); -} - -/** - * This node represents a general purpose MathML node of any type, - * for example, `"mo"` or `"mspace"`, corresponding to `` and - * `` tags). - */ -export class MathNode { - constructor(type, children, classes, style) { - this.type = type; - this.attributes = {}; - this.children = children || []; - this.classes = classes || []; - this.style = style || {}; // Used for elements - } - - /** - * Sets an attribute on a MathML node. MathML depends on attributes to convey a - * semantic content, so this is used heavily. - */ - setAttribute(name, value) { - this.attributes[name] = value; - } - - /** - * Gets an attribute on a MathML node. - */ - getAttribute(name) { - return this.attributes[name]; - } - - /** - * Converts the math node into a MathML-namespaced DOM element. - */ - toNode() { - const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); - - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - if (this.classes.length > 0) { - node.className = createClass(this.classes); - } - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; - } - - /** - * Converts the math node into an HTML markup string. - */ - toMarkup() { - let markup = "<" + this.type; - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - markup += " " + attr + '="'; - markup += utils.escape(this.attributes[attr]); - markup += '"'; - } - } - - if (this.classes.length > 0) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - markup += ">"; - - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ""; - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText, but escaped. - */ - toText() { - return this.children.map((child) => child.toText()).join(""); - } -} - -/** - * This node represents a piece of text. - */ -export class TextNode { - constructor(text) { - this.text = text; - } - - /** - * Converts the text node into a DOM text node. - */ - toNode() { - return document.createTextNode(this.text); - } - - /** - * Converts the text node into escaped HTML markup - * (representing the text itself). - */ - toMarkup() { - return utils.escape(this.toText()); - } - - /** - * Converts the text node into a string - * (representing the text iteself). - */ - toText() { - return this.text; - } -} - -// Do not make an the only child of a . -// An acts as its own implicit . -export const wrapWithMstyle = expression => { - let node - if (expression.length === 1 && expression[0].type === "mrow") { - node = expression.pop() - node.type = "mstyle" - } else { - node = new MathNode("mstyle", expression); - } - return node -} - -export default { - MathNode, - TextNode, - newDocumentFragment -}; diff --git a/src/parseNode.js b/src/parseNode.js deleted file mode 100644 index 9c3da07e..00000000 --- a/src/parseNode.js +++ /dev/null @@ -1,42 +0,0 @@ -import { NON_ATOMS } from "./symbols"; - -/** - * Asserts that the node is of the given type and returns it with stricter - * typing. Throws if the node's type does not match. - */ -export function assertNodeType(node, type) { - if (!node || node.type !== type) { - throw new Error( - `Expected node of type ${type}, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return node; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -export function assertSymbolNodeType(node) { - const typedNode = checkSymbolNodeType(node); - if (!typedNode) { - throw new Error( - `Expected node of symbol group type, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return typedNode; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -export function checkSymbolNodeType(node) { - if (node && (node.type === "atom" || - Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) { - return node; - } - return null; -} diff --git a/src/parseTree.js b/src/parseTree.js deleted file mode 100644 index f1399ad4..00000000 --- a/src/parseTree.js +++ /dev/null @@ -1,40 +0,0 @@ -import Parser from "./Parser" -import ParseError from "./ParseError" - -/** - * Parses an expression using a Parser, then returns the parsed result. - */ -const parseTree = function(toParse, settings) { - if (!(typeof toParse === "string" || toParse instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(toParse, settings) - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"] - - let tree = parser.parse() - - // LaTeX ignores a \tag placed outside an AMS environment. - if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) { - // If the input used \tag, it will set the \df@tag macro to the tag. - // In this case, we separately parse the tag and wrap the tree. - if (parser.gullet.macros.get("\\df@tag")) { - if (!settings.displayMode) { - throw new ParseError("\\tag works only in display mode") - } - parser.gullet.feed("\\df@tag") - tree = [ - { - type: "tag", - mode: "text", - body: tree, - tag: parser.parse() - } - ] - } - } - - return tree -} - -export default parseTree diff --git a/src/postProcess.js b/src/postProcess.js deleted file mode 100644 index c86cb268..00000000 --- a/src/postProcess.js +++ /dev/null @@ -1,57 +0,0 @@ -/* Temml Post Process - * Perform two tasks not done by Temml when it created each individual Temml element. - * Given a block of block, - * 1. At each AMS auto-numbered environment, assign an id. - * 2. Populate the text contents of each \ref & \eqref - * - * As with other Temml code, this file is released under terms of the MIT license. - * https://mit-license.org/ - */ - -export const version = "0.6.9"; - -export function postProcess(block) { - const labelMap = {} - let i = 0 - - // Get a collection of the parents of each \tag & auto-numbered equation - const parents = block.getElementsByClassName("tml-tageqn"); - for (const parent of parents) { - const eqns = parent.getElementsByClassName("tml-eqn") - if (eqns. length > 0 ) { - // AMS automatically numbered equation. - // Assign an id. - i += 1; - eqns[0].id = "tml-eqn-" + i - // No need to write a number into the text content of the element. - // A CSS counter does that even if this postProcess() function is not used. - } - // If there is a \label, add it to labelMap - const labels = parent.getElementsByClassName("tml-label") - if (labels.length === 0) { continue } - if (eqns.length > 0) { - labelMap[labels[0].id] = String(i) - } else { - const tags = parent.getElementsByClassName("tml-tag") - if (tags.length > 0) { - labelMap[labels[0].id] = tags[0].textContent - } - } - } - - // Populate \ref & \eqref text content - const refs = block.getElementsByClassName("tml-ref"); - [...refs].forEach(ref => { - let str = labelMap[ref.getAttribute("href").slice(1)]; - if (ref.className.indexOf("tml-eqref") === -1) { - // \ref. Omit parens. - str = str.replace(/^\(/, "") - str = str.replace(/\($/, "") - } { - // \eqref. Include parens - if (str.charAt(0) !== "(") { str = "(" + str } - if (str.slice(-1) !== ")") { str = str + ")" } - } - ref.textContent = str - }) -} diff --git a/src/replace.js b/src/replace.js deleted file mode 100644 index e69131fe..00000000 --- a/src/replace.js +++ /dev/null @@ -1,225 +0,0 @@ -// Chromium does not support the MathML `mathvariant` attribute. -// Instead, we replace ASCII characters with Unicode characters that -// are defined in the font as bold, italic, double-struck, etc. -// This module identifies those Unicode code points. - -// First, a few helpers. -const script = Object.freeze({ - B: 0x20EA, // Offset from ASCII B to Unicode script B - E: 0x20EB, - F: 0x20EB, - H: 0x20C3, - I: 0x20C7, - L: 0x20C6, - M: 0x20E6, - R: 0x20C9, - e: 0x20CA, - g: 0x20A3, - o: 0x20C5 -}) - -const frak = Object.freeze({ - C: 0x20EA, - H: 0x20C4, - I: 0x20C8, - R: 0x20CA, - Z: 0x20CE -}) - -const bbb = Object.freeze({ - C: 0x20BF, // blackboard bold - H: 0x20C5, - N: 0x20C7, - P: 0x20C9, - Q: 0x20C9, - R: 0x20CB, - Z: 0x20CA -}) - -const bold = Object.freeze({ - "\u03f5": 0x1D2E7, // lunate epsilon - "\u03d1": 0x1D30C, // vartheta - "\u03f0": 0x1D2EE, // varkappa - "\u03c6": 0x1D319, // varphi - "\u03f1": 0x1D2EF, // varrho - "\u03d6": 0x1D30B // varpi -}) - -const boldItalic = Object.freeze({ - "\u03f5": 0x1D35B, // lunate epsilon - "\u03d1": 0x1D380, // vartheta - "\u03f0": 0x1D362, // varkappa - "\u03c6": 0x1D38D, // varphi - "\u03f1": 0x1D363, // varrho - "\u03d6": 0x1D37F // varpi -}) - -const boldsf = Object.freeze({ - "\u03f5": 0x1D395, // lunate epsilon - "\u03d1": 0x1D3BA, // vartheta - "\u03f0": 0x1D39C, // varkappa - "\u03c6": 0x1D3C7, // varphi - "\u03f1": 0x1D39D, // varrho - "\u03d6": 0x1D3B9 // varpi -}) - -const bisf = Object.freeze({ - "\u03f5": 0x1D3CF, // lunate epsilon - "\u03d1": 0x1D3F4, // vartheta - "\u03f0": 0x1D3D6, // varkappa - "\u03c6": 0x1D401, // varphi - "\u03f1": 0x1D3D7, // varrho - "\u03d6": 0x1D3F3 // varpi -}) - -// Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf -const offset = Object.freeze({ - upperCaseLatin: { // A-Z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3BF }, - "italic": ch => { return 0x1D3F3 }, - "bold-italic": ch => { return 0x1D427 }, - "script": ch => { return script[ch] || 0x1D45B }, - "script-bold": ch => { return 0x1D48F }, - "fraktur": ch => { return frak[ch] || 0x1D4C3 }, - "fraktur-bold": ch => { return 0x1D52B }, - "double-struck": ch => { return bbb[ch] || 0x1D4F7 }, - "sans-serif": ch => { return 0x1D55F }, - "sans-serif-bold": ch => { return 0x1D593 }, - "sans-serif-italic": ch => { return 0x1D5C7 }, - "sans-serif-bold-italic": ch => { return 0x1D63C }, - "monospace": ch => { return 0x1D62F } - }, - lowerCaseLatin: { // a-z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3B9 }, - "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED }, - "bold-italic": ch => { return 0x1D421 }, - "script": ch => { return script[ch] || 0x1D455 }, - "script-bold": ch => { return 0x1D489 }, - "fraktur": ch => { return 0x1D4BD }, - "fraktur-bold": ch => { return 0x1D525 }, - "double-struck": ch => { return 0x1D4F1 }, - "sans-serif": ch => { return 0x1D559 }, - "sans-serif-bold": ch => { return 0x1D58D }, - "sans-serif-italic": ch => { return 0x1D5C1 }, - "sans-serif-bold-italic": ch => { return 0x1D5F5 }, - "monospace": ch => { return 0x1D629 } - }, - upperCaseGreek: { // A-Ω ∇ - "normal": ch => { return 0 }, - "bold": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "italic": ch => { return ch === "∇" ? 0x1B4F4 : 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-bold": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return ch === "∇" ? 0x1B5A2 : 0x1D3FF }, - "monospace": ch => { return 0 } - }, - lowerCaseGreek: { // α-ω - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D311 }, - "italic": ch => { return 0x1D34B }, - "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return 0x1D3BF }, - "sans-serif-bold": ch => { return 0x1D3BF }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0x1D3F9 }, - "monospace": ch => { return 0 } - }, - varGreek: { // \varGamma, etc - "normal": ch => { return 0 }, - "bold": ch => { return bold[ch] || -51 }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return boldItalic[ch] || 0x3A }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - "sans-serif": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-bold": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE }, - "monospace": ch => { return 0 } - }, - numeral: { // 0-9 - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D79E }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return 0 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0x1D7A8 }, - "sans-serif": ch => { return 0x1D7B2 }, - "sans-serif-bold": ch => { return 0x1D7BC }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0 }, - "monospace": ch => { return 0x1D7C6 } - } -}) - -export const variantChar = (ch, variant) => { - const codePoint = ch.codePointAt(0) - const block = 0x40 < codePoint && codePoint < 0x5b - ? "upperCaseLatin" - : 0x60 < codePoint && codePoint < 0x7b - ? "lowerCaseLatin" - : (0x390 < codePoint && codePoint < 0x3AA) || ch === "∇" - ? "upperCaseGreek" - : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5" - ? "lowerCaseGreek" - : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch] - ? "varGreek" - : (0x2F < codePoint && codePoint < 0x3A) - ? "numeral" - : "other" - return block === "other" - ? ch - : String.fromCodePoint(codePoint + offset[block][variant](ch)) -} - -export const smallCaps = Object.freeze({ - a: "ᴀ", - b: "ʙ", - c: "ᴄ", - d: "ᴅ", - e: "ᴇ", - f: "ꜰ", - g: "ɢ", - h: "ʜ", - i: "ɪ", - j: "ᴊ", - k: "ᴋ", - l: "ʟ", - m: "ᴍ", - n: "ɴ", - o: "ᴏ", - p: "ᴘ", - q: "ǫ", - r: "ʀ", - s: "s", - t: "ᴛ", - u: "ᴜ", - v: "ᴠ", - w: "ᴡ", - x: "x", - y: "ʏ", - z: "ᴢ" -}) diff --git a/src/stretchy.js b/src/stretchy.js deleted file mode 100644 index 6877835a..00000000 --- a/src/stretchy.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * This file provides support for building horizontal stretchy elements. - */ - -import mathMLTree from "./mathMLTree" - -const stretchyCodePoint = { - widehat: "^", - widecheck: "ˇ", - widetilde: "~", - wideparen: "⏜", // \u23dc - utilde: "~", - overleftarrow: "\u2190", - underleftarrow: "\u2190", - xleftarrow: "\u2190", - overrightarrow: "\u2192", - underrightarrow: "\u2192", - xrightarrow: "\u2192", - underbrace: "\u23df", - overbrace: "\u23de", - overgroup: "\u23e0", - overparen: "⏜", - undergroup: "\u23e1", - underparen: "\u23dd", - overleftrightarrow: "\u2194", - underleftrightarrow: "\u2194", - xleftrightarrow: "\u2194", - Overrightarrow: "\u21d2", - xRightarrow: "\u21d2", - overleftharpoon: "\u21bc", - xleftharpoonup: "\u21bc", - overrightharpoon: "\u21c0", - xrightharpoonup: "\u21c0", - xLeftarrow: "\u21d0", - xLeftrightarrow: "\u21d4", - xhookleftarrow: "\u21a9", - xhookrightarrow: "\u21aa", - xmapsto: "\u21a6", - xrightharpoondown: "\u21c1", - xleftharpoondown: "\u21bd", - xtwoheadleftarrow: "\u219e", - xtwoheadrightarrow: "\u21a0", - xlongequal: "=", - xrightleftarrows: "\u21c4", - yields: "\u2192", - yieldsLeft: "\u2190", - mesomerism: "\u2194", - longrightharpoonup: "\u21c0", - longleftharpoondown: "\u21bd", - eqrightharpoonup: "\u21c0", - eqleftharpoondown: "\u21bd", - "\\cdrightarrow": "\u2192", - "\\cdleftarrow": "\u2190", - "\\cdlongequal": "=" -} - -const mathMLnode = function(label) { - const child = new mathMLTree.TextNode(stretchyCodePoint[label.slice(1)]) - const node = new mathMLTree.MathNode("mo", [child]) - node.setAttribute("stretchy", "true") - return node -} - -export default { - mathMLnode -} diff --git a/src/symbols.js b/src/symbols.js deleted file mode 100644 index 7ce42f9d..00000000 --- a/src/symbols.js +++ /dev/null @@ -1,971 +0,0 @@ -/** - * This file holds a list of all no-argument functions and single-character - * symbols (like 'a' or ';'). - * - * For each of the symbols, there are two properties they can have: - * - group (required): the ParseNode group type the symbol should have (i.e. - "textord", "mathord", etc). - * - replace: the character that this symbol or function should be - * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi - * character in the main font). - * - * The outermost map in the table indicates what mode the symbols should be - * accepted in (e.g. "math" or "text"). - */ - -// Some of these have a "-token" suffix since these are also used as `ParseNode` -// types for raw text tokens, and we want to avoid conflicts with higher-level -// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by -// looking up the `symbols` map. -export const ATOMS = { - bin: 1, - close: 1, - inner: 1, - open: 1, - punct: 1, - rel: 1 -}; -export const NON_ATOMS = { - "accent-token": 1, - mathord: 1, - "op-token": 1, - spacing: 1, - textord: 1 -}; - -const symbols = { - math: {}, - text: {} -}; -export default symbols; - -/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ -export function defineSymbol(mode, group, replace, name, acceptUnicodeChar) { - symbols[mode][name] = { group, replace }; - - if (acceptUnicodeChar && replace) { - symbols[mode][replace] = symbols[mode][name]; - } -} - -// Some abbreviations for commonly used strings. -// This helps minify the code, and also spotting typos using jshint. - -// modes: -const math = "math"; -const text = "text"; - -// groups: -const accent = "accent-token"; -const bin = "bin"; -const close = "close"; -const inner = "inner"; -const mathord = "mathord"; -const op = "op-token"; -const open = "open"; -const punct = "punct"; -const rel = "rel"; -const spacing = "spacing"; -const textord = "textord"; - -// Now comes the symbol table - -// Relation Symbols -defineSymbol(math, rel, "\u2261", "\\equiv", true); -defineSymbol(math, rel, "\u227a", "\\prec", true); -defineSymbol(math, rel, "\u227b", "\\succ", true); -defineSymbol(math, rel, "\u223c", "\\sim", true); -defineSymbol(math, rel, "\u27c2", "\\perp", true); -defineSymbol(math, rel, "\u2aaf", "\\preceq", true); -defineSymbol(math, rel, "\u2ab0", "\\succeq", true); -defineSymbol(math, rel, "\u2243", "\\simeq", true); -defineSymbol(math, rel, "\u224c", "\\backcong", true); -defineSymbol(math, rel, "|", "\\mid", true); -defineSymbol(math, rel, "\u226a", "\\ll", true); -defineSymbol(math, rel, "\u226b", "\\gg", true); -defineSymbol(math, rel, "\u224d", "\\asymp", true); -defineSymbol(math, rel, "\u2225", "\\parallel"); -defineSymbol(math, rel, "\u22c8", "\\bowtie", true); -defineSymbol(math, rel, "\u2323", "\\smile", true); -defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true); -defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true); -defineSymbol(math, rel, "\u2250", "\\doteq", true); -defineSymbol(math, rel, "\u2322", "\\frown", true); -defineSymbol(math, rel, "\u220b", "\\ni", true); -defineSymbol(math, rel, "\u220c", "\\notni", true); -defineSymbol(math, rel, "\u221d", "\\propto", true); -defineSymbol(math, rel, "\u22a2", "\\vdash", true); -defineSymbol(math, rel, "\u22a3", "\\dashv", true); -defineSymbol(math, rel, "\u220b", "\\owns"); -defineSymbol(math, rel, "\u2258", "\\arceq", true); -defineSymbol(math, rel, "\u2259", "\\wedgeq", true); -defineSymbol(math, rel, "\u225a", "\\veeeq", true); -defineSymbol(math, rel, "\u225b", "\\stareq", true); -defineSymbol(math, rel, "\u225d", "\\eqdef", true); -defineSymbol(math, rel, "\u225e", "\\measeq", true); -defineSymbol(math, rel, "\u225f", "\\questeq", true); -defineSymbol(math, rel, "\u2260", "\\ne", true); -defineSymbol(math, rel, "\u2260", "\\neq"); -// mathtools.sty -defineSymbol(math, rel, "\u2237", "\\dblcolon", true); -defineSymbol(math, rel, "\u2254", "\\coloneqq", true); -defineSymbol(math, rel, "\u2255", "\\eqqcolon", true); -defineSymbol(math, rel, "\u2239", "\\eqcolon", true); -defineSymbol(math, rel, "\u2A74", "\\Coloneqq", true); - -// Punctuation -defineSymbol(math, punct, "\u002e", "\\ldotp"); -defineSymbol(math, punct, "\u00b7", "\\cdotp"); - -// Misc Symbols -defineSymbol(math, textord, "\u0023", "\\#"); -defineSymbol(text, textord, "\u0023", "\\#"); -defineSymbol(math, textord, "\u0026", "\\&"); -defineSymbol(text, textord, "\u0026", "\\&"); -defineSymbol(math, textord, "\u2135", "\\aleph", true); -defineSymbol(math, textord, "\u2200", "\\forall", true); -defineSymbol(math, textord, "\u210f", "\\hbar", true); -defineSymbol(math, textord, "\u2203", "\\exists", true); -defineSymbol(math, textord, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\AA", true); -defineSymbol(text, textord, "Å", "\\AA", true); -defineSymbol(math, textord, "\u2663", "\\clubsuit", true); -defineSymbol(math, textord, "\u2667", "\\varclubsuit", true); -defineSymbol(math, textord, "\u2118", "\\wp", true); -defineSymbol(math, textord, "\u266f", "\\sharp", true); -defineSymbol(math, textord, "\u2662", "\\diamondsuit", true); -defineSymbol(math, textord, "\u2666", "\\vardiamondsuit", true); -defineSymbol(math, textord, "\u211c", "\\Re", true); -defineSymbol(math, textord, "\u2661", "\\heartsuit", true); -defineSymbol(math, textord, "\u2665", "\\varheartsuit", true); -defineSymbol(math, textord, "\u2111", "\\Im", true); -defineSymbol(math, textord, "\u2660", "\\spadesuit", true); -defineSymbol(math, textord, "\u2664", "\\varspadesuit", true); -defineSymbol(math, textord, "\u2640", "\\female", true); -defineSymbol(math, textord, "\u2642", "\\male", true); -defineSymbol(math, textord, "\u00a7", "\\S", true); -defineSymbol(text, textord, "\u00a7", "\\S"); -defineSymbol(math, textord, "\u00b6", "\\P", true); -defineSymbol(text, textord, "\u00b6", "\\P"); -defineSymbol(text, textord, "\u263a", "\\smiley", true); -defineSymbol(math, textord, "\u263a", "\\smiley", true); - -// Math and Text -defineSymbol(math, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\textdagger"); -defineSymbol(math, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\textdaggerdbl"); - -// Large Delimiters -defineSymbol(math, close, "\u23b1", "\\rmoustache", true); -defineSymbol(math, open, "\u23b0", "\\lmoustache", true); -defineSymbol(math, close, "\u27ef", "\\rgroup", true); -defineSymbol(math, open, "\u27ee", "\\lgroup", true); - -// Binary Operators -defineSymbol(math, bin, "\u2213", "\\mp", true); -defineSymbol(math, bin, "\u2296", "\\ominus", true); -defineSymbol(math, bin, "\u228e", "\\uplus", true); -defineSymbol(math, bin, "\u2293", "\\sqcap", true); -defineSymbol(math, bin, "\u2217", "\\ast"); -defineSymbol(math, bin, "\u2294", "\\sqcup", true); -defineSymbol(math, bin, "\u25ef", "\\bigcirc", true); -defineSymbol(math, bin, "\u2219", "\\bullet", true); -defineSymbol(math, bin, "\u2021", "\\ddagger"); -defineSymbol(math, bin, "\u2240", "\\wr", true); -defineSymbol(math, bin, "\u2a3f", "\\amalg"); -defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath - -// Arrow Symbols -defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true); -defineSymbol(math, rel, "\u21d0", "\\Leftarrow", true); -defineSymbol(math, rel, "\u27f8", "\\Longleftarrow", true); -defineSymbol(math, rel, "\u27f6", "\\longrightarrow", true); -defineSymbol(math, rel, "\u21d2", "\\Rightarrow", true); -defineSymbol(math, rel, "\u27f9", "\\Longrightarrow", true); -defineSymbol(math, rel, "\u2194", "\\leftrightarrow", true); -defineSymbol(math, rel, "\u27f7", "\\longleftrightarrow", true); -defineSymbol(math, rel, "\u21d4", "\\Leftrightarrow", true); -defineSymbol(math, rel, "\u27fa", "\\Longleftrightarrow", true); -defineSymbol(math, rel, "\u21a6", "\\mapsto", true); -defineSymbol(math, rel, "\u27fc", "\\longmapsto", true); -defineSymbol(math, rel, "\u2197", "\\nearrow", true); -defineSymbol(math, rel, "\u21a9", "\\hookleftarrow", true); -defineSymbol(math, rel, "\u21aa", "\\hookrightarrow", true); -defineSymbol(math, rel, "\u2198", "\\searrow", true); -defineSymbol(math, rel, "\u21bc", "\\leftharpoonup", true); -defineSymbol(math, rel, "\u21c0", "\\rightharpoonup", true); -defineSymbol(math, rel, "\u2199", "\\swarrow", true); -defineSymbol(math, rel, "\u21bd", "\\leftharpoondown", true); -defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true); -defineSymbol(math, rel, "\u2196", "\\nwarrow", true); -defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true); -defineSymbol(math, mathord, "\u21af", "\\lightning", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); - -// AMS Negated Binary Relations -defineSymbol(math, rel, "\u226e", "\\nless", true); -// Symbol names preceeded by "@" each have a corresponding macro. -defineSymbol(math, rel, "\u2a87", "\\lneq", true); -defineSymbol(math, rel, "\u2268", "\\lneqq", true); -defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq"); -defineSymbol(math, rel, "\u22e6", "\\lnsim", true); -defineSymbol(math, rel, "\u2a89", "\\lnapprox", true); -defineSymbol(math, rel, "\u2280", "\\nprec", true); -// unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e0", "\\npreceq", true); -defineSymbol(math, rel, "\u22e8", "\\precnsim", true); -defineSymbol(math, rel, "\u2ab9", "\\precnapprox", true); -defineSymbol(math, rel, "\u2241", "\\nsim", true); -defineSymbol(math, rel, "\u2224", "\\nmid", true); -defineSymbol(math, rel, "\u2224", "\\nshortmid"); -defineSymbol(math, rel, "\u22ac", "\\nvdash", true); -defineSymbol(math, rel, "\u22ad", "\\nvDash", true); -defineSymbol(math, rel, "\u22ea", "\\ntriangleleft"); -defineSymbol(math, rel, "\u22ec", "\\ntrianglelefteq", true); -defineSymbol(math, rel, "\u2284", "\\nsubset", true); -defineSymbol(math, rel, "\u2285", "\\nsupset", true); -defineSymbol(math, rel, "\u228a", "\\subsetneq", true); -defineSymbol(math, rel, "\u228a\ufe00", "\\varsubsetneq"); -defineSymbol(math, rel, "\u2acb", "\\subsetneqq", true); -defineSymbol(math, rel, "\u2acb\ufe00", "\\varsubsetneqq"); -defineSymbol(math, rel, "\u226f", "\\ngtr", true); -defineSymbol(math, rel, "\u2a88", "\\gneq", true); -defineSymbol(math, rel, "\u2269", "\\gneqq", true); -defineSymbol(math, rel, "\u2269\ufe00", "\\gvertneqq"); -defineSymbol(math, rel, "\u22e7", "\\gnsim", true); -defineSymbol(math, rel, "\u2a8a", "\\gnapprox", true); -defineSymbol(math, rel, "\u2281", "\\nsucc", true); -// unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e1", "\\nsucceq", true); -defineSymbol(math, rel, "\u22e9", "\\succnsim", true); -defineSymbol(math, rel, "\u2aba", "\\succnapprox", true); -// unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u2246", "\\ncong", true); -defineSymbol(math, rel, "\u2226", "\\nparallel", true); -defineSymbol(math, rel, "\u2226", "\\nshortparallel"); -defineSymbol(math, rel, "\u22af", "\\nVDash", true); -defineSymbol(math, rel, "\u22eb", "\\ntriangleright"); -defineSymbol(math, rel, "\u22ed", "\\ntrianglerighteq", true); -defineSymbol(math, rel, "\u228b", "\\supsetneq", true); -defineSymbol(math, rel, "\u228b", "\\varsupsetneq"); -defineSymbol(math, rel, "\u2acc", "\\supsetneqq", true); -defineSymbol(math, rel, "\u2acc\ufe00", "\\varsupsetneqq"); -defineSymbol(math, rel, "\u22ae", "\\nVdash", true); -defineSymbol(math, rel, "\u2ab5", "\\precneqq", true); -defineSymbol(math, rel, "\u2ab6", "\\succneqq", true); -defineSymbol(math, bin, "\u22b4", "\\unlhd"); -defineSymbol(math, bin, "\u22b5", "\\unrhd"); - -// AMS Negated Arrows -defineSymbol(math, rel, "\u219a", "\\nleftarrow", true); -defineSymbol(math, rel, "\u219b", "\\nrightarrow", true); -defineSymbol(math, rel, "\u21cd", "\\nLeftarrow", true); -defineSymbol(math, rel, "\u21cf", "\\nRightarrow", true); -defineSymbol(math, rel, "\u21ae", "\\nleftrightarrow", true); -defineSymbol(math, rel, "\u21ce", "\\nLeftrightarrow", true); - -// AMS Misc -defineSymbol(math, rel, "\u25b3", "\\vartriangle"); -defineSymbol(math, textord, "\u210f", "\\hslash"); -defineSymbol(math, textord, "\u25bd", "\\triangledown"); -defineSymbol(math, textord, "\u25ca", "\\lozenge"); -defineSymbol(math, textord, "\u24c8", "\\circledS"); -defineSymbol(math, textord, "\u00ae", "\\circledR", true); -defineSymbol(text, textord, "\u00ae", "\\circledR"); -defineSymbol(text, textord, "\u00ae", "\\textregistered"); -defineSymbol(math, textord, "\u2221", "\\measuredangle", true); -defineSymbol(math, textord, "\u2204", "\\nexists"); -defineSymbol(math, textord, "\u2127", "\\mho"); -defineSymbol(math, textord, "\u2132", "\\Finv", true); -defineSymbol(math, textord, "\u2141", "\\Game", true); -defineSymbol(math, textord, "\u2035", "\\backprime"); -defineSymbol(math, textord, "\u25b2", "\\blacktriangle"); -defineSymbol(math, textord, "\u25bc", "\\blacktriangledown"); -defineSymbol(math, textord, "\u25a0", "\\blacksquare"); -defineSymbol(math, textord, "\u29eb", "\\blacklozenge"); -defineSymbol(math, textord, "\u2605", "\\bigstar"); -defineSymbol(math, textord, "\u2222", "\\sphericalangle", true); -defineSymbol(math, textord, "\u2201", "\\complement", true); -// unicode-math maps U+F0 to \matheth. We map to AMS function \eth -defineSymbol(math, textord, "\u00f0", "\\eth", true); -defineSymbol(text, textord, "\u00f0", "\u00f0"); -defineSymbol(math, textord, "\u2571", "\\diagup"); -defineSymbol(math, textord, "\u2572", "\\diagdown"); -defineSymbol(math, textord, "\u25a1", "\\square"); -defineSymbol(math, textord, "\u25a1", "\\Box"); -defineSymbol(math, textord, "\u25ca", "\\Diamond"); -// unicode-math maps U+A5 to \mathyen. We map to AMS function \yen -defineSymbol(math, textord, "\u00a5", "\\yen", true); -defineSymbol(text, textord, "\u00a5", "\\yen", true); -defineSymbol(math, textord, "\u2713", "\\checkmark", true); -defineSymbol(text, textord, "\u2713", "\\checkmark"); -defineSymbol(math, textord, "\u2717", "\\ballotx", true); -defineSymbol(text, textord, "\u2717", "\\ballotx"); -defineSymbol(text, textord, "\u2022", "\\textbullet"); - -// AMS Hebrew -defineSymbol(math, textord, "\u2136", "\\beth", true); -defineSymbol(math, textord, "\u2138", "\\daleth", true); -defineSymbol(math, textord, "\u2137", "\\gimel", true); - -// AMS Greek -defineSymbol(math, textord, "\u03dd", "\\digamma", true); -defineSymbol(math, textord, "\u03f0", "\\varkappa"); - -// AMS Delimiters -defineSymbol(math, open, "\u231C", "\\ulcorner", true); -defineSymbol(math, close, "\u231D", "\\urcorner", true); -defineSymbol(math, open, "\u231E", "\\llcorner", true); -defineSymbol(math, close, "\u231F", "\\lrcorner", true); - -// AMS Binary Relations -defineSymbol(math, rel, "\u2266", "\\leqq", true); -defineSymbol(math, rel, "\u2a7d", "\\leqslant", true); -defineSymbol(math, rel, "\u2a95", "\\eqslantless", true); -defineSymbol(math, rel, "\u2272", "\\lesssim", true); -defineSymbol(math, rel, "\u2a85", "\\lessapprox", true); -defineSymbol(math, rel, "\u224a", "\\approxeq", true); -defineSymbol(math, bin, "\u22d6", "\\lessdot"); -defineSymbol(math, rel, "\u22d8", "\\lll", true); -defineSymbol(math, rel, "\u2276", "\\lessgtr", true); -defineSymbol(math, rel, "\u22da", "\\lesseqgtr", true); -defineSymbol(math, rel, "\u2a8b", "\\lesseqqgtr", true); -defineSymbol(math, rel, "\u2251", "\\doteqdot"); -defineSymbol(math, rel, "\u2253", "\\risingdotseq", true); -defineSymbol(math, rel, "\u2252", "\\fallingdotseq", true); -defineSymbol(math, rel, "\u223d", "\\backsim", true); -defineSymbol(math, rel, "\u22cd", "\\backsimeq", true); -defineSymbol(math, rel, "\u2ac5", "\\subseteqq", true); -defineSymbol(math, rel, "\u22d0", "\\Subset", true); -defineSymbol(math, rel, "\u228f", "\\sqsubset", true); -defineSymbol(math, rel, "\u227c", "\\preccurlyeq", true); -defineSymbol(math, rel, "\u22de", "\\curlyeqprec", true); -defineSymbol(math, rel, "\u227e", "\\precsim", true); -defineSymbol(math, rel, "\u2ab7", "\\precapprox", true); -defineSymbol(math, rel, "\u22b2", "\\vartriangleleft"); -defineSymbol(math, rel, "\u22b4", "\\trianglelefteq"); -defineSymbol(math, rel, "\u22a8", "\\vDash", true); -defineSymbol(math, rel, "\u22aa", "\\Vvdash", true); -defineSymbol(math, rel, "\u2323", "\\smallsmile"); -defineSymbol(math, rel, "\u2322", "\\smallfrown"); -defineSymbol(math, rel, "\u224f", "\\bumpeq", true); -defineSymbol(math, rel, "\u224e", "\\Bumpeq", true); -defineSymbol(math, rel, "\u2267", "\\geqq", true); -defineSymbol(math, rel, "\u2a7e", "\\geqslant", true); -defineSymbol(math, rel, "\u2a96", "\\eqslantgtr", true); -defineSymbol(math, rel, "\u2273", "\\gtrsim", true); -defineSymbol(math, rel, "\u2a86", "\\gtrapprox", true); -defineSymbol(math, bin, "\u22d7", "\\gtrdot"); -defineSymbol(math, rel, "\u22d9", "\\ggg", true); -defineSymbol(math, rel, "\u2277", "\\gtrless", true); -defineSymbol(math, rel, "\u22db", "\\gtreqless", true); -defineSymbol(math, rel, "\u2a8c", "\\gtreqqless", true); -defineSymbol(math, rel, "\u2256", "\\eqcirc", true); -defineSymbol(math, rel, "\u2257", "\\circeq", true); -defineSymbol(math, rel, "\u225c", "\\triangleq", true); -defineSymbol(math, rel, "\u223c", "\\thicksim"); -defineSymbol(math, rel, "\u2248", "\\thickapprox"); -defineSymbol(math, rel, "\u2ac6", "\\supseteqq", true); -defineSymbol(math, rel, "\u22d1", "\\Supset", true); -defineSymbol(math, rel, "\u2290", "\\sqsupset", true); -defineSymbol(math, rel, "\u227d", "\\succcurlyeq", true); -defineSymbol(math, rel, "\u22df", "\\curlyeqsucc", true); -defineSymbol(math, rel, "\u227f", "\\succsim", true); -defineSymbol(math, rel, "\u2ab8", "\\succapprox", true); -defineSymbol(math, rel, "\u22b3", "\\vartriangleright"); -defineSymbol(math, rel, "\u22b5", "\\trianglerighteq"); -defineSymbol(math, rel, "\u22a9", "\\Vdash", true); -defineSymbol(math, rel, "\u2223", "\\shortmid"); -defineSymbol(math, rel, "\u2225", "\\shortparallel"); -defineSymbol(math, rel, "\u226c", "\\between", true); -defineSymbol(math, rel, "\u22d4", "\\pitchfork", true); -defineSymbol(math, rel, "\u221d", "\\varpropto"); -defineSymbol(math, rel, "\u25c0", "\\blacktriangleleft"); -// unicode-math says that \therefore is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2234", "\\therefore", true); -defineSymbol(math, rel, "\u220d", "\\backepsilon"); -defineSymbol(math, rel, "\u25b6", "\\blacktriangleright"); -// unicode-math says that \because is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2235", "\\because", true); -defineSymbol(math, rel, "\u22d8", "\\llless"); -defineSymbol(math, rel, "\u22d9", "\\gggtr"); -defineSymbol(math, bin, "\u22b2", "\\lhd"); -defineSymbol(math, bin, "\u22b3", "\\rhd"); -defineSymbol(math, rel, "\u2242", "\\eqsim", true); -defineSymbol(math, rel, "\u22c8", "\\Join"); -defineSymbol(math, rel, "\u2251", "\\Doteq", true); -defineSymbol(math, rel, "\u297d", "\\strictif", true); -defineSymbol(math, rel, "\u297c", "\\strictfi", true); - -// AMS Binary Operators -defineSymbol(math, bin, "\u2214", "\\dotplus", true); -defineSymbol(math, bin, "\u2216", "\\smallsetminus"); -defineSymbol(math, bin, "\u22d2", "\\Cap", true); -defineSymbol(math, bin, "\u22d3", "\\Cup", true); -defineSymbol(math, bin, "\u2a5e", "\\doublebarwedge", true); -defineSymbol(math, bin, "\u229f", "\\boxminus", true); -defineSymbol(math, bin, "\u229e", "\\boxplus", true); -defineSymbol(math, bin, "\u22c7", "\\divideontimes", true); -defineSymbol(math, bin, "\u22c9", "\\ltimes", true); -defineSymbol(math, bin, "\u22ca", "\\rtimes", true); -defineSymbol(math, bin, "\u22cb", "\\leftthreetimes", true); -defineSymbol(math, bin, "\u22cc", "\\rightthreetimes", true); -defineSymbol(math, bin, "\u22cf", "\\curlywedge", true); -defineSymbol(math, bin, "\u22ce", "\\curlyvee", true); -defineSymbol(math, bin, "\u229d", "\\circleddash", true); -defineSymbol(math, bin, "\u229b", "\\circledast", true); -defineSymbol(math, bin, "\u22ba", "\\intercal", true); -defineSymbol(math, bin, "\u22d2", "\\doublecap"); -defineSymbol(math, bin, "\u22d3", "\\doublecup"); -defineSymbol(math, bin, "\u22a0", "\\boxtimes", true); - -// AMS Arrows -// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. -// We'll map it to AMS function \dashrightarrow. It produces the same atom. -defineSymbol(math, rel, "\u21e2", "\\dashrightarrow", true); -// unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21e0", "\\dashleftarrow", true); -defineSymbol(math, rel, "\u21c7", "\\leftleftarrows", true); -defineSymbol(math, rel, "\u21c6", "\\leftrightarrows", true); -defineSymbol(math, rel, "\u21da", "\\Lleftarrow", true); -defineSymbol(math, rel, "\u219e", "\\twoheadleftarrow", true); -defineSymbol(math, rel, "\u21a2", "\\leftarrowtail", true); -defineSymbol(math, rel, "\u21ab", "\\looparrowleft", true); -defineSymbol(math, rel, "\u21cb", "\\leftrightharpoons", true); -defineSymbol(math, rel, "\u21b6", "\\curvearrowleft", true); -// unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21ba", "\\circlearrowleft", true); -defineSymbol(math, rel, "\u21b0", "\\Lsh", true); -defineSymbol(math, rel, "\u21c8", "\\upuparrows", true); -defineSymbol(math, rel, "\u21bf", "\\upharpoonleft", true); -defineSymbol(math, rel, "\u21c3", "\\downharpoonleft", true); -defineSymbol(math, rel, "\u22b6", "\\origof", true); -defineSymbol(math, rel, "\u22b7", "\\imageof", true); -defineSymbol(math, rel, "\u22b8", "\\multimap", true); -defineSymbol(math, rel, "\u21ad", "\\leftrightsquigarrow", true); -defineSymbol(math, rel, "\u21c9", "\\rightrightarrows", true); -defineSymbol(math, rel, "\u21c4", "\\rightleftarrows", true); -defineSymbol(math, rel, "\u21a0", "\\twoheadrightarrow", true); -defineSymbol(math, rel, "\u21a3", "\\rightarrowtail", true); -defineSymbol(math, rel, "\u21ac", "\\looparrowright", true); -defineSymbol(math, rel, "\u21b7", "\\curvearrowright", true); -// unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21bb", "\\circlearrowright", true); -defineSymbol(math, rel, "\u21b1", "\\Rsh", true); -defineSymbol(math, rel, "\u21ca", "\\downdownarrows", true); -defineSymbol(math, rel, "\u21be", "\\upharpoonright", true); -defineSymbol(math, rel, "\u21c2", "\\downharpoonright", true); -defineSymbol(math, rel, "\u21dd", "\\rightsquigarrow", true); -defineSymbol(math, rel, "\u21dd", "\\leadsto"); -defineSymbol(math, rel, "\u21db", "\\Rrightarrow", true); -defineSymbol(math, rel, "\u21be", "\\restriction"); - -defineSymbol(math, textord, "\u2018", "`"); -defineSymbol(math, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\textdollar"); -defineSymbol(math, textord, "%", "\\%"); -defineSymbol(text, textord, "%", "\\%"); -defineSymbol(math, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\textunderscore"); -defineSymbol(text, textord, "\u2423", "\\textvisiblespace", true); -defineSymbol(math, textord, "\u2220", "\\angle", true); -defineSymbol(math, textord, "\u221e", "\\infty", true); -defineSymbol(math, textord, "\u2032", "\\prime"); -defineSymbol(math, textord, "\u25b3", "\\triangle"); -defineSymbol(text, textord, "\u0391", "\\Alpha", true); -defineSymbol(text, textord, "\u0392", "\\Beta", true); -defineSymbol(text, textord, "\u0393", "\\Gamma", true); -defineSymbol(text, textord, "\u0394", "\\Delta", true); -defineSymbol(text, textord, "\u0395", "\\Epsilon", true); -defineSymbol(text, textord, "\u0396", "\\Zeta", true); -defineSymbol(text, textord, "\u0397", "\\Eta", true); -defineSymbol(text, textord, "\u0398", "\\Theta", true); -defineSymbol(text, textord, "\u0399", "\\Iota", true); -defineSymbol(text, textord, "\u039a", "\\Kappa", true); -defineSymbol(text, textord, "\u039b", "\\Lambda", true); -defineSymbol(text, textord, "\u039c", "\\Mu", true); -defineSymbol(text, textord, "\u039d", "\\Nu", true); -defineSymbol(text, textord, "\u039e", "\\Xi", true); -defineSymbol(text, textord, "\u039f", "\\Omicron", true); -defineSymbol(text, textord, "\u03a0", "\\Pi", true); -defineSymbol(text, textord, "\u03a1", "\\Rho", true); -defineSymbol(text, textord, "\u03a3", "\\Sigma", true); -defineSymbol(text, textord, "\u03a4", "\\Tau", true); -defineSymbol(text, textord, "\u03a5", "\\Upsilon", true); -defineSymbol(text, textord, "\u03a6", "\\Phi", true); -defineSymbol(text, textord, "\u03a7", "\\Chi", true); -defineSymbol(text, textord, "\u03a8", "\\Psi", true); -defineSymbol(text, textord, "\u03a9", "\\Omega", true); -defineSymbol(math, mathord, "\u0391", "\\Alpha", true); -defineSymbol(math, mathord, "\u0392", "\\Beta", true); -defineSymbol(math, mathord, "\u0393", "\\Gamma", true); -defineSymbol(math, mathord, "\u0394", "\\Delta", true); -defineSymbol(math, mathord, "\u0395", "\\Epsilon", true); -defineSymbol(math, mathord, "\u0396", "\\Zeta", true); -defineSymbol(math, mathord, "\u0397", "\\Eta", true); -defineSymbol(math, mathord, "\u0398", "\\Theta", true); -defineSymbol(math, mathord, "\u0399", "\\Iota", true); -defineSymbol(math, mathord, "\u039a", "\\Kappa", true); -defineSymbol(math, mathord, "\u039b", "\\Lambda", true); -defineSymbol(math, mathord, "\u039c", "\\Mu", true); -defineSymbol(math, mathord, "\u039d", "\\Nu", true); -defineSymbol(math, mathord, "\u039e", "\\Xi", true); -defineSymbol(math, mathord, "\u039f", "\\Omicron", true); -defineSymbol(math, mathord, "\u03a0", "\\Pi", true); -defineSymbol(math, mathord, "\u03a1", "\\Rho", true); -defineSymbol(math, mathord, "\u03a3", "\\Sigma", true); -defineSymbol(math, mathord, "\u03a4", "\\Tau", true); -defineSymbol(math, mathord, "\u03a5", "\\Upsilon", true); -defineSymbol(math, mathord, "\u03a6", "\\Phi", true); -defineSymbol(math, mathord, "\u03a7", "\\Chi", true); -defineSymbol(math, mathord, "\u03a8", "\\Psi", true); -defineSymbol(math, mathord, "\u03a9", "\\Omega", true); -defineSymbol(math, open, "\u00ac", "\\neg", true); -defineSymbol(math, open, "\u00ac", "\\lnot"); -defineSymbol(math, textord, "\u22a4", "\\top"); -defineSymbol(math, textord, "\u22a5", "\\bot"); -defineSymbol(math, textord, "\u2205", "\\emptyset"); -defineSymbol(math, textord, "\u00f8", "\\varnothing"); -defineSymbol(math, mathord, "\u03b1", "\\alpha", true); -defineSymbol(math, mathord, "\u03b2", "\\beta", true); -defineSymbol(math, mathord, "\u03b3", "\\gamma", true); -defineSymbol(math, mathord, "\u03b4", "\\delta", true); -defineSymbol(math, mathord, "\u03f5", "\\epsilon", true); -defineSymbol(math, mathord, "\u03b6", "\\zeta", true); -defineSymbol(math, mathord, "\u03b7", "\\eta", true); -defineSymbol(math, mathord, "\u03b8", "\\theta", true); -defineSymbol(math, mathord, "\u03b9", "\\iota", true); -defineSymbol(math, mathord, "\u03ba", "\\kappa", true); -defineSymbol(math, mathord, "\u03bb", "\\lambda", true); -defineSymbol(math, mathord, "\u03bc", "\\mu", true); -defineSymbol(math, mathord, "\u03bd", "\\nu", true); -defineSymbol(math, mathord, "\u03be", "\\xi", true); -defineSymbol(math, mathord, "\u03bf", "\\omicron", true); -defineSymbol(math, mathord, "\u03c0", "\\pi", true); -defineSymbol(math, mathord, "\u03c1", "\\rho", true); -defineSymbol(math, mathord, "\u03c3", "\\sigma", true); -defineSymbol(math, mathord, "\u03c4", "\\tau", true); -defineSymbol(math, mathord, "\u03c5", "\\upsilon", true); -defineSymbol(math, mathord, "\u03d5", "\\phi", true); -defineSymbol(math, mathord, "\u03c7", "\\chi", true); -defineSymbol(math, mathord, "\u03c8", "\\psi", true); -defineSymbol(math, mathord, "\u03c9", "\\omega", true); -defineSymbol(math, mathord, "\u03b5", "\\varepsilon", true); -defineSymbol(math, mathord, "\u03d1", "\\vartheta", true); -defineSymbol(math, mathord, "\u03d6", "\\varpi", true); -defineSymbol(math, mathord, "\u03f1", "\\varrho", true); -defineSymbol(math, mathord, "\u03c2", "\\varsigma", true); -defineSymbol(math, mathord, "\u03c6", "\\varphi", true); -defineSymbol(math, mathord, "\u03d8", "\\Coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\varcoppa", true); -defineSymbol(math, mathord, "\u03de", "\\Koppa", true); -defineSymbol(math, mathord, "\u03df", "\\koppa", true); -defineSymbol(math, mathord, "\u03e0", "\\Sampi", true); -defineSymbol(math, mathord, "\u03e1", "\\sampi", true); -defineSymbol(math, mathord, "\u03da", "\\Stigma", true); -defineSymbol(math, mathord, "\u03db", "\\stigma", true); -defineSymbol(math, mathord, "\u2aeb", "\\Bot"); -defineSymbol(math, bin, "\u2217", "\u2217", true); -defineSymbol(math, bin, "+", "+"); -defineSymbol(math, bin, "*", "*"); -defineSymbol(math, bin, "\u2044", "\u2044"); -defineSymbol(math, bin, "\u2212", "-", true); -defineSymbol(math, bin, "\u22c5", "\\cdot", true); -defineSymbol(math, bin, "\u2218", "\\circ", true); -defineSymbol(math, bin, "\u00f7", "\\div", true); -defineSymbol(math, bin, "\u00b1", "\\pm", true); -defineSymbol(math, bin, "\u00d7", "\\times", true); -defineSymbol(math, bin, "\u2229", "\\cap", true); -defineSymbol(math, bin, "\u222a", "\\cup", true); -defineSymbol(math, bin, "\u2216", "\\setminus", true); -defineSymbol(math, bin, "\u2227", "\\land"); -defineSymbol(math, bin, "\u2228", "\\lor"); -defineSymbol(math, bin, "\u2227", "\\wedge", true); -defineSymbol(math, bin, "\u2228", "\\vee", true); -defineSymbol(math, open, "\u27e6", "\\llbracket", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u27e7", "\\rrbracket", true); -defineSymbol(math, open, "\u27e8", "\\langle", true); -defineSymbol(math, open, "|", "\\lvert"); -defineSymbol(math, open, "\u2016", "\\lVert"); -defineSymbol(math, textord, "!", "\\oc"); // cmll package -defineSymbol(math, textord, "?", "\\wn"); -defineSymbol(math, textord, "\u2193", "\\shpos"); -defineSymbol(math, textord, "\u2195", "\\shift"); -defineSymbol(math, textord, "\u2191", "\\shneg"); -defineSymbol(math, close, "?", "?"); -defineSymbol(math, close, "!", "!"); -defineSymbol(math, close, "‼", "‼"); -defineSymbol(math, close, "\u27e9", "\\rangle", true); -defineSymbol(math, close, "|", "\\rvert"); -defineSymbol(math, close, "\u2016", "\\rVert"); -defineSymbol(math, open, "\u2983", "\\lBrace", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u2984", "\\rBrace", true); -defineSymbol(math, rel, "=", "\\equal", true); -defineSymbol(math, rel, ":", ":"); -defineSymbol(math, rel, "\u2248", "\\approx", true); -defineSymbol(math, rel, "\u2245", "\\cong", true); -defineSymbol(math, rel, "\u2265", "\\ge"); -defineSymbol(math, rel, "\u2265", "\\geq", true); -defineSymbol(math, rel, "\u2190", "\\gets"); -defineSymbol(math, rel, ">", "\\gt", true); -defineSymbol(math, rel, "\u2208", "\\in", true); -defineSymbol(math, rel, "\u2209", "\\notin", true); -defineSymbol(math, rel, "\ue020", "\\@not"); -defineSymbol(math, rel, "\u2282", "\\subset", true); -defineSymbol(math, rel, "\u2283", "\\supset", true); -defineSymbol(math, rel, "\u2286", "\\subseteq", true); -defineSymbol(math, rel, "\u2287", "\\supseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteqq"); -defineSymbol(math, rel, "\u2289", "\\nsupseteq", true); -defineSymbol(math, rel, "\u2289", "\\nsupseteqq"); -defineSymbol(math, rel, "\u22a8", "\\models"); -defineSymbol(math, rel, "\u2190", "\\leftarrow", true); -defineSymbol(math, rel, "\u2264", "\\le"); -defineSymbol(math, rel, "\u2264", "\\leq", true); -defineSymbol(math, rel, "<", "\\lt", true); -defineSymbol(math, rel, "\u2192", "\\rightarrow", true); -defineSymbol(math, rel, "\u2192", "\\to"); -defineSymbol(math, rel, "\u2271", "\\ngeq", true); -defineSymbol(math, rel, "\u2271", "\\ngeqq"); -defineSymbol(math, rel, "\u2271", "\\ngeqslant"); -defineSymbol(math, rel, "\u2270", "\\nleq", true); -defineSymbol(math, rel, "\u2270", "\\nleqq"); -defineSymbol(math, rel, "\u2270", "\\nleqslant"); -defineSymbol(math, rel, "\u2aeb", "\\Perp", true); //cmll package -defineSymbol(math, spacing, "\u00a0", "\\ "); -defineSymbol(math, spacing, "\u00a0", "\\space"); -// Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% -defineSymbol(math, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(text, spacing, "\u00a0", "\\ "); -defineSymbol(text, spacing, "\u00a0", " "); -defineSymbol(text, spacing, "\u00a0", "\\space"); -defineSymbol(text, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(math, spacing, null, "\\nobreak"); -defineSymbol(math, spacing, null, "\\allowbreak"); -defineSymbol(math, punct, ",", ","); -defineSymbol(text, punct, ":", ":"); -defineSymbol(math, punct, ";", ";"); -defineSymbol(math, bin, "\u22bc", "\\barwedge", true); -defineSymbol(math, bin, "\u22bb", "\\veebar", true); -defineSymbol(math, bin, "\u2299", "\\odot", true); -defineSymbol(math, bin, "\u2295", "\\oplus", true); -defineSymbol(math, bin, "\u2297", "\\otimes", true); -defineSymbol(math, textord, "\u2202", "\\partial", true); -defineSymbol(math, bin, "\u2298", "\\oslash", true); -defineSymbol(math, bin, "\u229a", "\\circledcirc", true); -defineSymbol(math, bin, "\u22a1", "\\boxdot", true); -defineSymbol(math, bin, "\u25b3", "\\bigtriangleup"); -defineSymbol(math, bin, "\u25bd", "\\bigtriangledown"); -defineSymbol(math, bin, "\u2020", "\\dagger"); -defineSymbol(math, bin, "\u22c4", "\\diamond"); -defineSymbol(math, bin, "\u22c6", "\\star"); -defineSymbol(math, bin, "\u25c3", "\\triangleleft"); -defineSymbol(math, bin, "\u25b9", "\\triangleright"); -defineSymbol(math, open, "{", "\\{"); -defineSymbol(text, textord, "{", "\\{"); -defineSymbol(text, textord, "{", "\\textbraceleft"); -defineSymbol(math, close, "}", "\\}"); -defineSymbol(text, textord, "}", "\\}"); -defineSymbol(text, textord, "}", "\\textbraceright"); -defineSymbol(math, open, "{", "\\lbrace"); -defineSymbol(math, close, "}", "\\rbrace"); -defineSymbol(math, open, "[", "\\lbrack", true); -defineSymbol(text, textord, "[", "\\lbrack", true); -defineSymbol(math, close, "]", "\\rbrack", true); -defineSymbol(text, textord, "]", "\\rbrack", true); -defineSymbol(math, open, "(", "\\lparen", true); -defineSymbol(math, close, ")", "\\rparen", true); -defineSymbol(text, textord, "<", "\\textless", true); // in T1 fontenc -defineSymbol(text, textord, ">", "\\textgreater", true); // in T1 fontenc -defineSymbol(math, open, "\u230a", "\\lfloor", true); -defineSymbol(math, close, "\u230b", "\\rfloor", true); -defineSymbol(math, open, "\u2308", "\\lceil", true); -defineSymbol(math, close, "\u2309", "\\rceil", true); -defineSymbol(math, textord, "\\", "\\backslash"); -defineSymbol(math, textord, "|", "|"); -defineSymbol(math, textord, "|", "\\vert"); -defineSymbol(text, textord, "|", "\\textbar", true); // in T1 fontenc -defineSymbol(math, textord, "\u2016", "\\|"); -defineSymbol(math, textord, "\u2016", "\\Vert"); -defineSymbol(text, textord, "\u2016", "\\textbardbl"); -defineSymbol(text, textord, "~", "\\textasciitilde"); -defineSymbol(text, textord, "\\", "\\textbackslash"); -defineSymbol(text, textord, "^", "\\textasciicircum"); -defineSymbol(math, rel, "\u2191", "\\uparrow", true); -defineSymbol(math, rel, "\u21d1", "\\Uparrow", true); -defineSymbol(math, rel, "\u2193", "\\downarrow", true); -defineSymbol(math, rel, "\u21d3", "\\Downarrow", true); -defineSymbol(math, rel, "\u2195", "\\updownarrow", true); -defineSymbol(math, rel, "\u21d5", "\\Updownarrow", true); -defineSymbol(math, op, "\u2210", "\\coprod"); -defineSymbol(math, op, "\u22c1", "\\bigvee"); -defineSymbol(math, op, "\u22c0", "\\bigwedge"); -defineSymbol(math, op, "\u2a04", "\\biguplus"); -defineSymbol(math, op, "\u22c2", "\\bigcap"); -defineSymbol(math, op, "\u22c3", "\\bigcup"); -defineSymbol(math, op, "\u222b", "\\int"); -defineSymbol(math, op, "\u222b", "\\intop"); -defineSymbol(math, op, "\u222c", "\\iint"); -defineSymbol(math, op, "\u222d", "\\iiint"); -defineSymbol(math, op, "\u220f", "\\prod"); -defineSymbol(math, op, "\u2211", "\\sum"); -defineSymbol(math, op, "\u2a02", "\\bigotimes"); -defineSymbol(math, op, "\u2a01", "\\bigoplus"); -defineSymbol(math, op, "\u2a00", "\\bigodot"); -defineSymbol(math, op, "\u222e", "\\oint"); -defineSymbol(math, op, "\u222f", "\\oiint"); -defineSymbol(math, op, "\u2230", "\\oiiint"); -defineSymbol(math, op, "\u2231", "\\intclockwise"); -defineSymbol(math, op, "\u2232", "\\varointclockwise"); -defineSymbol(math, op, "\u2a0c", "\\iiiint"); -defineSymbol(math, op, "\u2a0d", "\\intbar"); -defineSymbol(math, op, "\u2a0e", "\\intBar"); -defineSymbol(math, op, "\u2a0f", "\\fint"); -defineSymbol(math, op, "\u2a12", "\\rppolint"); -defineSymbol(math, op, "\u2a13", "\\scpolint"); -defineSymbol(math, op, "\u2a15", "\\pointint"); -defineSymbol(math, op, "\u2a16", "\\sqint"); -defineSymbol(math, op, "\u2a17", "\\intlarhk"); -defineSymbol(math, op, "\u2a18", "\\intx"); -defineSymbol(math, op, "\u2a19", "\\intcap"); -defineSymbol(math, op, "\u2a1a", "\\intcup"); -defineSymbol(math, op, "\u2a05", "\\bigsqcap"); -defineSymbol(math, op, "\u2a06", "\\bigsqcup"); -defineSymbol(math, op, "\u222b", "\\smallint"); -defineSymbol(text, inner, "\u2026", "\\textellipsis"); -defineSymbol(math, inner, "\u2026", "\\mathellipsis"); -defineSymbol(text, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u22f0", "\\iddots", true); -defineSymbol(math, inner, "\u22ef", "\\@cdots", true); -defineSymbol(math, inner, "\u22f1", "\\ddots", true); -defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro -defineSymbol(math, accent, "\u02ca", "\\acute"); -defineSymbol(math, accent, "\u0060", "\\grave"); -defineSymbol(math, accent, "\u00a8", "\\ddot"); -defineSymbol(math, accent, "\u20db", "\\dddot"); -defineSymbol(math, accent, "\u20dc", "\\ddddot"); -defineSymbol(math, accent, "\u007e", "\\tilde"); -defineSymbol(math, accent, "\u203e", "\\bar"); -defineSymbol(math, accent, "\u02d8", "\\breve"); -defineSymbol(math, accent, "\u02c7", "\\check"); -defineSymbol(math, accent, "\u005e", "\\hat"); -defineSymbol(math, accent, "\u20d7", "\\vec"); -defineSymbol(math, accent, "\u02d9", "\\dot"); -defineSymbol(math, accent, "\u02da", "\\mathring"); -defineSymbol(math, mathord, "\u0131", "\\imath", true); -defineSymbol(math, mathord, "\u0237", "\\jmath", true); -defineSymbol(math, textord, "\u0131", "\u0131"); -defineSymbol(math, textord, "\u0237", "\u0237"); -defineSymbol(text, textord, "\u0131", "\\i", true); -defineSymbol(text, textord, "\u0237", "\\j", true); -defineSymbol(text, textord, "\u00df", "\\ss", true); -defineSymbol(text, textord, "\u00e6", "\\ae", true); -defineSymbol(text, textord, "\u0153", "\\oe", true); -defineSymbol(text, textord, "\u00f8", "\\o", true); -defineSymbol(math, mathord, "\u00f8", "\\o", true); -defineSymbol(text, textord, "\u00c6", "\\AE", true); -defineSymbol(text, textord, "\u0152", "\\OE", true); -defineSymbol(text, textord, "\u00d8", "\\O", true); -defineSymbol(math, mathord, "\u00d8", "\\O", true); -defineSymbol(text, accent, "\u02ca", "\\'"); // acute -defineSymbol(text, accent, "\u02cb", "\\`"); // grave -defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(text, accent, "\u02dc", "\\~"); // tilde -defineSymbol(text, accent, "\u02c9", "\\="); // macron -defineSymbol(text, accent, "\u02d8", "\\u"); // breve -defineSymbol(text, accent, "\u02d9", "\\."); // dot above -defineSymbol(text, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(text, accent, "\u02da", "\\r"); // ring above -defineSymbol(text, accent, "\u02c7", "\\v"); // caron -defineSymbol(text, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(text, accent, "\u02dd", "\\H"); // double acute -defineSymbol(math, accent, "\u02ca", "\\'"); // acute -defineSymbol(math, accent, "\u02cb", "\\`"); // grave -defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(math, accent, "\u02dc", "\\~"); // tilde -defineSymbol(math, accent, "\u02c9", "\\="); // macron -defineSymbol(math, accent, "\u02d8", "\\u"); // breve -defineSymbol(math, accent, "\u02d9", "\\."); // dot above -defineSymbol(math, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(math, accent, "\u02da", "\\r"); // ring above -defineSymbol(math, accent, "\u02c7", "\\v"); // caron -defineSymbol(math, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(math, accent, "\u02dd", "\\H"); // double acute - -// These ligatures are detected and created in Parser.js's `formLigatures`. -export const ligatures = { - "--": true, - "---": true, - "``": true, - "''": true -}; - -defineSymbol(text, textord, "\u2013", "--", true); -defineSymbol(text, textord, "\u2013", "\\textendash"); -defineSymbol(text, textord, "\u2014", "---", true); -defineSymbol(text, textord, "\u2014", "\\textemdash"); -defineSymbol(text, textord, "\u2018", "`", true); -defineSymbol(text, textord, "\u2018", "\\textquoteleft"); -defineSymbol(text, textord, "\u2019", "'", true); -defineSymbol(text, textord, "\u2019", "\\textquoteright"); -defineSymbol(text, textord, "\u201c", "``", true); -defineSymbol(text, textord, "\u201c", "\\textquotedblleft"); -defineSymbol(text, textord, "\u201d", "''", true); -defineSymbol(text, textord, "\u201d", "\\textquotedblright"); -// \degree from gensymb package -defineSymbol(math, textord, "\u00b0", "\\degree", true); -defineSymbol(text, textord, "\u00b0", "\\degree"); -// \textdegree from inputenc package -defineSymbol(text, textord, "\u00b0", "\\textdegree", true); -// TODO: In LaTeX, \pounds can generate a different character in text and math -// mode, but among our fonts, only Main-Regular defines this character "163". -defineSymbol(math, textord, "\u00a3", "\\pounds"); -defineSymbol(math, textord, "\u00a3", "\\mathsterling", true); -defineSymbol(text, textord, "\u00a3", "\\pounds"); -defineSymbol(text, textord, "\u00a3", "\\textsterling", true); -defineSymbol(math, textord, "\u2720", "\\maltese"); -defineSymbol(text, textord, "\u2720", "\\maltese"); -defineSymbol(math, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\texteuro"); -defineSymbol(math, textord, "\u00a9", "\\copyright", true); -defineSymbol(text, textord, "\u00a9", "\\textcopyright"); - -// Italic Greek -defineSymbol(math, textord, "𝛤", "\\varGamma"); -defineSymbol(math, textord, "𝛥", "\\varDelta"); -defineSymbol(math, textord, "𝛩", "\\varTheta"); -defineSymbol(math, textord, "𝛬", "\\varLambda"); -defineSymbol(math, textord, "𝛯", "\\varXi"); -defineSymbol(math, textord, "𝛱", "\\varPi"); -defineSymbol(math, textord, "𝛴", "\\varSigma"); -defineSymbol(math, textord, "𝛶", "\\varUpsilon"); -defineSymbol(math, textord, "𝛷", "\\varPhi"); -defineSymbol(math, textord, "𝛹", "\\varPsi"); -defineSymbol(math, textord, "𝛺", "\\varOmega"); -defineSymbol(text, textord, "𝛤", "\\varGamma"); -defineSymbol(text, textord, "𝛥", "\\varDelta"); -defineSymbol(text, textord, "𝛩", "\\varTheta"); -defineSymbol(text, textord, "𝛬", "\\varLambda"); -defineSymbol(text, textord, "𝛯", "\\varXi"); -defineSymbol(text, textord, "𝛱", "\\varPi"); -defineSymbol(text, textord, "𝛴", "\\varSigma"); -defineSymbol(text, textord, "𝛶", "\\varUpsilon"); -defineSymbol(text, textord, "𝛷", "\\varPhi"); -defineSymbol(text, textord, "𝛹", "\\varPsi"); -defineSymbol(text, textord, "𝛺", "\\varOmega"); - - -// There are lots of symbols which are the same, so we add them in afterwards. -// All of these are textords in math mode -const mathTextSymbols = '0123456789/@."'; -for (let i = 0; i < mathTextSymbols.length; i++) { - const ch = mathTextSymbols.charAt(i); - defineSymbol(math, textord, ch, ch); -} - -// All of these are textords in text mode -const textSymbols = '0123456789!@*()-=+";:?/.,'; -for (let i = 0; i < textSymbols.length; i++) { - const ch = textSymbols.charAt(i); - defineSymbol(text, textord, ch, ch); -} - -// All of these are textords in text mode, and mathords in math mode -const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -for (let i = 0; i < letters.length; i++) { - const ch = letters.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// Some more letters in Unicode Basic Multilingual Plane. -const narrow = "ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ"; -for (let i = 0; i < narrow.length; i++) { - const ch = narrow.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// The next loop loads wide (surrogate pair) characters. -// We support some letters in the Unicode range U+1D400 to U+1D7FF, -// Mathematical Alphanumeric Symbols. -let wideChar = ""; -for (let i = 0; i < letters.length; i++) { - // The hex numbers in the next line are a surrogate pair. - // 0xD835 is the high surrogate for all letters in the range we support. - // 0xDC00 is the low surrogate for bold A. - wideChar = String.fromCharCode(0xd835, 0xdc00 + i); // A-Z a-z bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc34 + i); // A-Z a-z italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc68 + i); // A-Z a-z bold italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd04 + i); // A-Z a-z Fractur - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdda0 + i); // A-Z a-z sans-serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xddd4 + i); // A-Z a-z sans bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde08 + i); // A-Z a-z sans italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde70 + i); // A-Z a-z monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd38 + i); // A-Z a-z double struck - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - const ch = letters.charAt(i); - wideChar = String.fromCharCode(0xd835, 0xdc9c + i); // A-Z a-z calligraphic - defineSymbol(math, mathord, ch, wideChar); - defineSymbol(text, textord, ch, wideChar); -} - -// Next, some wide character numerals -for (let i = 0; i < 10; i++) { - wideChar = String.fromCharCode(0xd835, 0xdfce + i); // 0-9 bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfe2 + i); // 0-9 sans serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfec + i); // 0-9 bold sans - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdff6 + i); // 0-9 monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); -} diff --git a/src/tree.js b/src/tree.js deleted file mode 100644 index 5ae654ba..00000000 --- a/src/tree.js +++ /dev/null @@ -1,52 +0,0 @@ -import utils from "./utils"; - -/** - * This node represents a document fragment, which contains elements, but when - * placed into the DOM doesn't have any representation itself. It only contains - * children and doesn't have any DOM node properties. - */ -export class DocumentFragment { - constructor(children) { - this.children = children; - this.classes = []; - this.style = {}; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - /** Convert the fragment into a node. */ - toNode() { - const frag = document.createDocumentFragment(); - - for (let i = 0; i < this.children.length; i++) { - frag.appendChild(this.children[i].toNode()); - } - - return frag; - } - - /** Convert the fragment into HTML markup. */ - toMarkup() { - let markup = ""; - - // Simply concatenate the markup for the children together. - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText. Applies to - * MathDomNode's only. - */ - toText() { - // To avoid this, we would subclass documentFragment separately for - // MathML, but polyfills for subclassing is expensive per PR 1469. - const toText = (child) => child.toText(); - return this.children.map(toText).join(""); - } -} diff --git a/src/unicodeAccents.js b/src/unicodeAccents.js deleted file mode 100644 index 36844133..00000000 --- a/src/unicodeAccents.js +++ /dev/null @@ -1,16 +0,0 @@ -// Mapping of Unicode accent characters to their LaTeX equivalent in text and -// math mode (when they exist). -export default { - "\u0301": { text: "\\'", math: "\\acute" }, - "\u0300": { text: "\\`", math: "\\grave" }, - "\u0308": { text: '\\"', math: "\\ddot" }, - "\u0303": { text: "\\~", math: "\\tilde" }, - "\u0304": { text: "\\=", math: "\\bar" }, - "\u0306": { text: "\\u", math: "\\breve" }, - "\u030c": { text: "\\v", math: "\\check" }, - "\u0302": { text: "\\^", math: "\\hat" }, - "\u0307": { text: "\\.", math: "\\dot" }, - "\u030a": { text: "\\r", math: "\\mathring" }, - "\u030b": { text: "\\H" }, - '\u0327': { text: '\\c' } -}; diff --git a/src/unicodeScripts.js b/src/unicodeScripts.js deleted file mode 100644 index 13e825af..00000000 --- a/src/unicodeScripts.js +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file defines the Unicode scripts and script families that we - * support. To add new scripts or families, just add a new entry to the - * scriptData array below. Adding scripts to the scriptData array allows - * characters from that script to appear in \text{} environments. - */ - -/** - * Each script or script family has a name and an array of blocks. - * Each block is an array of two numbers which specify the start and - * end points (inclusive) of a block of Unicode codepoints. - -/** - * Unicode block data for the families of scripts we support in \text{}. - * Scripts only need to appear here if they do not have font metrics. - */ -const scriptData = [ - { - // Latin characters beyond the Latin-1 characters we have metrics for. - // Needed for Czech, Hungarian and Turkish text, for example. - name: "latin", - blocks: [ - [0x0100, 0x024f], // Latin Extended-A and Latin Extended-B - [0x0300, 0x036f] // Combining Diacritical marks - ] - }, - { - // The Cyrillic script used by Russian and related languages. - // A Cyrillic subset used to be supported as explicitly defined - // symbols in symbols.js - name: "cyrillic", - blocks: [[0x0400, 0x04ff]] - }, - { - // Armenian - name: "armenian", - blocks: [[0x0530, 0x058f]] - }, - { - // The Brahmic scripts of South and Southeast Asia - // Devanagari (0900–097F) - // Bengali (0980–09FF) - // Gurmukhi (0A00–0A7F) - // Gujarati (0A80–0AFF) - // Oriya (0B00–0B7F) - // Tamil (0B80–0BFF) - // Telugu (0C00–0C7F) - // Kannada (0C80–0CFF) - // Malayalam (0D00–0D7F) - // Sinhala (0D80–0DFF) - // Thai (0E00–0E7F) - // Lao (0E80–0EFF) - // Tibetan (0F00–0FFF) - // Myanmar (1000–109F) - name: "brahmic", - blocks: [[0x0900, 0x109f]] - }, - { - name: "georgian", - blocks: [[0x10a0, 0x10ff]] - }, - { - // Chinese and Japanese. - // The "k" in cjk is for Korean, but we've separated Korean out - name: "cjk", - blocks: [ - [0x3000, 0x30ff], // CJK symbols and punctuation, Hiragana, Katakana - [0x4e00, 0x9faf], // CJK ideograms - [0xff00, 0xff60] // Fullwidth punctuation - // TODO: add halfwidth Katakana and Romanji glyphs - ] - }, - { - // Korean - name: "hangul", - blocks: [[0xac00, 0xd7af]] - } -]; - -/** - * Given a codepoint, return the name of the script or script family - * it is from, or null if it is not part of a known block - */ -export function scriptFromCodepoint(codepoint) { - for (let i = 0; i < scriptData.length; i++) { - const script = scriptData[i]; - for (let i = 0; i < script.blocks.length; i++) { - const block = script.blocks[i]; - if (codepoint >= block[0] && codepoint <= block[1]) { - return script.name; - } - } - } - return null; -} - -/** - * A flattened version of all the supported blocks in a single array. - * This is an optimization to make supportedCodepoint() fast. - */ -const allBlocks = []; -scriptData.forEach((s) => s.blocks.forEach((b) => allBlocks.push(...b))); - -/** - * Given a codepoint, return true if it falls within one of the - * scripts or script families defined above and false otherwise. - * - * Micro benchmarks shows that this is faster than - * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() - * in Firefox, Chrome and Node. - */ -export function supportedCodepoint(codepoint) { - for (let i = 0; i < allBlocks.length; i += 2) { - if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { - return true; - } - } - return false; -} diff --git a/src/unicodeSupOrSub.js b/src/unicodeSupOrSub.js deleted file mode 100644 index 7588582a..00000000 --- a/src/unicodeSupOrSub.js +++ /dev/null @@ -1,108 +0,0 @@ -// Helpers for Parser.js handling of Unicode (sub|super)script characters. - -export const unicodeSubRegEx = /^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/ - -export const uSubsAndSups = Object.freeze({ - '₊': '+', - '₋': '-', - '₌': '=', - '₍': '(', - '₎': ')', - '₀': '0', - '₁': '1', - '₂': '2', - '₃': '3', - '₄': '4', - '₅': '5', - '₆': '6', - '₇': '7', - '₈': '8', - '₉': '9', - '\u2090': 'a', - '\u2091': 'e', - '\u2095': 'h', - '\u1D62': 'i', - '\u2C7C': 'j', - '\u2096': 'k', - '\u2097': 'l', - '\u2098': 'm', - '\u2099': 'n', - '\u2092': 'o', - '\u209A': 'p', - '\u1D63': 'r', - '\u209B': 's', - '\u209C': 't', - '\u1D64': 'u', - '\u1D65': 'v', - '\u2093': 'x', - '\u1D66': 'β', - '\u1D67': 'γ', - '\u1D68': 'ρ', - '\u1D69': '\u03d5', - '\u1D6A': 'χ', - '⁺': '+', - '⁻': '-', - '⁼': '=', - '⁽': '(', - '⁾': ')', - '⁰': '0', - '¹': '1', - '²': '2', - '³': '3', - '⁴': '4', - '⁵': '5', - '⁶': '6', - '⁷': '7', - '⁸': '8', - '⁹': '9', - '\u1D2C': 'A', - '\u1D2E': 'B', - '\u1D30': 'D', - '\u1D31': 'E', - '\u1D33': 'G', - '\u1D34': 'H', - '\u1D35': 'I', - '\u1D36': 'J', - '\u1D37': 'K', - '\u1D38': 'L', - '\u1D39': 'M', - '\u1D3A': 'N', - '\u1D3C': 'O', - '\u1D3E': 'P', - '\u1D3F': 'R', - '\u1D40': 'T', - '\u1D41': 'U', - '\u2C7D': 'V', - '\u1D42': 'W', - '\u1D43': 'a', - '\u1D47': 'b', - '\u1D9C': 'c', - '\u1D48': 'd', - '\u1D49': 'e', - '\u1DA0': 'f', - '\u1D4D': 'g', - '\u02B0': 'h', - '\u2071': 'i', - '\u02B2': 'j', - '\u1D4F': 'k', - '\u02E1': 'l', - '\u1D50': 'm', - '\u207F': 'n', - '\u1D52': 'o', - '\u1D56': 'p', - '\u02B3': 'r', - '\u02E2': 's', - '\u1D57': 't', - '\u1D58': 'u', - '\u1D5B': 'v', - '\u02B7': 'w', - '\u02E3': 'x', - '\u02B8': 'y', - '\u1DBB': 'z', - '\u1D5D': 'β', - '\u1D5E': 'γ', - '\u1D5F': 'δ', - '\u1D60': '\u03d5', - '\u1D61': 'χ', - '\u1DBF': 'θ' -}) diff --git a/src/unicodeSymbolBuilder.js b/src/unicodeSymbolBuilder.js deleted file mode 100644 index 3be3f5a0..00000000 --- a/src/unicodeSymbolBuilder.js +++ /dev/null @@ -1,31 +0,0 @@ -// This is an internal module, not part of the Temml distribution, -// whose purpose is to generate `unicodeSymbols` for Parser.js -// In this way, only this module, and not the distribution/browser, -// needs String's normalize function. -import * as accents from "./unicodeAccents"; - -const result = {}; -const letters = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "αβγδεϵζηθϑικλμνξοπϖρϱςστυφϕχψωΓΔΘΛΞΠΣΥΦΨΩ"; -for (const letter of letters) { - for (const accent of Object.getOwnPropertyNames(accents)) { - const combined = letter + accent; - const normalized = combined.normalize("NFC"); - if (normalized.length === 1) { - result[normalized] = combined; - } - for (const accent2 of Object.getOwnPropertyNames(accents)) { - if (accent === accent2) { - continue; - } - const combined2 = combined + accent2; - const normalized2 = combined2.normalize("NFC"); - if (normalized2.length === 1) { - result[normalized2] = combined2; - } - } - } -} - -export default result; diff --git a/src/unicodeSymbols.js b/src/unicodeSymbols.js deleted file mode 100644 index 56dbcc5d..00000000 --- a/src/unicodeSymbols.js +++ /dev/null @@ -1,320 +0,0 @@ -export default { - "á": "á", - "à": "à", - "ä": "ä", - "ǟ": "ǟ", - "ã": "ã", - "ā": "ā", - "ă": "ă", - "ắ": "ắ", - "ằ": "ằ", - "ẵ": "ẵ", - "ǎ": "ǎ", - "â": "â", - "ấ": "ấ", - "ầ": "ầ", - "ẫ": "ẫ", - "ȧ": "ȧ", - "ǡ": "ǡ", - "å": "å", - "ǻ": "ǻ", - "ḃ": "ḃ", - "ć": "ć", - "č": "č", - "ĉ": "ĉ", - "ċ": "ċ", - "ď": "ď", - "ḋ": "ḋ", - "é": "é", - "è": "è", - "ë": "ë", - "ẽ": "ẽ", - "ē": "ē", - "ḗ": "ḗ", - "ḕ": "ḕ", - "ĕ": "ĕ", - "ě": "ě", - "ê": "ê", - "ế": "ế", - "ề": "ề", - "ễ": "ễ", - "ė": "ė", - "ḟ": "ḟ", - "ǵ": "ǵ", - "ḡ": "ḡ", - "ğ": "ğ", - "ǧ": "ǧ", - "ĝ": "ĝ", - "ġ": "ġ", - "ḧ": "ḧ", - "ȟ": "ȟ", - "ĥ": "ĥ", - "ḣ": "ḣ", - "í": "í", - "ì": "ì", - "ï": "ï", - "ḯ": "ḯ", - "ĩ": "ĩ", - "ī": "ī", - "ĭ": "ĭ", - "ǐ": "ǐ", - "î": "î", - "ǰ": "ǰ", - "ĵ": "ĵ", - "ḱ": "ḱ", - "ǩ": "ǩ", - "ĺ": "ĺ", - "ľ": "ľ", - "ḿ": "ḿ", - "ṁ": "ṁ", - "ń": "ń", - "ǹ": "ǹ", - "ñ": "ñ", - "ň": "ň", - "ṅ": "ṅ", - "ó": "ó", - "ò": "ò", - "ö": "ö", - "ȫ": "ȫ", - "õ": "õ", - "ṍ": "ṍ", - "ṏ": "ṏ", - "ȭ": "ȭ", - "ō": "ō", - "ṓ": "ṓ", - "ṑ": "ṑ", - "ŏ": "ŏ", - "ǒ": "ǒ", - "ô": "ô", - "ố": "ố", - "ồ": "ồ", - "ỗ": "ỗ", - "ȯ": "ȯ", - "ȱ": "ȱ", - "ő": "ő", - "ṕ": "ṕ", - "ṗ": "ṗ", - "ŕ": "ŕ", - "ř": "ř", - "ṙ": "ṙ", - "ś": "ś", - "ṥ": "ṥ", - "š": "š", - "ṧ": "ṧ", - "ŝ": "ŝ", - "ṡ": "ṡ", - "ẗ": "ẗ", - "ť": "ť", - "ṫ": "ṫ", - "ú": "ú", - "ù": "ù", - "ü": "ü", - "ǘ": "ǘ", - "ǜ": "ǜ", - "ǖ": "ǖ", - "ǚ": "ǚ", - "ũ": "ũ", - "ṹ": "ṹ", - "ū": "ū", - "ṻ": "ṻ", - "ŭ": "ŭ", - "ǔ": "ǔ", - "û": "û", - "ů": "ů", - "ű": "ű", - "ṽ": "ṽ", - "ẃ": "ẃ", - "ẁ": "ẁ", - "ẅ": "ẅ", - "ŵ": "ŵ", - "ẇ": "ẇ", - "ẘ": "ẘ", - "ẍ": "ẍ", - "ẋ": "ẋ", - "ý": "ý", - "ỳ": "ỳ", - "ÿ": "ÿ", - "ỹ": "ỹ", - "ȳ": "ȳ", - "ŷ": "ŷ", - "ẏ": "ẏ", - "ẙ": "ẙ", - "ź": "ź", - "ž": "ž", - "ẑ": "ẑ", - "ż": "ż", - "Á": "Á", - "À": "À", - "Ä": "Ä", - "Ǟ": "Ǟ", - "Ã": "Ã", - "Ā": "Ā", - "Ă": "Ă", - "Ắ": "Ắ", - "Ằ": "Ằ", - "Ẵ": "Ẵ", - "Ǎ": "Ǎ", - "Â": "Â", - "Ấ": "Ấ", - "Ầ": "Ầ", - "Ẫ": "Ẫ", - "Ȧ": "Ȧ", - "Ǡ": "Ǡ", - "Å": "Å", - "Ǻ": "Ǻ", - "Ḃ": "Ḃ", - "Ć": "Ć", - "Č": "Č", - "Ĉ": "Ĉ", - "Ċ": "Ċ", - "Ď": "Ď", - "Ḋ": "Ḋ", - "É": "É", - "È": "È", - "Ë": "Ë", - "Ẽ": "Ẽ", - "Ē": "Ē", - "Ḗ": "Ḗ", - "Ḕ": "Ḕ", - "Ĕ": "Ĕ", - "Ě": "Ě", - "Ê": "Ê", - "Ế": "Ế", - "Ề": "Ề", - "Ễ": "Ễ", - "Ė": "Ė", - "Ḟ": "Ḟ", - "Ǵ": "Ǵ", - "Ḡ": "Ḡ", - "Ğ": "Ğ", - "Ǧ": "Ǧ", - "Ĝ": "Ĝ", - "Ġ": "Ġ", - "Ḧ": "Ḧ", - "Ȟ": "Ȟ", - "Ĥ": "Ĥ", - "Ḣ": "Ḣ", - "Í": "Í", - "Ì": "Ì", - "Ï": "Ï", - "Ḯ": "Ḯ", - "Ĩ": "Ĩ", - "Ī": "Ī", - "Ĭ": "Ĭ", - "Ǐ": "Ǐ", - "Î": "Î", - "İ": "İ", - "Ĵ": "Ĵ", - "Ḱ": "Ḱ", - "Ǩ": "Ǩ", - "Ĺ": "Ĺ", - "Ľ": "Ľ", - "Ḿ": "Ḿ", - "Ṁ": "Ṁ", - "Ń": "Ń", - "Ǹ": "Ǹ", - "Ñ": "Ñ", - "Ň": "Ň", - "Ṅ": "Ṅ", - "Ó": "Ó", - "Ò": "Ò", - "Ö": "Ö", - "Ȫ": "Ȫ", - "Õ": "Õ", - "Ṍ": "Ṍ", - "Ṏ": "Ṏ", - "Ȭ": "Ȭ", - "Ō": "Ō", - "Ṓ": "Ṓ", - "Ṑ": "Ṑ", - "Ŏ": "Ŏ", - "Ǒ": "Ǒ", - "Ô": "Ô", - "Ố": "Ố", - "Ồ": "Ồ", - "Ỗ": "Ỗ", - "Ȯ": "Ȯ", - "Ȱ": "Ȱ", - "Ő": "Ő", - "Ṕ": "Ṕ", - "Ṗ": "Ṗ", - "Ŕ": "Ŕ", - "Ř": "Ř", - "Ṙ": "Ṙ", - "Ś": "Ś", - "Ṥ": "Ṥ", - "Š": "Š", - "Ṧ": "Ṧ", - "Ŝ": "Ŝ", - "Ṡ": "Ṡ", - "Ť": "Ť", - "Ṫ": "Ṫ", - "Ú": "Ú", - "Ù": "Ù", - "Ü": "Ü", - "Ǘ": "Ǘ", - "Ǜ": "Ǜ", - "Ǖ": "Ǖ", - "Ǚ": "Ǚ", - "Ũ": "Ũ", - "Ṹ": "Ṹ", - "Ū": "Ū", - "Ṻ": "Ṻ", - "Ŭ": "Ŭ", - "Ǔ": "Ǔ", - "Û": "Û", - "Ů": "Ů", - "Ű": "Ű", - "Ṽ": "Ṽ", - "Ẃ": "Ẃ", - "Ẁ": "Ẁ", - "Ẅ": "Ẅ", - "Ŵ": "Ŵ", - "Ẇ": "Ẇ", - "Ẍ": "Ẍ", - "Ẋ": "Ẋ", - "Ý": "Ý", - "Ỳ": "Ỳ", - "Ÿ": "Ÿ", - "Ỹ": "Ỹ", - "Ȳ": "Ȳ", - "Ŷ": "Ŷ", - "Ẏ": "Ẏ", - "Ź": "Ź", - "Ž": "Ž", - "Ẑ": "Ẑ", - "Ż": "Ż", - "ά": "ά", - "ὰ": "ὰ", - "ᾱ": "ᾱ", - "ᾰ": "ᾰ", - "έ": "έ", - "ὲ": "ὲ", - "ή": "ή", - "ὴ": "ὴ", - "ί": "ί", - "ὶ": "ὶ", - "ϊ": "ϊ", - "ΐ": "ΐ", - "ῒ": "ῒ", - "ῑ": "ῑ", - "ῐ": "ῐ", - "ό": "ό", - "ὸ": "ὸ", - "ύ": "ύ", - "ὺ": "ὺ", - "ϋ": "ϋ", - "ΰ": "ΰ", - "ῢ": "ῢ", - "ῡ": "ῡ", - "ῠ": "ῠ", - "ώ": "ώ", - "ὼ": "ὼ", - "Ύ": "Ύ", - "Ὺ": "Ὺ", - "Ϋ": "Ϋ", - "Ῡ": "Ῡ", - "Ῠ": "Ῠ", - "Ώ": "Ώ", - "Ὼ": "Ὼ" -}; diff --git a/src/units.js b/src/units.js deleted file mode 100644 index 86ca71d0..00000000 --- a/src/units.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * This file does conversion between units. In particular, it provides - * calculateSize to convert other units into CSS units. - */ - -import ParseError from "./ParseError" -import utils from "./utils" - -const ptPerUnit = { - // Convert to CSS (Postscipt) points, not TeX points - // https://en.wikibooks.org/wiki/LaTeX/Lengths and - // https://tex.stackexchange.com/a/8263 - pt: 800 / 803, // convert TeX point to CSS (Postscript) point - pc: (12 * 800) / 803, // pica - dd: ((1238 / 1157) * 800) / 803, // didot - cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot) - nd: ((685 / 642) * 800) / 803, // new didot - nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot) - sp: ((1 / 65536) * 800) / 803, // scaled point (TeX's internal smallest unit) - mm: (25.4 / 72), - cm: (2.54 / 72), - in: (1 / 72), - px: (96 / 72) -} - -/** - * Determine whether the specified unit (either a string defining the unit - * or a "size" parse node containing a unit field) is valid. - */ -const validUnits = [ - "em", - "ex", - "mu", - "pt", - "mm", - "cm", - "in", - "px", - "bp", - "pc", - "dd", - "cc", - "nd", - "nc", - "sp" -] - -export const validUnit = function(unit) { - if (typeof unit !== "string") { - unit = unit.unit - } - return validUnits.indexOf(unit) > -1 -} - -export const emScale = styleLevel => { - const scriptLevel = Math.max(styleLevel - 1, 0) - return [1, 0.7, 0.5][scriptLevel] -}; - -/* - * Convert a "size" parse node (with numeric "number" and string "unit" fields, - * as parsed by functions.js argType "size") into a CSS value. - */ -export const calculateSize = function(sizeValue, style) { - let number = sizeValue.number - if (style.maxSize[0] < 0 && number > 0) { - return { number: 0, unit: "em" } - } - const unit = sizeValue.unit - switch (unit) { - case "mm": - case "cm": - case "in": - case "px": { - const numInCssPts = number * ptPerUnit[unit]; - if (numInCssPts > style.maxSize[1]) { - return { number: style.maxSize[1], unit: "pt" } - } - return { number, unit }; // absolute CSS units. - } - case "em": - case "ex": { - // In TeX, em and ex do not change size in \scriptstyle. - if (unit === "ex") { number *= 0.431 } - number = Math.min(number / emScale(style.level), style.maxSize[0]) - return { number: utils.round(number), unit: "em" }; - } - case "bp": { - if (number > style.maxSize[1]) { number = style.maxSize[1] } - return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch). - } - case "pt": - case "pc": - case "dd": - case "cc": - case "nd": - case "nc": - case "sp": { - number = Math.min(number * ptPerUnit[unit], style.maxSize[1]) - return { number: utils.round(number), unit: "pt" } - } - case "mu": { - number = Math.min(number / 18, style.maxSize[0]) - return { number: utils.round(number), unit: "em" } - } - default: - throw new ParseError("Invalid unit: '" + unit + "'") - } -} diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index ab6a57ae..00000000 --- a/src/utils.js +++ /dev/null @@ -1,160 +0,0 @@ -// -/** - * This file contains a list of utility functions which are useful in other - * files. - */ - -/** - * Return whether an element is contained in a list - */ -const contains = function(list, elem) { - return list.indexOf(elem) !== -1; -}; - -/** - * Provide a default value if a setting is undefined - */ -const deflt = function(setting, defaultIfUndefined) { - return setting === undefined ? defaultIfUndefined : setting; -}; - -// hyphenate and escape adapted from Facebook's React under Apache 2 license - -const uppercase = /([A-Z])/g; -const hyphenate = function(str) { - return str.replace(uppercase, "-$1").toLowerCase(); -}; - -const ESCAPE_LOOKUP = { - "&": "&", - ">": ">", - "<": "<", - '"': """, - "'": "'" -}; - -const ESCAPE_REGEX = /[&><"']/g; - -/** - * Escapes text to prevent scripting attacks. - */ -function escape(text) { - return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); -} - -/** - * Sometimes we want to pull out the innermost element of a group. In most - * cases, this will just be the group itself, but when ordgroups and colors have - * a single element, we want to pull that out. - */ -const getBaseElem = function(group) { - if (group.type === "ordgroup") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "color") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "font") { - return getBaseElem(group.body); - } else { - return group; - } -}; - -/** - * TeXbook algorithms often reference "character boxes", which are simply groups - * with a single character in them. To decide if something is a character box, - * we find its innermost group, and see if it is a single character. - */ -const isCharacterBox = function(group) { - const baseElem = getBaseElem(group); - - // These are all the types of groups which hold single characters - return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom" -}; - -export const assert = function(value) { - if (!value) { - throw new Error("Expected non-null, but got " + String(value)); - } - return value; -}; - -/** - * Return the protocol of a URL, or "_relative" if the URL does not specify a - * protocol (and thus is relative). - */ -export const protocolFromUrl = function(url) { - const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); - return protocol != null ? protocol[1] : "_relative"; -}; - -/** - * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook - * gives an acceptable rounding error of 100sp (which would be the nearest - * 1/6551.6em with our ptPerEm = 10): - * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69 - */ -const round = function(n) { - return +n.toFixed(4); -}; - -const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - const mtext = mrow.children[0] - if (!mtext.attributes || mtext.type !== "mtext") { return mrow } - const variant = mtext.attributes.mathvariant || "" - for (let i = 1; i < mrow.children.length; i++) { - // Check each child and, if possible, copy the character into child[0]. - const localVariant = mrow.children[i].attributes.mathvariant || "" - if (mrow.children[i].type === "mrow") { - const childRow = mrow.children[i] - for (let j = 0; j < childRow.children.length; j++) { - // We'll also check the children of a mrow. One level only. No recursion. - const childVariant = childRow.children[j].attributes.mathvariant || "" - if (childVariant !== variant || childRow.children[j].type !== "mtext") { - return mrow // At least one element cannot be consolidated. Get out. - } else { - mtext.children[0].text += childRow.children[j].children[0].text - } - } - } else if (localVariant !== variant || mrow.children[i].type !== "mtext") { - return mrow - } else { - mtext.children[0].text += mrow.children[i].children[0].text - } - } - // Since we have gotten here, the text has been loaded into a single mtext node. - // Next, consolidate the children into a single element. - mtext.children.splice(1, mtext.children.length - 1) - // Firefox does not render a space at either end of an string. - // To get proper rendering, we replace leading or trailing spaces with no-break spaces. - if (mtext.children[0].text.charAt(0) === " ") { - mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1) - } - const L = mtext.children[0].text.length - if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") { - mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0" - } - return mtext -} - -export default { - contains, - deflt, - escape, - hyphenate, - getBaseElem, - isCharacterBox, - protocolFromUrl, - round, - consolidateText -}; diff --git a/src/variant.js b/src/variant.js deleted file mode 100644 index aff58e5b..00000000 --- a/src/variant.js +++ /dev/null @@ -1,103 +0,0 @@ -import symbols from "./symbols"; - -/** - * Maps TeX font commands to "mathvariant" attribute in buildMathML.js - */ -const fontMap = { - // styles - mathbf: "bold", - mathrm: "normal", - textit: "italic", - mathit: "italic", - mathnormal: "italic", - - // families - mathbb: "double-struck", - mathcal: "script", - mathfrak: "fraktur", - mathscr: "script", - mathsf: "sans-serif", - mathtt: "monospace", - oldstylenums: "oldstylenums" -} - -/** - * Returns the math variant as a string or null if none is required. - */ -export const getVariant = function(group, style) { - // Handle font specifiers as best we can. - // Chromium does not support the MathML mathvariant attribute. - // So we'll use Unicode replacement characters instead. - // But first, determine the math variant. - - // Deal with the \textit, \textbf, etc., functions. - if (style.fontFamily === "texttt") { - return "monospace" - } else if (style.fontFamily === "textsc") { - return "normal"; // handled via character substitution in symbolsOrd.js. - } else if (style.fontFamily === "textsf") { - if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "sans-serif-bold-italic" - } else if (style.fontShape === "textit") { - return "sans-serif-italic" - } else if (style.fontWeight === "textbf") { - return "sans-serif-bold" - } else { - return "sans-serif" - } - } else if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "bold-italic" - } else if (style.fontShape === "textit") { - return "italic" - } else if (style.fontWeight === "textbf") { - return "bold" - } - - // Deal with the \mathit, mathbf, etc, functions. - const font = style.font - if (!font || font === "mathnormal") { - return null - } - - const mode = group.mode; - switch (font) { - case "mathit": - return "italic" - case "mathrm": { - const codePoint = group.text.codePointAt(0) - // LaTeX \mathrm returns italic for Greek characters. - return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal" - } - case "greekItalic": - return "italic" - case "up@greek": - return "normal" - case "boldsymbol": - case "mathboldsymbol": - return "bold-italic" - case "mathbf": - return "bold" - case "mathbb": - return "double-struck" - case "mathfrak": - return "fraktur" - case "mathscr": - case "mathcal": - return "script" - case "mathsf": - return "sans-serif" - case "mathtt": - return "monospace" - case "oldstylenums": - return "oldstylenums" - default: - break - } - - let text = group.text; - if (symbols[mode][text] && symbols[mode][text].replace) { - text = symbols[mode][text].replace - } - - return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null -}; diff --git a/temml.js b/temml.js deleted file mode 100644 index 5e971e32..00000000 --- a/temml.js +++ /dev/null @@ -1,177 +0,0 @@ -/* eslint no-console:0 */ -/** - * This is the main entry point for Temml. Here, we expose functions for - * rendering expressions either to DOM nodes or to markup strings. - * - * We also expose the ParseError class to check if errors thrown from Temml are - * errors in the expression, or errors in javascript handling. - */ - -import ParseError from "./src/ParseError"; -import Settings from "./src/Settings"; - -import Parser from "./src/Parser"; -import parseTree from "./src/parseTree"; -import buildMathML from "./src/buildMathML"; -import { StyleLevel } from "./src/constants"; -import Style from "./src/Style"; -import { Span } from "./src/domTree"; -import { TextNode } from "./src/domTree"; -import { defineSymbol } from "./src/symbols"; -import defineMacro from "./src/defineMacro"; -import { postProcess, version } from "./src/postProcess"; - -/** - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options) { - baseNode.textContent = ""; - const math = renderToMathMLTree(expression, options) - if (options.elementIsMath) { - // The element already exists. Populate it. - baseNode.textContent = "" - math.children.forEach(e => { baseNode.appendChild(e.toNode()) }) - } else { - baseNode.appendChild(math.toNode()) - } -}; - -// Temml's styles don't work properly in quirks mode. Print out an error, and -// disable rendering. -if (typeof document !== "undefined") { - if (document.compatMode !== "CSS1Compat") { - typeof console !== "undefined" && - console.warn( - "Warning: Temml doesn't work in quirks mode. Make sure your " + - "website has a suitable doctype." - ); - - render = function() { - throw new ParseError("Temml doesn't work in quirks mode."); - }; - } -} - -/** - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * Take an expression which contains a preamble. - * Parse it and return the macros. - */ -const definePreamble = function(expression, options) { - const settings = new Settings(options); - settings.macros = {}; - if (!(typeof expression === "string" || expression instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(expression, settings, true) - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"] - const macros = parser.parse() - return macros -}; - -/** - * If the given error is a Temml ParseError, - * renders the invalid LaTeX as a span with hover title giving the Temml - * error message. Otherwise, simply throws the error. - */ -const renderError = function(error, expression, options) { - if (options.throwOnError || !(error instanceof ParseError)) { - throw error; - } - const node = new Span(["temml-error"], [new TextNode(expression + "\n" + error.toString())]); - node.style.color = options.errorColor - node.style.whiteSpace = "pre-line" - return node; -}; - -/** - * Generates and returns the Temml build tree. This is used for advanced - * use cases (like rendering to custom output). - */ -const renderToMathMLTree = function(expression, options) { - const settings = new Settings(options); - try { - const tree = parseTree(expression, settings); - const style = new Style({ - level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT, - maxSize: settings.maxSize - }); - return buildMathML(tree, expression, style, settings); - } catch (error) { - return renderError(error, expression, settings); - } -}; - -export default { - /** - * Current Temml version - */ - version: version, - /** - * Renders the given LaTeX into MathML, and adds - * it as a child to the specified DOM node. - */ - render, - /** - * Renders the given LaTeX into MathML string, - * for sending to the client. - */ - renderToString, - /** - * Post-process an entire HTML block. - * Writes AMS auto-numbers and implements \ref{}. - * Typcally called once, after a loop has rendered many individual spans. - */ - postProcess, - /** - * Temml error, usually during parsing. - */ - ParseError, - /** - * Creates a set of macros with document-wide scope. - */ - definePreamble, - /** - * Parses the given LaTeX into Temml's internal parse tree structure, - * without rendering to HTML or MathML. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __parse: generateParseTree, - /** - * Renders the given LaTeX into a MathML internal DOM tree - * representation, without flattening that representation to a string. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __renderToMathMLTree: renderToMathMLTree, - /** - * adds a new symbol to builtin symbols table - */ - __defineSymbol: defineSymbol, - /** - * adds a new macro to builtin macro list - */ - __defineMacro: defineMacro -} diff --git a/test/Investigate.html b/test/Investigate.html deleted file mode 100644 index 9dc34889..00000000 --- a/test/Investigate.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - Investigate - - - - - - - -

- - - a - - b - - - - - a - Γ - b - -

- - -

- - - - - M - - - c - - - - - - f - - - c - 2 - - - - - - - - M - g - - 2 - - - - - M - 2 - - - - - - - - f - c - - - - - - -

- -

- -

- - - - - diff --git a/test/LaTeXML-tests.md b/test/LaTeXML-tests.md deleted file mode 100644 index 346cda38..00000000 --- a/test/LaTeXML-tests.md +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - Temml LaTeXML Tests - - - - - - - - -# LaTeXML Test - -This LaTeXML test reproduces math examples from https://latexml.mathweb.org/editor\ -The equations in the first table came originally from http://www.mathjax.org/demos/tex-samples/, which no longer exists. - -### Equations - -+-----+------------------------------------------------+------------------------------------------------+ -| | Source | Temml | -+=====+================================================+================================================+ -| The Lorenz Equations | -+-----+------------------------------------------------+------------------------------------------------+ -| 1 | \\begin{aligned} \ | $$\begin{aligned} | -| | \\dot{x} & = \\sigma(y-x) \\\\ \ | \dot{x} & = \sigma(y-x) \\ | -| | \\dot{y} & = \\rho x - y - xz \\\\ \ | \dot{y} & = \rho x - y - xz \\ | -| | \\dot{z} & = -\\beta z + xy \ | \dot{z} & = -\beta z + xy | -| | \\end{aligned} | \end{aligned}$$ | -+-----+------------------------------------------------+------------------------------------------------+ -| The Cauchy-Schwarz Inequality | -+-----+------------------------------------------------+------------------------------------------------+ -| 2 | \\left( \\sum\_{k=1}^n a_k b_k \\right)^2 \ | $$\left( \sum_{k=1}^n a_k b_k \right)^2 | -| | \\leq \\left( \\sum\_{k=1}^n a_k^2 \\right) \ | \leq \left( \sum_{k=1}^n a_k^2 \right) | -| | \left( \sum\_{k=1}^n b_k^2 \right) \ | \left( \sum_{k=1}^n b_k^2 \right)$$ | -+-----+------------------------------------------------+------------------------------------------------+ -| A Cross Product Formula | -+-----+------------------------------------------------+------------------------------------------------+ -| 3 | \\mathbf{V}\_1 \\times \\mathbf{V}\_2 = \ | $$\mathbf{V}_1 \times \mathbf{V}_2 = | -| | \\begin{vmatrix} \ | \begin{vmatrix} | -| | \\mathbf{i} & \\mathbf{j} & \\mathbf{k} \\\\ \ | \mathbf{i} & \mathbf{j} & \mathbf{k} \\ | -| | \\frac{\\partial X}{\\partial u} & \ | \frac{\partial X}{\partial u} & | -| | \\frac{\\partial Y}{\\partial u} & 0 \\\\ \ | \frac{\partial Y}{\partial u} & 0 \\ | -| | \\frac{\\partial X}{\\partial v} & \ | \frac{\partial X}{\partial v} & | -| | \\frac{\\partial Y}{\\partial v} & 0 \ | \frac{\partial Y}{\partial v} & 0 | -| | \\end{vmatrix} | \end{vmatrix}$$ | -+-----+------------------------------------------------+------------------------------------------------+ -| The probability of getting $`k` heads when flipping $`n` coins is: | -+-----+------------------------------------------------+------------------------------------------------+ -| 4 | P(E) = {n \\choose k} p^k (1-p)^{ n-k} \ | $$P(E) = {n \choose k} p^k (1-p)^{ n-k}$$ | -+-----+------------------------------------------------+------------------------------------------------+ -| An Identity of Ramanujan | -+-----+------------------------------------------------+------------------------------------------------+ -| 5 | \\frac{1}{\\Bigl(\\sqrt{\\phi \\sqrt{5}}- \ | $$\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}- | -| | \\phi\\Bigr) e^{\\frac25 \\pi}} = \ | \phi\Bigr) e^{\frac25 \pi}} = | -| | 1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} \ | 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} | -| | {1+\\frac{e^{-6\\pi}} \ | {1+\frac{e^{-6\pi}} | -| | {1+\\frac{e^{-8\\pi}} {1+\\ldots} } } } | {1+\frac{e^{-8\pi}} {1+\ldots} } } }$$ | -+-----+------------------------------------------------+------------------------------------------------+ -| A Rogers-Ramanujan Identity | -+-----+------------------------------------------------+------------------------------------------------+ -| 6 | 1 + \\frac{q^2}{(1-q)}+ \ | $$1 + \frac{q^2}{(1-q)}+ | -| | \\frac{q^6}{(1-q)(1-q^2)}+\\cdots = \ | \frac{q^6}{(1-q)(1-q^2)}+\cdots = | -| | \\prod\_{j=0}^{\\infty}\frac{1} \ | \prod_{j=0}^{\infty}\frac{1} | -| | {(1-q^{5j+2})(1-q^{5j+3})}, \ | {(1-q^{5j+2})(1-q^{5j+3})}, | -| | \\quad\\quad \\text{for} |q|<1. | \quad\quad \text{for} |q|<1.$$ | -+-----+------------------------------------------------+------------------------------------------------+ -| Maxwell's Equations | -+-----+------------------------------------------------+------------------------------------------------+ -| 7 | \\begin{aligned} \ | $$\begin{aligned} | -| | \\nabla \\times \\vec{\mathbf{B}} -\\\\, \ | \nabla \times \vec{\mathbf{B}} -\, | -| | \\frac1c\\, \\frac{\\partial\\vec{ \ | \frac1c\, \frac{\partial\vec{ | -| | \\mathbf{E}}}{\\partial t} & \ | \mathbf{E}}}{\partial t} & | -| | = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\ \ | = \frac{4\pi}{c}\vec{\mathbf{j}} \\ | -| | \\nabla \\cdot \\vec{\\mathbf{E}} & \ | \nabla \cdot \vec{\mathbf{E}} & | -| | = 4 \\pi \\rho \\\\ \ | = 4 \pi \rho \\ | -| | \\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \ | \nabla \times \vec{\mathbf{E}}\, +\, | -| | \\frac1c\\, \\frac{\\partial\\vec{ \ | \frac1c\, \frac{\partial\vec{ | -| | \\mathbf{B}}}{\\partial t} & \ | \mathbf{B}}}{\partial t} & | -| | = \\vec{\mathbf{0}} \\\\ \ | = \vec{\mathbf{0}} \\ | -| | \\nabla \\cdot \\vec{\\mathbf{B}} & \ | \nabla \cdot \vec{\mathbf{B}} & | -| | = 0 \ | = 0 | -| | \\end{aligned} \ | \end{aligned}$$ | -+-----+------------------------------------------------+------------------------------------------------+ - -### Boxes - -| Source | Temml | -|:-------|:--------| -| `\raisebox{0pt}[0pt][0pt]{\Large%`
`\textbf{Aaaa\raisebox{-0.3ex}{a}%`
`\raisebox{-0.7ex}{aa}\raisebox{-1.2ex}{r}%`
`\raisebox{-2.2ex}{g}\raisebox{-4.5ex}{h}}}` | $`\raisebox{0pt}{\Large\textbf{Aaaa\raisebox{-0.3ex}{a}\raisebox{-0.7ex}{aa}\raisebox{-1.2ex}{r}\raisebox{-2.2ex}{g}\raisebox{-4.5ex}{h}}}` | - -### Unicode - -The tests below come from https://latexml.mathweb.org/editor\ -They got them from https://trac.edgewall.org/wiki/TracUnicode\ -I have no idea what these lines say. - -All the Unicode characters are written inside `\text{}`. - -| Language | Temml | -|:----------------------|:-------------------------------------------------------------| -| Arabic | $`\dfrac{\text{تراك يقوم بحفظ كل الكلمات باستخدام صيغة}} 2` -| Bulgarian | $`\dfrac{\text{Българският език работи ли?}} 2` -| Česky | $`\dfrac{\text{Čeština v kódování UTF-8, žádný problém.}} 2` -| Chinese (Traditional) | $`\dfrac{\text{繁體中文, 漢字測試}} 2` -| Chinese (Simplified) | $`\dfrac{\text{简体中文,汉字测试}} 2` -| Croatian | $`\left(\begin{array}{l}\text{Ako podržava srpski i slovenski mora podržavati} \\ \text{ i Hrvatski - čćžšđ ČĆŽŠĐ}\end{array}\right)` -| English | $`\dfrac{\text{Yes indeed, Trac supports English. Fully.}} 2` -| Français | $`\dfrac{\text{Il est possible d'écrire en Français : à, ç, û, …}} 2` -| German | $`\left(\begin{array}{l}\text{Trac-Wiki muß auch deutsche Umlaute richtig anzeigen:} \\ \text{ö, ä, ü, Ä, Ö, Ü; und das scharfe ß}\end{array}\right)` -| Greek | $`\dfrac{\text{Τα Ελληνικά υποστηρίζονται επαρκώς επίσης.}} 2` -| Hebrew | $`\dfrac{\text{אני יכול לאכול זכוכית וזה לא מזיק לי}} 2` -| Hindi | $`\dfrac{\text{अब हिन्दी में।}} 2` -| Hungarian | $`\dfrac{\text{Árvíztűrő tükörfúrógép}} 2` -| Icelandic | $`\dfrac{\text{Ævar sagði við ömmu sína: Sjáðu hvað ég er stór!}} 2` -| Japanese | $`\dfrac{\text{漢字 ひらがな カタカナ ハンカクカナ 日本語試験}} 2` -| Korean | $`\dfrac{\text{이번에는 한글로 써보겠습니다. 잘 보이나요? 한글}} 2` -| Latvian | $`\dfrac{\text{Latviešu valoda arī strādā!}} 2` -| Lithuanian | $`\left(\begin{array}{l}\text{Sudalyvaukime ir mes. Ar veikia lietuviškos raidės?} \\ \text{ąčęėįšųūž ĄČĘĖĮŠŲŪŽ Žinoma, kad veikia :) Kas tie mes?}\end{array}\right)` -| Persian (Farsi) | $`\left(\begin{array}{l}\text{ولی امکان نوشتن مستقیم فارسی نیست چون حالت متن از راست به چپ و جود} \\ \text{این یک متن فارسی است ندارد برای فارسی نوشتن باید از HTML استفاده کنید.}\end{array}\right)` -| Polish | $`\left(\begin{array}{l}\text{Pchnąć w tę łódź jeża lub osiem skrzyń fig;} \\ \text{Nocna gżegżółka zawsze dzienną przekuka.}\end{array}\right)` -| Portuguese | $`\left(\begin{array}{l}\text{É possível guardar caracteres especias da língua portuguesa, } \\ \text{incluindo o símbolo da moeda européia '€', trema 'ü', crase 'à', agudos 'áéíóú',} \\ \text{circunflexos 'âêô', til 'ãõ', cedilha 'ç', ordinais 'ªº', grau '°¹²³'.}\end{array}\right)` -| Russian | $`\dfrac{(\text{Проверка русского языка: кажется работает... И буква "ё" есть...}} 2` -| Serbian | $`\left(\begin{array}{l}\text{Podržan, uprkos činjenici da se za njegovo} \\ \text{pisanje koriste чак два алфабета.}\end{array}\right)` -| Slovenian | $`\dfrac{\text{Ta suhi škafec pušča vodo že od nekdaj!}} 2` -| Spanish | $`\left(\begin{array}{l}\text{Esto es un pequeño texto en Español,} \\ \text{donde el veloz murciélago hindú comía cardlllo y kiwi}\end{array}\right)` -| Swedish | $`\dfrac{\text{Räven raskar över isen med luva på.}} 2` -| Thai | $`\dfrac{\text{Trac แสดงภาษาไทยได้อย่างถูกต้อง!}} 2` -| Ukrainian | $`\dfrac{\text{Перевірка української мови...}} 2` -| Urdu | $`\dfrac{\text{ٹریک اردو بھی سپورٹ کرتا ہے۔}} 2` -| Vietnamese | $`\dfrac{\text{Viết tiếng Việt cũng được.}} 2` - -
- - diff --git a/test/auto-render.js b/test/auto-render.js deleted file mode 100644 index 0b0b00dc..00000000 --- a/test/auto-render.js +++ /dev/null @@ -1,212 +0,0 @@ -var autorender = (function () { - 'use strict'; - - /* eslint no-constant-condition:0 */ - const findEndOfMath = function(delimiter, text, startIndex) { - // Adapted from - // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx - let index = startIndex; - let braceLevel = 0; - - const delimLength = delimiter.length; - - while (index < text.length) { - const character = text[index]; - - if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { - return index; - } else if (character === "\\") { - index++; - } else if (character === "{") { - braceLevel++; - } else if (character === "}") { - braceLevel--; - } - - index++; - } - - return -1; - }; - - const escapeRegex = function(string) { - return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); - }; - - const amsRegex = /^\\begin{/; - - const splitAtDelimiters = function(text, delimiters) { - let index; - const data = []; - - const regexLeft = new RegExp( - "(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")" - ); - - while (true) { - index = text.search(regexLeft); - if (index === -1) { - break; - } - if (index > 0) { - data.push({ - type: "text", - data: text.slice(0, index) - }); - text = text.slice(index); // now text starts with delimiter - } - // ... so this always succeeds: - const i = delimiters.findIndex((delim) => text.startsWith(delim.left)); - index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length); - if (index === -1) { - break; - } - const rawData = text.slice(0, index + delimiters[i].right.length); - const math = amsRegex.test(rawData) - ? rawData - : text.slice(delimiters[i].left.length, index); - data.push({ - type: "math", - data: math, - rawData, - display: delimiters[i].display - }); - text = text.slice(index + delimiters[i].right.length); - } - - if (text !== "") { - data.push({ - type: "text", - data: text - }); - } - - return data; - }; - - /* eslint no-console:0 */ - - /* Note: optionsCopy is mutated by this method. If it is ever exposed in the - * API, we should copy it before mutating. - */ - const renderMathInText = function(text, optionsCopy) { - const data = splitAtDelimiters(text, optionsCopy.delimiters); - if (data.length === 1 && data[0].type === "text") { - // There is no formula in the text. - // Let's return null which means there is no need to replace - // the current text node with a new one. - return null; - } - - const fragment = document.createDocumentFragment(); - - for (let i = 0; i < data.length; i++) { - if (data[i].type === "text") { - fragment.appendChild(document.createTextNode(data[i].data)); - } else { - const span = document.createElement("span"); - let math = data[i].data; - // Override any display mode defined in the settings with that - // defined by the text itself - optionsCopy.displayMode = data[i].display; - try { - if (optionsCopy.preProcess) { - math = optionsCopy.preProcess(math); - } - temml.render(math, span, optionsCopy); - } catch (e) { - if (!(e instanceof temml.ParseError)) { - throw e; - } - optionsCopy.errorCallback( - "temml auto-render: Failed to parse `" + data[i].data + "` with ", - e - ); - fragment.appendChild(document.createTextNode(data[i].rawData)); - continue; - } - fragment.appendChild(span); - } - } - - return fragment; - }; - - const renderElem = function(elem, optionsCopy) { - for (let i = 0; i < elem.childNodes.length; i++) { - const childNode = elem.childNodes[i]; - if (childNode.nodeType === 3) { - // Text node - const frag = renderMathInText(childNode.textContent, optionsCopy); - if (frag) { - i += frag.childNodes.length - 1; - elem.replaceChild(frag, childNode); - } - } else if (childNode.nodeType === 1) { - // Element node - const className = " " + childNode.className + " "; - const shouldRender = - optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 && - optionsCopy.ignoredClasses.every((x) => className.indexOf(" " + x + " ") === -1); - - if (shouldRender) { - renderElem(childNode, optionsCopy); - } - } - // Otherwise, it's something else, and ignore it. - } - }; - - const renderMathInElement = function(elem, options) { - if (!elem) { - throw new Error("No element provided to render"); - } - - const optionsCopy = {}; - - // Object.assign(optionsCopy, option) - for (const option in options) { - if (options.hasOwnProperty(option)) { - optionsCopy[option] = options[option]; - } - } - - // default options - optionsCopy.delimiters = optionsCopy.delimiters || [ - { left: "$$", right: "$$", display: true }, - { left: "\\(", right: "\\)", display: false }, - // LaTeX uses $…$, but it ruins the display of normal `$` in text: - // {left: "$", right: "$", display: false}, - // $ must come after $$ - - // Render AMS environments even if outside $$…$$ delimiters. - { left: "\\begin{equation}", right: "\\end{equation}", display: true }, - { left: "\\begin{align}", right: "\\end{align}", display: true }, - { left: "\\begin{alignat}", right: "\\end{alignat}", display: true }, - { left: "\\begin{gather}", right: "\\end{gather}", display: true }, - { left: "\\begin{CD}", right: "\\end{CD}", display: true }, - - { left: "\\[", right: "\\]", display: true } - ]; - optionsCopy.ignoredTags = optionsCopy.ignoredTags || [ - "script", - "noscript", - "style", - "textarea", - "pre", - "code", - "option" - ]; - optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; - optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; - - // Enable sharing of global macros defined via `\gdef` between different - // math elements within a single call to `renderMathInElement`. - optionsCopy.macros = optionsCopy.macros || {}; - - renderElem(elem, optionsCopy); - }; - - return renderMathInElement; - -}()); diff --git a/test/katex-tests.md b/test/katex-tests.md deleted file mode 100644 index 88d4c05a..00000000 --- a/test/katex-tests.md +++ /dev/null @@ -1,1159 +0,0 @@ - - - - - - Temml Screen Tests - - - - - - - - -# Tests from KaTeX - -This file renders examples from KaTeX’s -[screenshotter tests](https://github.com/KaTeX/KaTeX/blob/main/test/screenshotter/ss_data.yaml).\ -Images from LaTeX are also provided for comparison.\ -(Images come from [LaTeX Previewer](http://www.tlhiv.org/ltxpreview/), thanks.) - -#### Accents - -+---------------------------+---------------------------------------+--------------------------------+ -| Source | Temml | LaTeX | -+===========================+=======================================+================================+ -| \vec{A}\vec{x}\vec x^2 \ | $`\vec{A}\vec{x}\vec x^2\vec{x}_2^2 | ![accents](images/accents.svg) | -| \vec{x}_2^2 \vec{A}^2 \ | \vec{A}^2\vec{xA}^2\; \underbar{X}` | | -| \vec{xA}^2\; \underbar{X} | | | -+---------------------------+---------------------------------------+--------------------------------+ - -#### AccentsText - -+---+---------------------------------------------------------------------------------------------------------------+------------------+ -| | $``\begin{array}{lccccc} \text{\'\i} & \text{\.\i} & \text{\`\i} & \text{\"\i} & \text{\H\i} & \text{\r\i} \\ | ![AccentsText][] | -| | \text{\'\j} & \text{\.\j} & \text{\`\j} & \text{\"\j} & \text{\H\j} & \text{\r\j} \\ | | -| | \text{\'a} & \text{\.a} & \text{\`a} & \text{\"a} & \text{\H{a}} & \text{\r{a}} \\ | | -| | \text{\'A} & \text{\.A} & \text{\`A} & \text{\"A} & \text{\H{A}} & \text{\r{A}} \\ | | -| | \text{\.I İ} & \text{\H e e̋} & \text{\i ı} \end{array}`` | | -+---+---------------------------------------------------------------------------------------------------------------+------------------+ - -[AccentsText]: images/AccentsText.svg - -#### Actuarial Angle - -+--------------------------+---------------------------+--------------------------+ -| `a_{\angl n}\; a_\angln` | $`a_{\angl n}\; a_\angln` | ![angl](images/angl.svg) | -+--------------------------+---------------------------+--------------------------+ - -#### Align - -+---------------------------+------------------------------------+ -| \begin{align} \ | $$\begin{align}a &= 1 & b &= 2 \\ | -| a &= 1 & b &= 2 \\\\ \ | 3a &= 3 & 17b &= 34\end{align}$$ | -| 3a &= 3 & 17b &= 34 \ | | -| \end{align} | | -+---------------------------+------------------------------------+ -{colWidths="null 200"} - -#### Alignat - -+--------------------------------------------------+------------------------------------------------+ -| \begin{alignat}{3} \ | $$\begin{alignat}{3} | -| a &= 1\quad & b &= 2 &\quad c &= 3\\\\ \ | a &= 1\quad & b &= 2 &\quad c &= 3\\ | -| 3a &= 3 &\quad 17b &= 34 &\quad 400c &= 1200 \ | 3a &= 3 &\quad 17b &= 34 &\quad 400c &= 1200 | -| \end{alignat} | \end{alignat}$$ | -+--------------------------------------------------+------------------------------------------------+ -{colWidths="null 350"} - -#### Aligned - -+---------------------------+-------------------------------------+--------------------------------+ -| \begin{aligned} \ | $`\begin{aligned}a &= 1 & b &= 2 \\ | ![aligned](images/aligned.svg) | -| a &= 1 & b &= 2 \\\\ \ | 3a &= 3 & 17b &= 34\end{aligned}` | | -| 3a &= 3 & 17b &= 34 \ | | | -| \end{aligned} | | | -+---------------------------+-------------------------------------+--------------------------------+ - -#### Alignedat - -+--------------------------------------------------+------------------------------------------------+----------------+ -| \begin{alignedat}{3} \ | $$\begin{alignedat}{3} | ![alignedat][] | -| a &= 1\quad & b &= 2 &\quad c &= 3\\\\ \ | a &= 1\quad & b &= 2 &\quad c &= 3\\ | | -| 3a &= 3 &\quad 17b &= 34 &\quad 400c &= 1200 \ | 3a &= 3 &\quad 17b &= 34 &\quad 400c &= 1200 | | -| \end{alignedat} | \end{alignedat}$$ | | -+--------------------------------------------------+------------------------------------------------+----------------+ - -[alignedat]: images/alignedat.svg - -#### Arrays - -This LaTeX image does include dashed lines.\ -LaTeX Previewer does not include the `arydshln` package. - -+-------------------------------------------------------------+----------------------------------------------------------+---------------+ -| \left(\begin{array}{|rl:c|} | $`\left(\begin{array}{|rl:c|} | ![Arrays][] | -| 1&2&3\\\\ \hline \ | 1&2&3\\ \hline | | -| 1+1&2+1&3+1\cr1\over2&\scriptstyle 1/2&\frac 1 2\\\\ \ | 1+1&2+1&3+1\cr1\over2&\scriptstyle 1/2&\frac 1 2\\ | | -| \hdashline \ | \hdashline | | -| \begin{pmatrix}x\\\\y\end{pmatrix}&0& \ | \begin{pmatrix}x\\y\end{pmatrix}&0& | | -| \begin{vmatrix}a&b\\\\c&d\end{vmatrix} \ | \begin{vmatrix}a&b\\c&d\end{vmatrix} | | -| \end{array}\right] | \end{array}\right]` | | -+-------------------------------------------------------------+----------------------------------------------------------+---------------+ -| \begin{smallmatrix} a & b \\\\ c & d \end{smallmatrix} \ | $`\begin{smallmatrix} a & b \\ c & d \end{smallmatrix}` | ![subarray][] | -| \begin{subarray}{c}a \\\\ b\end{subarray} | $`\begin{subarray}{c}a \\ b\end{subarray}` | | -+-------------------------------------------------------------+----------------------------------------------------------+---------------+ - -[Arrays]: images/Arrays.svg -[subarray]: images/subarray.svg - -#### ArrayMode - -+---+---------------------------------------------------------------+------------------------------------+ -| | $$\begin{matrix} \frac{\partial^2 f}{\partial x_1^2} & | ![ArrayMode](images/ArrayMode.svg) | -| | \frac{\partial^2 f}{\partial x_1\,\partial x_2} & | | -| | \cdots & \frac{\partial^2 f}{\partial x_1\,\partial x_n} \\ | | -| | \frac{\partial^2 f}{\partial x_2\,\partial x_1} & | | -| | \frac{\partial^2 f}{\partial x_2^2} & | | -| | \cdots & \frac{\partial^2 f}{\partial x_2\,\partial x_n} \\ | | -| | \vdots & \vdots & \ddots & \vdots \\ | | -| | \frac{\partial^2 f}{\partial x_n\,\partial x_1} & | | -| | \frac{\partial^2 f}{\partial x_n\,\partial x_2} & | | -| | \cdots & \frac{\partial^2 f}{\partial x_n^2} | | -| | \end{matrix}$$ | | -+---+---------------------------------------------------------------+------------------------------------+ - -#### ArrayType - -+-------------------------------------+--------------------------------------+------------------------------------+ -| 1\begin{array}{c}2\\\\3\end{array}4 | $`1\begin{array}{c}2\\3\end{array}4` | ![ArrayType](images/ArrayType.svg) | -+-------------------------------------+--------------------------------------+------------------------------------+ - -#### ArrayRemoveEmptyLine - -A `\\` at the end of a matrix should not create another line. - -+---------------------------------------------+--------------------------------------------+ -| \begin{pmatrix} 1 \\\\ 2 \\\\ \end{pmatrix} | $`\begin{pmatrix} 1 \\ 2 \\ \end{pmatrix}` | -+---------------------------------------------+--------------------------------------------+ - -#### Baseline - -+----------------+-------------------+----------------------------------+ -| a+b-c\cdot d/e | $`a+b-c\cdot d/e` | ![Baseline](images/baseline.svg) | -+----------------+-------------------+----------------------------------+ - -#### BasicTest - -$`a` - -#### BinCancellation - -+--------------------------------------------+-------------------------------------------+----------------------+ -| \begin{array}{cccc} \ | $`\begin{array}{cccc} | ![BinCancellation][] | -| +1 & 1+ & 1+1 & (,) \\\\ \ | +1 & 1+ & 1+1 & (,) \\ | | -| 1++1 & 3\times) & 1+, & \left(,\right) \ | 1++1 & 3\times) & 1+, & \left(,\right) | | -| \end{array} | \end{array}` | | -+--------------------------------------------+-------------------------------------------+----------------------+ - -[BinCancellation]: images/BinCancellation.svg - -#### Binom - -+----------------------------------------------+-------------------------------------------------+------------+ -| \dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17} | $`\dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17}` | ![binom][] | -+----------------------------------------------+-------------------------------------------------+------------+ - -[binom]: images/binom.svg - -#### BoldSpacing - -+----------------------------------------+-------------------------------------------+ -| \mathbf{A}^2+\mathbf{B}_3*\mathscr{C}' | $`\mathbf{A}^2+\mathbf{B}_3*\mathscr{C}'` | -+----------------------------------------+-------------------------------------------+ - -#### BoldSymbol - -+-----------------------------------------------------+----------------------------------------------------+-----------------+ -| `\sum_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}}` \ | $`\sum_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}} | ![BoldSymbol][] | -| \boldsymbol{\omega}+ \ | \boldsymbol{\omega}+ | | -| `\boldsymbol{\int_\alpha^\beta}` \ | \boldsymbol{\int_\alpha^\beta} | | -| \boldsymbol{\Omega + {}} \\\\ \ | \boldsymbol{\Omega + {}} \\ | | -| \boldsymbol{\lim_{x \to \infty} \ | \boldsymbol{\lim_{x \to \infty} | | -| \log Ax2k\omega\Omega\imath+} \\\\ \ | \log Ax2k\omega\Omega\imath+} \\ | | -| x \boldsymbol{+} y \boldsymbol{=} z | x \boldsymbol{+} y \boldsymbol{=} z` | | -+-----------------------------------------------------+----------------------------------------------------+-----------------+ - -[BoldSymbol]: images/BoldSymbol.svg - -#### Boxed - -+----------------------------------------+-----------------------------------------+------------+ -| \boxed{F=ma} \quad \boxed{ac}\ | $`\boxed{F=ma} \quad \boxed{ac} | ![boxed][] | -| \color{magenta}{\boxed{F}}\boxed{F=mg} | \color{magenta}{\boxed{F}}\boxed{F=mg}` | | -+----------------------------------------+-----------------------------------------+------------+ - -[boxed]: images/boxed.svg - -#### Cases - -+----------------------------------------+------------------------------------+------------------------------+ -| f(a,b)= \ | $`f(a,b)= | ![cases](images/cases.svg) | -| \begin{cases} \ | \begin{cases} | | -| a+1&\text{if }b\text{ is odd} \\\\ \ | a+1&\text{if }b\text{ is odd} \\ | | -| a&\text{if }b=0 \\\\ \ | a&\text{if }b=0 \\ | | -| a-1&\text{otherwise} \ | a-1&\text{otherwise} | | -| \end{cases} | \end{cases}` | | -+----------------------------------------+------------------------------------+------------------------------+ -| \begin{rcases} \ | $`\begin{rcases} | ![rcases](images/rcases.svg) | -| a &\text{if } b \\\\ \ | a &\text{if } b \\ | | -| c &\text{if } d \ | c &\text{if } d | | -| \end{rcases}\Rightarrow\ldots | \end{rcases}\Rightarrow\ldots` | | -+----------------------------------------+------------------------------------+------------------------------+ - -#### CD - -+-----------------------------+-------------------------+----------------------+ -| \begin{CD} \ | $$\begin{CD} | ![CD](images/CD.svg) | -| A @>b> C \\\\ \ | A @>b> C \\ | | -| @| @AcAA @VVdV \\\\ \ | @| @AcAA @VVdV \\ | | -| D @= E @>>> F \ | D @= E @>>> F | | -| \end{CD} | \end{CD}$$ | | -+-----------------------------+-------------------------+----------------------+ - -#### Colors - -+-----------------------+-----------------------+------------------------------+ -| \textcolor{#0f0}{b} \ | $`\textcolor{#0f0}{b} | ![colors](images/colors.svg) | -| \textcolor{red}{c} | \textcolor{red}{c}` | | -+-----------------------+-----------------------+------------------------------+ - -#### ColorImplicit - -+----------------------------------+------------------------------+--------------------------------------------+ -| bl{ack\color{red}red \ | $`bl{ack\color{red}red | ![ColorImplicit](images/ColorImplicit.svg) | -| \textcolor{green}{green} \ | \textcolor{green}{green} | | -| red\color{blue}blue}black \\\\ \ | red\color{blue}blue}black \\ | | -| black\left(black \ | black\left(black | | -| \color{red}red\right)black | \color{red}red\right)black` | | -+----------------------------------+------------------------------+--------------------------------------------+ - -#### ColorSpacing - -+----------------------------+-----------------------------+------------------------------------------+ -| \textcolor{red}{x} + 1 \ | $`\textcolor{red}{x} + 1 | ![ColorSpacing](images/ColorSpacing.svg) | -| {\color{green}+ 2 +} 3 + 4 | {\color{green}+ 2 +} 3 + 4` | | -+----------------------------+-----------------------------+------------------------------------------+ - -#### Colorbox - -+----------------------------+----------------------------+----------------------------------+ -| a \colorbox{teal} B \ | $`a \colorbox{teal} B | ![Colorbox](images/Colorbox.svg) | -| \fcolorbox{blue}{red}{C} \ | \fcolorbox{blue}{red}{C} | | -| e+\colorbox{teal}x | e+\colorbox{teal}x` | | -+----------------------------+----------------------------+----------------------------------+ - -#### DashesAndQuotes - -+-----------------------------------------------------------+------------------------------------------------------+----------------------+ -| \begin{array}{l} \ | $```\begin{array}{l} | ![DashesAndQuotes][] | -| ```\text{``a'' b---c -- d----`e'-{-}-f} -- \\``` \ | \text{``a'' b---c -- d----`e'-{-}-f} -- \\ | | -| ```\text{\it ``a'' b---c -- d----`e'-{-}-f} ``x'' \\``` \ | \text{\it ``a'' b---c -- d----`e'-{-}-f} ``x'' \\ | | -| ```\text{\tt ``a''---} \texttt{``a''---} \mathtt{--}``` \ | \text{\tt ``a''---} \texttt{``a''---} \mathtt{--} \\ | | -| \end{array} | \end{array}``` | | -+-----------------------------------------------------------+------------------------------------------------------+----------------------+ - -[DashesAndQuotes]: images/DashesAndQuotes.svg - -#### DelimiterSizing - -+-----------------------------------+-----------------------------------+-----------------------+ -| \bigl\uparrow\Bigl\downarrow \ | $`\bigl\uparrow\Bigl\downarrow | ![DelimiterSizing1][] | -| \biggl\updownarrow \ | \biggl\updownarrow | | -| \Biggl\Uparrow\Biggr\Downarrow \ | \Biggl\Uparrow\Biggr\Downarrow | | -| \biggr\langle\Bigr\\}\bigr\rfloor | \biggr\langle\Bigr\}\bigr\rfloor` | | -+-----------------------------------+-----------------------------------+-----------------------+ -| \begin{pmatrix} \ | $`\begin{pmatrix} | ![DelimiterSizing2][] | -| a & b & c\\\\ \ | a & b & c\\ | | -| a & b & c\\\\ \ | a & b & c\\ | | -| a & b & c \ | a & b & c\\ | | -| \end{pmatrix} | \end{pmatrix}` | | -+-----------------------------------+-----------------------------------+-----------------------+ - -[DelimiterSizing1]: images/DelimiterSizing1.svg -[DelimiterSizing2]: images/DelimiterSizing2.svg - -#### DisplayMode - -+-------------------------------+-----------------------------------+----------------------------------------+ -| \sum_{i=0}^\infty \frac{1}{i} | $$\sum_{i=0}^\infty \frac{1}{i}$$ | ![DisplayMode](images/DisplayMode.svg) | -+-------------------------------+-----------------------------------+----------------------------------------+ - -#### DisplayStyle - -+----------------------------------------+---------------------------------------+-------------------+ -| {\displaystyle\sqrt{x}}{\sqrt{x}} \ | $`{\displaystyle\sqrt{x}}{\sqrt{x}} | ![displaystyle][] | -| {\displaystyle \frac 1 2}{\frac 1 2} \ | {\displaystyle \frac 1 2}{\frac 1 2} | | -| `{\displaystyle x^1_2}{x^1_2}` | {\displaystyle x^1_2}{x^1_2}` | | -+----------------------------------------+---------------------------------------+-------------------+ - -[displaystyle]: images/displaystyle.svg - -#### Dots - -+---------------------------------------------+-----------------------------------------+--------------------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![dots](images/dots.svg) | -| \cdots;\dots+\dots\int\dots,\dots \\\\ \ | \cdots;\dots+\dots\int\dots,\dots \\ | | -| \cdots{};\ldots+\ldots\int\ldots,\ldots \ | \cdots{};\ldots+\ldots\int\ldots,\ldots | | -| \end{array} | \end{array}` | | -+---------------------------------------------+-----------------------------------------+--------------------------+ - -#### Equation - -+---------------------+--------------------+----------------------------------+ -| \begin{equation} \ | $$\begin{equation} | ![equation](images/equation.svg) | -| \begin{split} \ | \begin{split} | | -| a& =b+c-d \\\\ \ | a& =b+c-d \\ | | -| & \quad +e-f \\\\ \ | & \quad +e-f \\ | | -| & =g+h \\\\ \ | & =g+h \\ | | -| & =i \ | & =i | | -| \end{split} \ | \end{split} | | -| \end{equation} | \end{equation}$$ | | -+---------------------+--------------------+----------------------------------+ -{colWidths="null 150"} - -#### Exponents - -+---------------------+----------------------+------------------------------------+ -| `a^{a^a_a}_{a^a_a}` | $`a^{a^a_a}_{a^a_a}` | ![exponents](images/exponents.svg) | -+---------------------+----------------------+------------------------------------+ - -#### ExtensibleArrows - -+------------------------------------+----------------------------------+-----------------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![ExtensibleArrows][] | -| \xrightarrow[ab]{ABC} + \ | \xrightarrow[ab]{ABC} + | | -| \xRightarrow{ABC} \\\\ \ | \xRightarrow{ABC} \\ | | -| \xleftrightharpoons[ab]{ABC} + \ | \xleftrightharpoons[ab]{ABC} + | | -| \xhookrightarrow[ab]{ABC} \\\\ \ | \xhookrightarrow[ab]{ABC} \\ | | -| \xmapsto{ABC} + \ | \xmapsto{ABC} + | | -| \frac{\xrightarrow[ab]{ABC}} \ | \frac{\xrightarrow[ab]{ABC}} | | -| {\xrightarrow[ab]{ABC}} + \ | {\xrightarrow[ab]{ABC}} + | | -| \left\lvert\xrightarrow[ab]{ABC} \ | \left\lvert\xrightarrow[ab]{ABC} | | -| \right\rvert \ | \right\rvert | | -| \end{array} | \end{array}` | | -+------------------------------------+----------------------------------+-----------------------+ - -[ExtensibleArrows]: images/ExtensibleArrows.svg - -#### Fractions - -+----------------------------------------------------+--------------------------------------------------+-----------------+ -| \dfrac{a}{b}\frac{a}{b} \ | $`\dfrac{a}{b}\frac{a}{b} | ![Fractions1][] | -| \tfrac{a}{b}\\;- \ | \tfrac{a}{b}\;- | | -| \dfrac 1 2\\;1\tfrac 1 2\\;{1 \atop 2}\\; \ | \dfrac 1 2\;1\tfrac 1 2\;{1 \atop 2}\; | | -| {a \brace b} \\; {a \brack b} | {a \brace b} \; {a \brack b}` | | -+----------------------------------------------------+--------------------------------------------------+-----------------+ -| \genfrac \\{ ]{0.8pt}{0}{a}{b}\\; \ | $`\genfrac \{ ]{0.8pt}{0}{a}{b}\; | ![Fractions2][] | -| {a \above1.0pt b} \\; \ | {a \above1.0pt b} \; | | -| \cfrac{1}{1+\cfrac{1}{x}} \ | \cfrac{1}{1+\cfrac{1}{x}} | | -| \xrightarrow[\dfrac g h]{\displaystyle\frac g h} \ | \xrightarrow[\dfrac g h]{\displaystyle\frac g h} | | -| \\; \xrightarrow [2.\\, \dfrac c d] \ | \; \xrightarrow [2.\, \dfrac c d] | | -| {1.\\, \displaystyle\frac c d} | {1.\, \displaystyle\frac c d}` | | -+----------------------------------------------------+--------------------------------------------------+-----------------+ - -[Fractions1]: images/Fractions1.svg -[Fractions2]: images/Fractions2.svg - -#### Functions - -+---------------------+------------------------+------------------------------------+ -| \sin\cos\tan\ln\log | $`\sin\cos\tan\ln\log` | ![functions](images/functions.svg) | -+---------------------+------------------------+------------------------------------+ - -#### Gather - -+--------------------+------------------+------------------------------+ -| \begin{gather} \ | $$\begin{gather} | ![gather](images/gather.svg) | -| a=\frac 1 2 \\\\ \ | a=\frac 1 2 \\ | | -| e=b+c \ | e=b+c | | -| \end{gather} | \end{gather}$$ | | -+--------------------+------------------+------------------------------+ -{colWidths="null 150 null"} - -#### GreekLetters - -+-------------------------+----------------------------+----------------------------+ -| \alpha\beta\gamma\omega | $`\alpha\beta\gamma\omega` | ![greek](images/greek.svg) | -+-------------------------+----------------------------+----------------------------+ - -#### GreekUnicode - -+--------------------------------------------+-----------------------------------------------+ -| \frac{αβγδεϵζηθϑικλμνξοπϖρϱςστυφϕχψω} \ | $`\frac{αβγδεϵζηθϑικλμνξοπϖρϱςστυφϕχψω} | -| {ΓΔΘΞΠΣΦΨΩϝ\mathbf{Ω}\mathbf{\Omega}} | {ΓΔΘΞΠΣΦΨΩϝ\mathbf{Ω}\mathbf{\Omega}}` | -+--------------------------------------------+-----------------------------------------------+ - -#### HorizontalBraces - -+------------------------------------------------+-----------------------------------------------+-----------------------+ -| \overbrace{\displaystyle{ \ | $`\overbrace{\displaystyle{ | ![HorizontalBraces][] | -| `\oint_S{\vec E\cdot\hat n\,\mathrm d a}}}^` \ | \oint_S{\vec E\cdot\hat n\,\mathrm d a}}}^ | | -| \text{emf} = \ | \text{emf} = | | -| `\underbrace{\frac{q_{` \ | \underbrace{\frac{q_{ | | -| `\text{enc}}}{\varepsilon_0}}_{\text{charge}}` | \text{enc}}}{\varepsilon_0}}_{\text{charge}}` | | -+------------------------------------------------+-----------------------------------------------+-----------------------+ - -[HorizontalBraces]: images/HorizontalBraces.svg - -#### HTML - -+-----------------------------------+--------------------------------------+-----+ -| \id{a}{a+}b\style{color:red;}{+c} | $`\id{a}{a+}b\style{color:red;}{+c}` | N/A | -+-----------------------------------+--------------------------------------+-----+ - -#### Includegraphics - -$`\def\logo{\includegraphics[height=0.8em, totalheight=0.9em, width=0.9em, alt=sphere]{../docs/sphere.jpg}} -\def\logoB{\includegraphics[height=0.4em, totalheight=0.9em, width=0.9em, alt=sphere]{../docs/sphere.jpg}} -\begin{array}{l} \underline{A\logo} + \sqrt{\logo} + \tfrac{A\logo}{\logo}\\[1em] \underline{A\logoB} + \sqrt{x\logoB} + \tfrac{A\logoB}{\logoB} \end{array}` - -#### Integrands - -+------------------------------------+----------------------------------+--------------------------------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![Integrands](images/Integrands.svg) | -| \displaystyle \int + \oint + \ | \displaystyle \int + \oint + | | -| `\iint + \oiint_i^n \\` \ | \iint + \oiint_i^n \\ | | -| \displaystyle \iiint + \oiiint + \ | \displaystyle \iiint + \oiiint + | | -| `\textstyle \int + \oint_i^n \\` \ | \textstyle \int + \oint_i^n \\ | | -| \iint + \oiint + \ | \iint + \oiint + | | -| \iiint + \oiiint \end{array} | \iiint + \oiiint \end{array}` | | -+------------------------------------+----------------------------------+--------------------------------------+ - -#### Kern - -+----------------------------+-----------------------------+--------------------------+ -| \frac{a\kern{1em}b}{c}a \ | $`\frac{a\kern{1em}b}{c}a | ![kern](images/kern.svg) | -| \kern{1em}b \ | \kern{1em}b | | -| \kern{1ex}c\kern{-0.25em}d | \kern{1ex}c\kern{-0.25em}d` | | -+----------------------------+-----------------------------+--------------------------+ - - -#### Lap - -+----------------------------------------------------+--------------------------------------------------+----------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![lap][] | -| ab\mathllap{f}cd\mathrlap{g}hij\mathclap{k}lm \; \ | ab\mathllap{f}cd\mathrlap{g}hij\mathclap{k}lm \; | | -| ab\llap{f}cd\rlap{g}hij\clap{k}lm \\\\ \ | ab\llap{f}cd\rlap{g}hij\clap{k}lm \\ | | -| \mathrlap{\frac a b}\frac a b \\\\ \ | \mathrlap{\frac a b}{\frac a b} \\ | | -| \mathrlap{\overbrace{ \ | \mathrlap{\overbrace{ | | -| `\phantom{a_0+a_1+a_2}}^m}a_0+a_1+a_2` \ | \phantom{a_0+a_1+a_2}}^m}a_0+a_1+a_2 | | -| \end{array} | \end{array}` | | -+----------------------------------------------------+--------------------------------------------------+----------+ - -[lap]: images/lap.svg - -#### LargeRuleNumerator - -+--------------------------+--------------------------+------------------------------------------------------+ -| \frac{\textcolor{blue} \ | $`\frac{\textcolor{blue} | ![LargeRuleNumerator](images/LargeRuleNumerator.svg) | -| {\rule{1em}{2em}}}{x} | {\rule{1em}{2em}}}{x}` | | -+--------------------------+--------------------------+------------------------------------------------------+ - -#### LaTeX - -+----------------------------+-------------------------------+----------------------------+ -| \text{\LaTeX}, \text{\TeX} | $`\text{\LaTeX}, \text{\TeX}` | ![latex](images/latex.svg) | -+----------------------------+-------------------------------+----------------------------+ - -#### LeftRight - -+----------------------------------+----------------------------------+------------------------------------+ -| \left( x^2 \right) \ | $`\left( x^2 \right) | ![LeftRight](images/LeftRight.svg) | -| \left\\{ x^{x^{x^{x^x}}} \right. | \left\{ x^{x^{x^{x^x}}} \right.` | | -+----------------------------------+----------------------------------+------------------------------------+ - -#### LeftRightListStyling - -+----------------------+-------------------------+----------------------------------------------------------+ -| a+\left(x+y\right)-x | $`a+\left(x+y\right)-x` | ![LeftRightListStyling](images/LeftRightListStyling.svg) | -+----------------------+-------------------------+----------------------------------------------------------+ - -#### LeftRightMiddle - -+----------------------------------------+----------------------------------------+----------------------+ -| \left( x^2 \middle/ \right) \ | $`\left( x^2 \middle/ \right) | ![LeftRightMiddle][] | -| \left\\{ x^{x^{x^{x^x}}} \ | \left\{ x^{x^{x^{x^x}}} | | -| \middle/ y \right. \ | \middle/ y \right. | | -| \left(x\middle|y\\,\middle|\\,z\right) | \left(x\middle|y\,\middle|\,z\right)` | | -+----------------------------------------+----------------------------------------+----------------------+ - -[LeftRightMiddle]: images/LeftRightMiddle.svg - -#### LeftRightStyleSizing - -+----------------------------------------+-----------------------------------------+---------------------------+ -| +\left\\{\rule{0.1em}{1em}\right. \ | $`+\left\{\rule{0.1em}{1em}\right. | ![LeftRightStyleSizing][] | -| x^{+\left\\{\rule{0.1em}{1em}\right. \ | x^{+\left\{\rule{0.1em}{1em}\right. | | -| x^{+\left\\{\rule{0.1em}{1em}\right.}} | x^{+\left\{\rule{0.1em}{1em}\right.}}` | | -+----------------------------------------+-----------------------------------------+---------------------------+ - -[LeftRightStyleSizing]: images/LeftRightStyleSizing.svg - -#### LimitControls - -+-------------------------------------------+------------------------------------------+--------------------+ -| `\displaystyle\int\limits_2^3 3x^2\,dx` \ | $`\displaystyle\int\limits_2^3 3x^2\,dx | ![LimitControls][] | -| `+ \sum\nolimits^n_{i=1}i + ` \ | + \sum\nolimits^n_{i=1}i + | | -| `\textstyle\int\limits_x^y z ` | \textstyle\int\limits_x^y z` | | -+-------------------------------------------+------------------------------------------+--------------------+ - -[LimitControls]: images/LimitControls.svg - -#### LineBreak - -Firefox will apply soft lines breaks after relationss and binary operators. - -$`\frac{x^2}{y^2} + z^2 = z^2 + \frac{x^2}{y^2} = \frac{x^2}{y^2} +\nobreak z^2 = z^2 + \frac{x^2}{y^2} = \frac{x^2}{y^2} + ~ z^2 = z^2 + \frac{x^2}{y^2} = \frac{x^2}{y^2} + \hspace{1em} z^2 = z^2 + \frac{x^2}{y^2} = \frac{x^2}{y^2} + z^2 = \hspace*{1em} z^2 + \frac{x^2}{y^2} = \frac{x^2}{y^2} + z^2 = hi \allowbreak there = hi \allowbreak there` - -#### LowerAccent - -+--------------------------------------------------------+------------------------------------------------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | -| \underleftarrow{AB} \quad \underrightarrow{AB} \quad \ | \underleftarrow{AB} \quad \underrightarrow{AB} \quad | -| \underleftrightarrow{AB} \quad \undergroup{AB} \\\\ \ | \underleftrightarrow{AB} \quad \undergroup{AB} \\ | -| \text{\underline{text}} \quad \utilde{AB} \ | \text{\underline{text}} \quad \utilde{AB} | -| \quad \underrightarrow{AB} \\\\ \ | \quad \underrightarrow{AB} \\ | -| \underrightarrow{F} + \underrightarrow{AB} + \ | \underrightarrow{F} + \underrightarrow{AB} + | -| \underrightarrow{AB}^2 + \underrightarrow{AB}_2 \\\\ \ | \underrightarrow{AB}^2 + \underrightarrow{AB}_2 \\ | -| \frac{\underrightarrow{AB}}{\underrightarrow{AB}} + \ | \frac{\underrightarrow{AB}}{\underrightarrow{AB}} + | -| \sqrt{\underrightarrow{AB}} + \ | \sqrt{\underrightarrow{AB}} + | -| \left\lvert\underrightarrow{AB}\right\rvert \ | \left\lvert\underrightarrow{AB}\right\rvert | -| \end{array} | \end{array}` | -+--------------------------------------------------------+------------------------------------------------------+ - -#### MathChoice - -+---------------------------------------------------+------------------------------------------------+-----------------+ -| {\displaystyle\mathchoice{D}{T}{S}{SS}}\\; \ | $`{\displaystyle\mathchoice{D}{T}{S}{SS}}\; | ![MathChoice][] | -| {\textstyle\mathchoice{D}{T}{S}{SS}}\\; \ | {\textstyle\mathchoice{D}{T}{S}{SS}}\; | | -| {\scriptstyle \mathchoice{D}{T}{S}{SS}}\\; \ | {\scriptstyle \mathchoice{D}{T}{S}{SS}}\; | | -| {\scriptscriptstyle\mathchoice{D}{T}{S}{SS}}\\; \ | {\scriptscriptstyle\mathchoice{D}{T}{S}{SS}}\; | | -| \displaystyle X\_{\mathchoice{D}{T}{S}{SS}\_ \ | \displaystyle X_{\mathchoice{D}{T}{S}{SS}_ | | -| {\mathchoice{D}{T}{S}{SS}}} | {\mathchoice{D}{T}{S}{SS}}}` | | -+---------------------------------------------------+------------------------------------------------+-----------------+ - -[MathChoice]: images/MathChoice.svg - -#### MathDefaultFonts - -+---------------------------------+------------------------------------+ -| Ax2k\breve{a}\omega\Omega\imath | $`Ax2k\breve{a}\omega\Omega\imath` | -+---------------------------------+------------------------------------+ - -#### MathBb - -+------------------------------------------+---------------------------------------------+ -| \mathbb{Ax2k\breve{a}\omega\Omega\imath} | $`\mathbb{Ax2k\breve{a}\omega\Omega\imath}` | -+------------------------------------------+---------------------------------------------+ - -#### MathBf - -+------------------------------------------+---------------------------------------------+ -| \mathbf{Ax2k\breve{a}\omega\Omega\imath} | $`\mathbf{Ax2k\breve{a}\omega\Omega\imath}` | -+------------------------------------------+---------------------------------------------+ - -#### MathCal - -+-------------------------------------------+----------------------------------------------+ -| \mathcal{Ax2k\breve{a}\omega\Omega\imath} | $`\mathcal{Ax2k\breve{a}\omega\Omega\imath}` | -+-------------------------------------------+----------------------------------------------+ - -#### MathFrak - -+--------------------------------------------+-----------------------------------------------+ -| \mathfrak{Ax2k\breve{a}\omega\Omega\imath} | $`\mathfrak{Ax2k\breve{a}\omega\Omega\imath}` | -+--------------------------------------------+-----------------------------------------------+ - -#### MathIt - -+------------------------------------------+---------------------------------------------+ -| \mathit{Ax2k\breve{a}\omega\Omega\imath} | $`\mathit{Ax2k\breve{a}\omega\Omega\imath}` | -+------------------------------------------+---------------------------------------------+ - -#### MathNormal - -+----------------------------------------------+-------------------------------------------------+ -| \mathnormal{Ax2k\breve{a}\omega\Omega\imath} | $`\mathnormal{Ax2k\breve{a}\omega\Omega\imath}` | -+----------------------------------------------+-------------------------------------------------+ - -#### MathOp - -+--------------------------------------+--------------------------------------+------------------------------+ -| a\mathop+b\mathop:c\mathop{\delta} \ | $`a\mathop+b\mathop:c\mathop{\delta} | ![mathop](images/mathop.svg) | -| e\mathop{\textrm{and}}f \ | e\mathop{\textrm{and}}f | | -| \mathrel{\mathop{:}}=g\sin h | \mathrel{\mathop{:}}=g\sin h` | | -+--------------------------------------+--------------------------------------+------------------------------+ - -#### MathRm - -+------------------------------------------+---------------------------------------------+ -| \mathrm{Ax2k\breve{a}\omega\Omega\imath} | $`\mathrm{Ax2k\breve{a}\omega\Omega\imath}` | -+------------------------------------------+---------------------------------------------+ - -#### MathSf - -+------------------------------------------+---------------------------------------------+ -| \mathsf{Ax2k\breve{a}\omega\Omega\imath} | $`\mathsf{Ax2k\breve{a}\omega\Omega\imath}` | -+------------------------------------------+---------------------------------------------+ - -#### MathScr - -+-------------------------------------------+----------------------------------------------+ -| \mathscr{Ax2k\breve{a}\omega\Omega\imath} | $`\mathscr{Ax2k\breve{a}\omega\Omega\imath}` | -+-------------------------------------------+----------------------------------------------+ - -#### MathtoolsMatrix - -+-----------------------+----------------------+------------------------------------------------+ -| \begin{matrix*}[l] \ | $`\begin{matrix*}[l] | ![MathtoolsMatrix](images/MathtoolsMatrix.svg) | -| a & -1 \\\\ \ | a & -1 \\ | | -| -1 & d \ | -1 & d | | -| \end{matrix*} \\; \ | \end{matrix*} \; | | -| \begin{pmatrix*}[r] \ | \begin{pmatrix*}[r] | | -| a & -1 \\\\ \ | a & -1 \\ | | -| -1 & d \ | -1 & d | | -| \end{pmatrix*} | \end{pmatrix*}` | | -+-----------------------+----------------------+------------------------------------------------+ - -#### MathTt - -+------------------------------------------+---------------------------------------------+ -| \mathtt{Ax2k\breve{a}\omega\Omega\imath} | $`\mathtt{Ax2k\breve{a}\omega\Omega\imath}` | -+------------------------------------------+---------------------------------------------+ - -#### Mod - -+-------------------------------------------+---------------------------------------+------------------------+ -| \begin{array}{cc} | $`\begin{array}{cc} | ![mod](images/mod.svg) | -| a \bmod 2 & b \pod 3 \\\\ \ | a \bmod 2 & b \pod 3 \\ | | -| c \pmod{4} & d \mod{56} \\\\ \ | c \pmod{4} & d \mod{56} \\ | | -| \displaystyle a\bmod 2 & b \pod 3 \\\\ \ | \displaystyle a\bmod 2 & b \pod 3 \\ | | -| \displaystyle c\pmod{4} & d \mod{56} \ | \displaystyle c\pmod{4} & d \mod{56} | | -| \end{array} | \end{array}` | | -+-------------------------------------------+---------------------------------------+------------------------+ - -#### NegativeSpace - -+-------------------------+----------------------------+--------------------------------------------+ -| \boxed{\$1,\!000,\!000} | $`\boxed{\$1,\!000,\!000}` | ![NegativeSpace](images/NegativeSpace.svg) | -+-------------------------+----------------------------+--------------------------------------------+ - -#### NestedFractions - -+--------------------------------------+-------------------------------------+----------------------+ -| \dfrac{\frac{a}{b}}{\frac{c}{d}} \ | $`\dfrac{\frac{a}{b}}{\frac{c}{d}} | ![NestedFractions][] | -| \dfrac{\dfrac{a}{b}}{\dfrac{c}{d}} \ | \dfrac{\dfrac{a}{b}} {\dfrac{c}{d}} | | -| \frac{\frac{a}{b}}{\frac{c}{d}} | \frac{\frac{a}{b}}{\frac{c}{d}}` | | -+--------------------------------------+-------------------------------------+----------------------+ - -[NestedFractions]: images/NestedFractions.svg - -#### NewLine - -+--------------------------------+--------------------------------+--------------------------------+ -| \frac{a^2+b^2}{c^2} \newline \ | $`\frac{a^2+b^2}{c^2} \newline | ![newline](images/newline.svg) | -| \frac{a^2+b^2}{c^2} \\\\ \ | \frac{a^2+b^2}{c^2} \\ | | -| \begin{pmatrix} a & b \\\\ \ | \begin{pmatrix} a & b \\ | | -| c & d \cr \end{pmatrix} \\\\ \ | c & d \cr \end{pmatrix} \\ | | -| a+b+c+{d+\\\\e}+f+g | a+b+c+{d+\\e}+f+g` | | -+--------------------------------+--------------------------------+--------------------------------+ - -#### Not - -+--------------------------------------------------------+----------------------------------------------------+----------+ -| \not = \begin{array}{l} \ | $`\not = \begin{array}{l} | ![not][] | -| \not=\not>\not\geq\not\in\not<\not\leq\not{abc} \\\\ \ | \not=\not>\not\geq\not\in\not<\not\leq\not{abc} \\ | | -| \not xy + ab \not xy \\\\ \ | \not xy + ab \not xy \\ | | -| a \neq b \notin c \end{array} | a \neq b \notin c \end{array}` | | -+--------------------------------------------------------+----------------------------------------------------+----------+ - -[not]: images/not.svg - -#### NullDelimiterInteraction - -+---------------------------------------+------------------------------------------+-------------------------------+ -| a \bigl. + 2 \quad \left. + a \right) | $`a \bigl. + 2 \quad \left. + a \right)` | ![NullDelimiterInteraction][] | -+---------------------------------------+------------------------------------------+-------------------------------+ - -[NullDelimiterInteraction]: images/NullDelimiterInteraction.svg - -#### OldFont - -+------------------------------------------------------+--------------------------------------------------+--------------+ -| \begin{matrix} \ | $`\begin{matrix} | ![oldfont][] | -| \rm rm & it & \it it & \ | \rm rm & it & \it it & | | -| \bf bf & \sf sf & \tt tt \\\\ \ | \bf bf & \sf sf & \tt tt \\ | | -| \text{\rm rm} & \text{rm} & \text{\it it} & \ | \text{\rm rm} & \text{rm} & \text{\it it} & | | -| \text{\bf bf} & \text{\sf sf} & \text{\tt tt} \\\\ \ | \text{\bf bf} & \text{\sf sf} & \text{\tt tt} \\ | | -| i\rm r\it i & \text{r\it i\rm r} \ | i\rm r\it i & \text{r\it i\rm r} | | -| \end{matrix} | \end{matrix}` | | -+------------------------------------------------------+--------------------------------------------------+--------------+ - -[oldfont]: images/oldfont.svg - -#### OperatorName - -+----------------------------------------------+------------------------------------------+-------------------+ -| \begin{matrix} | $`\begin{matrix} | ![OperatorName][] | -| \operatorname g (z) + 5\operatorname{g}z \ | \operatorname g (z) + 5\operatorname{g}z | | -| + \operatorname{Gam-ma}(z) \\\\ \ | + \operatorname{Gam-ma}(z) \\ | | -| \operatorname{Gam ma}(z) \ | \operatorname{Gam ma}(z) | | -| + \operatorname{\Gamma}(z) \ | + \operatorname{\Gamma}(z) | | -| + \operatorname{}x \\\\ \ | + \operatorname{}x \\ | | -| \operatorname*{asin} x + \ | \operatorname*{asin} x + | | -| \operatorname*{asin}\_y x + \ | \operatorname*{asin}_y x + | | -| \operatorname*{asin}\limits\_y x \\\\ \ | \operatorname*{asin}\limits_y x \\ | | -| {\displaystyle \operatorname*{asin}\_y x} \ | {\displaystyle \operatorname*{asin}_y x} | | -| \end{matrix} | \end{matrix}` | | -+----------------------------------------------+------------------------------------------+-------------------+ - -[OperatorName]: images/OperatorName.svg - -#### OpLimits - -+--------------------------------------------------------------+----------------------------------------------------------+---------------+ -| \begin{matrix} \ | $`\begin{matrix} | | -| {\sin\_2^2 \lim\_2^2 \int\_2^2 \sum\_2^2} \ | {\sin_2^2 \lim_2^2 \int_2^2 \sum_2^2} | ![OpLimits][] | -| `{\displaystyle \lim_2^2 \int_2^2 \intop_2^2 \sum_2^2} \\` \ | {\displaystyle \lim_2^2 \int_2^2 \intop_2^2 \sum_2^2} \\ | | -| \limsup\_{x \rightarrow \infty} x \stackrel{?}= \ | \limsup_{x \rightarrow \infty} x \stackrel{?}= | | -| \liminf\_{x \rightarrow \infty} x \\\\ \ | \liminf_{x \rightarrow \infty} x \\ | | -| {\displaystyle \limsup\_{x \rightarrow \infty} \ | {\displaystyle \limsup_{x \rightarrow \infty} | | -| `x\:\: \sum_{\substack{00}\to0}}\\\\ \ | {\displaystyle\lim_{t\underset{>0}\to0}}\\ | | -| a+b+c+d\overset{b+c=0} \ | a+b+c+d\overset{b+c=0} | | -| \longrightarrow a+d\\\\ \ | \longrightarrow a+d\\ | | -| \overset { x = y } { \sqrt { a b } } \ | \overset { x = y } { \sqrt { a b } } | | -| \end{array} | \end{array}` | | -+------------------------------------------------+--------------------------------------------+-------------------+ - -[OverUnderset]: images/OverUnderset.svg - -#### Phantom - -+-------------------------------------------------------+---------------------------------------------------+--------------+ -| \begin{array}{l} | $`\begin{array}{l} | ![phantom][] | -| \dfrac{1+\phantom{x^{\textcolor{blue}{2}}} = x} \ | \dfrac{1+\phantom{x^{\textcolor{blue}{2}}} = x} | | -| {1+x^{\textcolor{blue}{2}} = x} \ | {1+x^{\textcolor{blue}{2}} = x} | | -| \left(\vphantom{\int_t} zzz \right) \ | \left(\vphantom{\int_t} zzz \right) | | -| \left( X \hphantom{\frac{\frac X X}{X}} \right)\\\\ \ | \left( X \hphantom{\frac{\frac X X}{X}} \right)\\ | | -| \text{a \phantom{123}} b \hphantom{\frac{1}{2}}=c \ | \text{a \phantom{123}} b \hphantom{\frac{1}{2}}=c | | -| \vphantom{101112} d \\\\ \ | \vphantom{101112} d \\ | | -| \sqrt{\mathstrut a} + \sqrt{\mathstrut d} \ | \sqrt{\mathstrut a} + \sqrt{\mathstrut d} | | -| \end{array} | \end{array}` | | -+-------------------------------------------------------+---------------------------------------------------+--------------+ - -[phantom]: images/phantom.svg - -#### Phase - -+------------------------------------+------------------------------------+ -| 120\text{V}\phase{-78.2^\circ}\; \ | $`120\text{V}\phase{-78.2^\circ}\; | -| \Large\phase{78.2^\circ} | \Large\phase{78.2^\circ}` | -+------------------------------------+------------------------------------+ - -#### Pmb - -+----------------------------------+-------------------------------------+------------------------+ -| \mu\pmb{\mu}\pmb{=}\mu\pmb{+}\mu | $`\mu\pmb{\mu}\pmb{=}\mu\pmb{+}\mu` | ![pmb](images/pmb.svg) | -+----------------------------------+-------------------------------------+------------------------+ - -#### PrimeSpacing - -+------------------+-------------------+------------------------------------------+ -| `f'+f_2'+f^{f'}` | $`f'+f_2'+f^{f'}` | ![PrimeSpacing](images/PrimeSpacing.svg) | -+------------------+-------------------+------------------------------------------+ - -#### PrimeSuper - -+-----------------------------+------------------------------+--------------------------------------+ -| `x'^2+x'''^2+x'^2_3+x_3'^2` | $`x'^2+x'''^2+x'^2_3+x_3'^2` | ![PrimeSuper](images/PrimeSuper.svg) | -+-----------------------------+------------------------------+--------------------------------------+ - -#### Raisebox - -+-------------------------------------------------+--------------------------------------------------+---------------+ -| \frac{a}{a\raisebox{0.5em}{b}} \cdot \ | $`\frac{a}{a\raisebox{0.5em}{b}} \cdot | ![raisebox][] | -| \frac{a\raisebox{-0.5em}{b}}{a} \cdot \ | \frac{a\raisebox{-0.5em}{b}}{a} \cdot | | -| \sqrt{a\raisebox{0.5em}{b}} \cdot \ | \sqrt{a\raisebox{0.5em}{b}} \cdot | | -| \sqrt{a\raisebox{-0.5em}{b}} \cdot \ | \sqrt{a\raisebox{-0.5em}{b}} \cdot | | -| \sqrt{a\raisebox{0.5em}{b}\raisebox{-0.5em}{b}} | \sqrt{a\raisebox{0.5em}{b}\raisebox{-0.5em}{b}}` | | -+-------------------------------------------------+--------------------------------------------------+---------------+ - -[raisebox]: images/raisebox.svg - -#### RelativeUnits - -+------------------------------------------------+----------------------------------------------+--------------------+ -| \begin{array}{ll} \ | $`\begin{array}{ll} | ![RelativeUnits][] | -| a\kern1emb^{a\kern1emb^{a\kern1emb}} & \ | a\kern1emb^{a\kern1emb^{a\kern1emb}} & | | -| {\footnotesize a\kern1emb^ \ | {\footnotesize a\kern1emb^ | | -| {a\kern1emb^{a\kern1emb}}} \\\\ \ | {a\kern1emb^{a\kern1emb}}} \\ | | -| a\mkern18mub^{a\mkern18mub^{a\mkern18mub}} & \ | a\mkern18mub^{a\mkern18mub^{a\mkern18mub}} & | | -| {\footnotesize a\mkern18mub^ \ | {\footnotesize a\mkern18mub^{a\mkern18mub^ | | -| {a\mkern18mub^{a\mkern18mub}}} \\\\ \ | {a\mkern18mub}}} \\ | | -| \end{array} | \end{array}` | | -+------------------------------------------------+----------------------------------------------+--------------------+ - -[RelativeUnits]: images/RelativeUnits.svg - -#### RlapBug - -+-------------------------+---------------------------+--------------------------------+ -| \frac{\mathrlap{x}}{2} | $`\frac{\mathrlap{x}}{2}` | ![rlapbug](images/rlapbug.svg) | -+-------------------------+---------------------------+--------------------------------+ - -#### Rule - -+------------------------------------+-------------------------------------+--------------------------+ -| \rule{1em}{0.5em}\rule{1ex}{2ex} \ | $`\rule{1em}{0.5em}\rule{1ex}{2ex} | ![rule](images/rule.svg) | -| \rule{1em}{1ex}\rule{1em}{0.431ex} | \rule{1em}{1ex}\rule{1em}{0.431ex}` | | -+------------------------------------+-------------------------------------+--------------------------+ - -#### SizingBaseline - -+----------------------------------+-------------------------------------+----------------------------------------------+ -| \text{{\tiny a+b}a+b{\Huge a+b}} | $`\text{{\tiny a+b}a+b{\Huge a+b}}` | ![SizingBaseline](images/SizingBaseline.svg) | -+----------------------------------+-------------------------------------+----------------------------------------------+ - -#### Sizing - -+-----------------------------------+---------------------------------+------------------------------+ -| \text{{\Huge x}{\LARGE y} \ | $`\text{{\Huge x}{\LARGE y} | ![sizing](images/sizing.svg) | -| {\normalsize z}{\scriptsize w}} \ | {\normalsize z}{\scriptsize w}} | | -| \sqrt[\text{\small 3}]{x+1} | \sqrt[\text{\small 3}]{x+1}` | | -+-----------------------------------+---------------------------------+------------------------------+ - -#### Smash - -+-------------------------------+-------------------------------+----------------------------+ -| \left( X^{\smash 2} \right) \ | $`\left( X^{\smash 2} \right) | ![smash](images/smash.svg) | -| \sqrt{\smash[b]{y=}} | \sqrt{\smash[b]{y=}}` | | -+-------------------------------+-------------------------------+----------------------------+ - -#### Spacing - -+--------------------------------------------+----------------------------------------+--------------+ -| \begin{matrix} \ | $`\begin{matrix} | ![spacing][] | -| `^3+[-1][1-1]1=1(=1)\lvert a\rvert~b \\` \ | ^3+[-1][1-1]1=1(=1)\lvert a\rvert~b \\ | | -| `\scriptstyle{^3+[-1][1-1]` \ | \scriptstyle{^3+[-1][1-1] | | -| 1=1(=1)\lvert a\rvert~b} \\\\ \ | 1=1(=1)\lvert a\rvert~b} \\ | | -| `\scriptscriptstyle{^3+[-1][1-1]` \ | \scriptscriptstyle{^3+[-1][1-1] | | -| 1=1(=1)\lvert a\rvert~b} \\\\ \ | 1=1(=1)\lvert a\rvert~b} \\ | | -| a : a \colon a \\\\ \ | a : a \colon a \\ | | -| \end{matrix} | \end{matrix}` | | -+--------------------------------------------+----------------------------------------+--------------+ - -[spacing]: images/spacing.svg - -#### Sqrt - -+------------------------------------------------+----------------------------------------------+-----------+ -| \sqrt{\sqrt{\sqrt{x}}}\_ \ | $`\sqrt{\sqrt{\sqrt{x}}}_ | ![sqrt][] | -| {\sqrt{\sqrt{x}}}^ \ | {\sqrt{\sqrt{x}}}^ | | -| {\sqrt{\sqrt{\sqrt{x}}} \ | {\sqrt{\sqrt{\sqrt{x}}} | | -| ^{\sqrt{\sqrt{\sqrt{x}}}}} \\\\ \ | ^{\sqrt{\sqrt{\sqrt{x}}}}} \\ | | -| \sqrt{\frac{\frac{A}{B}}{\frac{A}{B}}} \\; \ | \sqrt{\frac{\frac{A}{B}}{\frac{A}{B}}} \; | | -| \sqrt{\frac{\frac{\frac{A}{B}}{\frac{A}{B}}} \ | \sqrt{\frac{\frac{\frac{A}{B}}{\frac{A}{B}}} | | -| {\frac{\frac{A}{B}}{\frac{A}{B}}}} | {\frac{\frac{A}{B}}{\frac{A}{B}}}}` | | -+------------------------------------------------+----------------------------------------------+-----------+ - -[sqrt]: images/sqrt.svg - -#### SqrtRoot - -+------------------------------------------------------+--------------------------------------------------+---------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![SqrtRoot][] | -| 1+\sqrt[3]{2}+\sqrt[1923^234] \ | 1+\sqrt[3]{2}+\sqrt[1923^234] | | -| {2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}} \\\\ \ | {2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}} \\ | | -| \Huge \sqrt[3]{M} + x^{\sqrt[3] a} \ | \Huge \sqrt[3]{M} + x^{\sqrt[3] a} | | -| \end{array} | \end{array}` | | -+------------------------------------------------------+--------------------------------------------------+---------------+ - -[SqrtRoot]: images/SqrtRoot.svg - -#### StackRel - -+----------------------------+-----------------------------+----------------------------------+ -| a \stackrel{?}{=} b \ | $`a \stackrel{?}{=} b | ![StackRel](images/StackRel.svg) | -| \stackrel{\text{def}}{=} c | \stackrel{\text{def}}{=} c` | | -+----------------------------+-----------------------------+----------------------------------+ - -#### StretchyAccent - -+---------------------------------------------------------+--------------------------------------------------------+---------------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![StretchyAccent][] | -| \overrightarrow{AB} \quad \overleftarrow{AB} \quad \ | \overrightarrow{AB} \quad \overleftarrow{AB} \quad | | -| \overleftrightarrow{AB} \quad \ | \overleftrightarrow{AB} \quad | | -| \left(\underleftarrow{\frac{value}{j}}\right) \\\\ \ | \left(\underleftarrow{\frac{value}{j}}\right) \\ | | -| \widehat{ABC} \quad \ | \widehat{ABC} \quad | | -| \widetilde{AB} \quad \widetilde{ABC} \\\\ \ | \widetilde{AB} \quad \widetilde{ABC} \\ | | -| \overrightarrow{F} + \overrightarrow{AB} + \ | \overrightarrow{F} + \overrightarrow{AB} + | | -| \overrightarrow{F}^2 + \overrightarrow{F}\_2 + \ | \overrightarrow{F}^2 + \overrightarrow{F}_2 + | | -| \overrightarrow{F}\_1^2 \\\\ \ | \overrightarrow{F}_1^2 \\ | | -| \overrightarrow{AB}^2+ \ | \overrightarrow{AB}^2+ | | -| \frac{\overrightarrow{AB}}{\overrightarrow{AB}} + \ | \frac{\overrightarrow{AB}}{\overrightarrow{AB}} + | | -| \sqrt{\overrightarrow{AB}} + \ | \sqrt{\overrightarrow{AB}} + | | -| \left\lvert\overrightarrow{AB}\right\rvert | \left\lvert\overrightarrow{AB}\right\rvert | | -| \end{array} | \end{array}` | | -+---------------------------------------------------------+--------------------------------------------------------+---------------------+ - -[StretchyAccent]: images/StretchyAccent.svg - -#### StrikeThrough - -+-------------------------------------------+----------------------------------------+--------------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![StrikeThrough][] | -| \cancel x \quad \cancel{2B} + \ | \cancel x \quad \cancel{2B} + | | -| \bcancel 5 +\bcancel{5ay} \\\\ \ | \bcancel 5 +\bcancel{5ay} \\ | | -| \sout{5ab} + \sout{5ABC} + \ | \sout{5ab} + \sout{5ABC} + | | -| \xcancel{\oint\_S{\vec E\cdot\hat n \ | \xcancel{\oint_S{\vec E\cdot\hat n | | -| \\,\mathrm d a}} \\\\[0.3em] \ | \,\mathrm d a}} \\[0.3em] | | -| \frac{x+\cancel B}{x+\cancel x} + \ | \frac{x+\cancel B}{x+\cancel x} + | | -| \frac{x+\cancel y}{x} + \cancel{B}\_1^2 \ | \frac{x+\cancel y}{x} + \cancel{B}_1^2 | | -| + \cancel{B^2} \\\\[0.2em] \ | + \cancel{B^2} \\[0.2em] | | -| \left\lvert\cancel{ac}\right\rvert \ | \left\lvert\cancel{ac}\right\rvert | | -| \end{array} | \end{array}` | | -+-------------------------------------------+----------------------------------------+--------------------+ - -[StrikeThrough]: images/StrikeThrough.svg - -#### StrikeThroughColor - -+----------------------------------------------------------+------------------------------------------------------+-------------------------+ -| \begin{array}{l} | $`\begin{array}{l} | ![StrikeThroughColor][] | -| \textcolor{red}{\cancel x \quad \cancel{2B}} \\\\ \ | \textcolor{red}{\cancel x \quad \cancel{2B}} \\ | | -| \textcolor{red}{\bcancel{\textcolor{black}{5}}} + \ | \textcolor{red}{\bcancel{\textcolor{black}{5}}} + | | -| \textcolor{red}{\bcancel{\textcolor{black}{5ay}}} \\\\ \ | \textcolor{red}{\bcancel{\textcolor{black}{5ay}}} \\ | | -| \color{green}{\sout{5ABC}} \ | \color{green}{\sout{5ABC}} | | -| \end{array} | \end{array}` | | -+----------------------------------------------------------+------------------------------------------------------+-------------------------+ - -[StrikeThroughColor]: images/StrikeThroughColor.svg - -#### StyleSpacing - -+----------------------+------------------------+------------------------------------------+ -| \scriptstyle ab\\;cd | $`\scriptstyle ab\;cd` | ![StyleSpacing](images/StyleSpacing.svg) | -+----------------------+------------------------+------------------------------------------+ - -#### StyleSwitching - -+---------------------------------------+----------------------------------------+---------------------+ -| a\cdot b\scriptstyle a\cdot ba \ | $`a\cdot b\scriptstyle a\cdot ba | ![StyleSwitching][] | -| \textstyle\cdot ba\scriptstyle\cdot b | \textstyle\cdot ba\scriptstyle\cdot b` | | -+---------------------------------------+----------------------------------------+---------------------+ - -[StyleSwitching]: images/StyleSwitching.svg - -#### SupSubCharacterBox - -+------------------------------------------+-------------------------------------------+-------------------------+ -| `a_2f_2{f}_2{aa}_2{af}_2\mathbf{y}_Ay_A` | $`a_2f_2{f}_2{aa}_2{af}_2\mathbf{y}_Ay_A` | ![SupSubCharacterBox][] | -+------------------------------------------+-------------------------------------------+-------------------------+ - -[SupSubCharacterBox]: images/SupSubCharacterBox.svg - -#### SupSubHorizSpacing - -+------------------------------------+----------------------------------+-------------------------+ -| `x^{x^{x}}\Big|` \ | $`x^{x^{x}}\Big| | ![SupSubHorizSpacing][] | -| `x_{x_{x_{x_{x}}}}\bigg|` \ | x_{x_{x_{x_{x}}}}\bigg| | | -| `x^{x^{x_{x_{x_{x_{x}}}}}}\bigg|` | x^{x^{x_{x_{x_{x_{x}}}}}}\bigg|` | | -+------------------------------------+----------------------------------+-------------------------+ - -[SupSubHorizSpacing]: images/SupSubHorizSpacing.svg - -#### SupSubLeftAlignReset - -+-------------------------------------------+----------------------------------------+---------------------------+ -| \omega^8\_{888} \quad \ | $`\omega^8_{888} \quad | ![SupSubLeftAlignReset][] | -| \frac{1}{\hat{\omega}^{8}\_{888}} \quad \ | \frac{1}{\hat{\omega}^{8}_{888}} \quad | | -| \displaystyle\sum\_{\omega^{8}\_{888}} | \displaystyle\sum_{\omega^{8}_{888}}` | | -+-------------------------------------------+----------------------------------------+---------------------------+ - -[SupSubLeftAlignReset]: images/SupSubLeftAlignReset.svg - -#### SupSubOffsets - -+-------------------------------------+-------------------------------------+--------------------+ -| \displaystyle \int_{2+3}x f^{2+3} \ | $`\displaystyle \int_{2+3}x f^{2+3} | ![SupSubOffsets][] | -| +3\lim\_{2+3+4+5}f | +3\lim_{2+3+4+5}f` | | -+-------------------------------------+-------------------------------------+--------------------+ - -[SupSubOffsets]: images/SupSubOffsets.svg - -#### SurrogatePairs - -| Source | Temml | -|-----------------------|------------------------| -| 𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜 | $`𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜` | -| 𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶 | $`𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶` | -| \text{𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜} | $`\text{𝐀𝐚𝟎𝐴𝑎𝑨𝒂𝔅𝔞𝔸𝒜}` | -| \text{𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶} | $`\text{𝖠𝖺𝟢𝗔𝗮𝟬𝘈𝘢𝙰𝚊𝟶}` | -| \mathrm{𝐀𝐚𝑨𝒂𝔅𝔞𝔸𝒜} | $`\mathrm{𝐀𝐚𝑨𝒂𝔅𝔞𝔸𝒜}` | - -#### Symbols1 - -+-------------------------------------------+-------------------------------------------+ -| \maltese\degree\standardstate\pounds\\$ \ | $`\maltese\degree\standardstate\pounds\$ | -| \text{\maltese\degree\pounds\textdollar} | \text{\maltese\degree\pounds\textdollar}` | -+-------------------------------------------+-------------------------------------------+ - -#### Tag - -+-----------------------------------+---------------------------------------+ -| \tag{$+$hi} \frac{x^2}{y}+x^{2^y} | $$\tag{$+$hi} \frac{x^2}{y}+x^{2^y}$$ | -+-----------------------------------+---------------------------------------+ -{colWidths="null 200"} - -#### Text - -+----------------------------------+-------------------------------------+--------------------------+ -| \frac{a}{b}\text{c~ {ab} \ e}+fg | $`\frac{a}{b}\text{c~ {ab} \ e}+fg` | ![text](images/text.svg) | -+----------------------------------+-------------------------------------+--------------------------+ - -#### TextSpace - -+-------------------------------------+-------------------------------+------------------------------------+ -| \begin{array}{l} \ | $`\begin{array}{l} | ![TextSpace](images/TextSpace.svg) | -| \texttt{12345678901234} \\\\ \ | \texttt{12345678901234} \\ | | -| \texttt{A test 1~~2 \ \\ 3} \\\\ \ | \texttt{A test 1~~2\ \ 3} \\ | | -| \verb|A test 1 2 3| \ | \verb|A test 1 2 3| | | -| \end{array} | \end{array}` | | -+-------------------------------------+-------------------------------+------------------------------------+ - -#### TextStacked - -+------------------------------------+----------------------------------+------------------+ -| \begin{matrix} \ | $`\begin{matrix} | ![TextStacked][] | -| \textsf{abc123 \textbf{abc123} \ | \textsf{abc123 \textbf{abc123} | | -| \textit{abc123}}\\\\ \ | \textit{abc123}}\\ | | -| \text{abc123 \textbf{abc123} \ | \text{abc123 \textbf{abc123} | | -| \textit{abc123}}\\\\ \ | \textit{abc123}}\\ | | -| \textrm{abc123 \textbf{abc123} \ | \textrm{abc123 \textbf{abc123} | | -| \textit{abc123}}\\\\ \ | \textit{abc123}}\\ | | -| \textsf{\textrm{\textbf{abc123}} \ | \textsf{\textrm{\textbf{abc123}} | | -| \textbf{abc123} \ | \textbf{abc123} | | -| \textit{abc123}}\\\\ \ | \textit{abc123}}\\ | | -| \textit{abc123 \textbf{abc123} \ | \textit{abc123 \textbf{abc123} | | -| \textsf{abc123}}\\\\ \ | \textsf{abc123}}\\ | | -| \end{matrix} | \end{matrix}` | | -+------------------------------------+----------------------------------+------------------+ - -[TextStacked]: images/TextStacked.svg - -#### TextWithMath - -+---------------------------------------------------+-----------------------------------------------+-------------------+ -| \begin{matrix} \ | $`\begin{matrix} | ![TextWithMath][] | -| \text{for $a < b$ and $ c < d $}. \\\\ \ | \text{for $a < b$ and $ c < d $}. \\ | | -| \textsf{for $a < b$ and $ c < d $}. \\\\ \ | \textsf{for $a < b$ and $ c < d $}. \\ | | -| \textsf{for $a < b \textbf{ and } c < d $} \\\\ \ | \textsf{for $a < b \textbf{ and } c < d $} \\ | | -| \text{\sf for $a < b$ and $c < d$.} \ | \text{\sf for $a < b$ and $c < d$.} | | -| \end{matrix} | \end{matrix}` | | -+---------------------------------------------------+-----------------------------------------------+-------------------+ - -[TextWithMath]: images/TextWithMath.svg - -#### Unicode - -| Source | Temml | -|----------------------|-------------------------| -| \text{ÀàÇçÉéÏïÖöÛû} | $`\text{ÀàÇçÉéÏïÖöÛû}` | -| \text{БГДЖЗЙЛФЦШЫЮЯ} | $`\text{БГДЖЗЙЛФЦШЫЮЯ}` | -| \text{여보세요} | $`\text{여보세요}` | -| \text{私はバナナです} | $`\text{私はバナナです}` | - -#### Units - -+------------------------------------------------+----------------------------------------------+------------+ -| \begin{array}{ll} \ | $`\begin{array}{ll} | ![units][] | -| \mathrm H\kern 1em\mathrm H \ | \mathrm H\kern 1em\mathrm H | | -| \text{\tiny (1em)} & \ | \text{\tiny (1em)} & | | -| \mathrm H\kern 1ex\mathrm H \ | \mathrm H\kern 1ex\mathrm H | | -| \text{\tiny (1ex)} \\\\ \ | \text{\tiny (1ex)} \\ | | -| \mathrm H{\scriptstyle \kern 1em}\mathrm H \ | \mathrm H{\scriptstyle \kern 1em}\mathrm H | | -| \text{\tiny (ss 1em)} & \ | \text{\tiny (ss 1em)} & | | -| \mathrm H{\scriptstyle \kern 1ex}\mathrm H \ | \mathrm H{\scriptstyle \kern 1ex}\mathrm H | | -| \text{\tiny (ss 1ex)} \\\\ \ | \text{\tiny (ss 1ex)} \\ | | -| \mathrm H{\small \kern 1em}\mathrm H \ | \mathrm H{\small \kern 1em}\mathrm H | | -| \text{\tiny (sm 1em)} & \ | \text{\tiny (sm 1em)} & | | -| \mathrm H{\small \kern 1ex}\mathrm H \ | \mathrm H{\small \kern 1ex}\mathrm H | | -| \text{\tiny (sm 1ex)} \\\\ \ | \text{\tiny (sm 1ex)} \\ | | -| \mathrm H\mkern 18mu\mathrm H \ | \mathrm H\mkern 18mu\mathrm H | | -| \text{\tiny (18mu)} & \ | \text{\tiny (18mu)} & | | -| \mathrm H\kern 1cm\mathrm H \ | \mathrm H\kern 1cm\mathrm H | | -| \text{\tiny (1cm)} \\\\ \ | \text{\tiny (1cm)} \\ | | -| \mathrm H{\scriptstyle \mkern 18mu}\mathrm H \ | \mathrm H{\scriptstyle \mkern 18mu}\mathrm H | | -| \text{\tiny (ss 18mu)} & \ | \text{\tiny (ss 18mu)} & | | -| \mathrm H{\scriptstyle \kern 1cm}\mathrm H \ | \mathrm H{\scriptstyle \kern 1cm}\mathrm H | | -| \text{\tiny (ss 1cm)} \\\\ \ | \text{\tiny (ss 1cm)} \\ | | -| \mathrm H{\small \mkern 18mu}\mathrm H \ | \mathrm H{\small \mkern 18mu}\mathrm H | | -| \text{\tiny (sm 18mu)} & \ | \text{\tiny (sm 18mu)} & | | -| \mathrm H{\small \kern 1cm}\mathrm H \ | \mathrm H{\small \kern 1cm}\mathrm H | | -| \text{\tiny (sm 1cm)} \ | \text{\tiny (sm 1cm)} | | -| \end{array} | \end{array}` | | -+------------------------------------------------+----------------------------------------------+------------+ - -[units]: images/units.svg - -#### UnsupportedCmds - -$`\err\,\frac\fracerr3\,2^\superr_\suberr\,\sqrt\sqrterr` - -deliberately does not compile - -#### Verb - -+-------------------------------------------------------+---------------------------------------------------+-----------+ -| \begin{array}{ll} \ | $`\begin{array}{ll} | ![verb][] | -| \verb \verb , & \verb|\verb |, \\\\ \ | \verb \verb , & \verb|\verb |, \\ | | -| \verb* \verb* , & \verb*|\verb* |, \\\\ \ | \verb* \verb* , & \verb*|\verb* |, \\ | | -| \verb! & ! & \scriptstyle\verb|ss verb| \\\\ \ | \verb! & ! & \scriptstyle\verb|ss verb| \\ | | -| \verb*! & ! & \small\verb|sm verb| \\\\ \ | \verb*! & ! & \small\verb|sm verb| \\ | | -| \verb|``---''~| \ | \verb|``---''~| | | -| \end{array} | \end{array}` | | -+-------------------------------------------------------+---------------------------------------------------+-----------+ - -[verb]: images/verb.svg - - - \ No newline at end of file diff --git a/test/main.css b/test/main.css deleted file mode 100644 index 17df816f..00000000 --- a/test/main.css +++ /dev/null @@ -1,16 +0,0 @@ -body { - margin: 0; - padding: 0; - font-size: 24px; -} - -#math { - font-size: 72px; -} - -#input { - margin: 0; - font-size: 100%; - width: 100%; - box-sizing: border-box; -} diff --git a/test/mhchem-tests.md b/test/mhchem-tests.md deleted file mode 100644 index f988ff1e..00000000 --- a/test/mhchem-tests.md +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - Temml mhchem Tests - - - - - - - - -# mhchem - -This file contains all the examples in the `mhchem` manual.\ -Ref: https://mhchem.github.io/MathJax-mhchem/ - -## Chemical Equations (ce) - -| Source | Temml | -|------------------------------------------------|-------------------------| -| `\ce{CO2 + C -> 2 CO}` | $`\ce{CO2 + C -> 2 CO}` | -| `\ce{Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2-}` | $`\ce{Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2-}` | -| `C_p[\ce{H2O(l)}] = \pu{75.3 J // mol K}` | $`C_p[\ce{H2O(l)}] = \pu{75.3 J // mol K}` | - -## Chemical Formulae - -| Source | Temml | -|--------------|---------------| -| `\ce{H2O}` | $`\ce{H2O}` | -| `\ce{Sb2O3}` | $`\ce{Sb2O3}` | - -## Charges - -| Source | Temml | -|-----------------|------------------| -| `\ce{H+}` | $`\ce{H+}` | -| `\ce{CrO4^2-}` | $`\ce{CrO4^2-}` | -| `\ce{[AgCl2]-}` | $`\ce{[AgCl2]-}` | -| `\ce{Y^99+}` | $`\ce{Y^99+}` | -| `\ce{Y^{99+}}` | $`\ce{Y^{99+}}` | - -## Stoichiometric Numbers - -| Source | Temml | -|-----------------|--------------------| -| `\ce{2 H2O}` | $`\ce{2 H2O}` | -| `\ce{2H2O}` | $`\ce{2H2O}` | -| `\ce{0.5 H2O}` | $`\ce{0.5 H2O}` | -| `\ce{1/2 H2O}` | $`\ce{1/2 H2O}` | -| `\ce{(1/2) H2O}` | $`\ce{(1/2) H2O}` | -| `\ce{$n$ H2O}` | $`\ce{$n$ H2O}` | - -## Isotopes - -+-----------------------+------------------------------+ -| `\ce{^{227}_{90}Th+}` | $`\ce{^{227}_{90}Th+}` | -+-----------------------+------------------------------+ -| `\ce{^227_90Th+}` | $`\ce{^227_90Th+}` | -+-----------------------+------------------------------+ -| `\ce{^{0}_{-1}n^{-}}` | $`\ce{^{0}_{-1}n^{-}}` | -+-----------------------+------------------------------+ -| `\ce{^0_-1n-}` | $`\ce{^0_-1n-}` | -+-----------------------+------------------------------+ -| `\ce{H{}^3HO}` | $`\ce{H{}^3HO}` | -+-----------------------+------------------------------+ -| `\ce{H^3HO}` | $`\ce{H^3HO}` | -+-----------------------+------------------------------+ - -## Reaction Arrows - -| Source | Temml | -|------------------|------------------| -| `\ce{A -> B}` | $`\ce{A -> B}` | -| `\ce{A <- B}` | $`\ce{A <- B}` | -| `\ce{A <-> B}` | $`\ce{A <-> B}` | -| `\ce{A <--> B}` | $`\ce{A <--> B}` | -| `\ce{A <=> B}` | $`\ce{A <=> B}` | -| `\ce{A <=>> B}` | $`\ce{A <=>> B}` | -| `\ce{A <<=> B}` | $`\ce{A <<=> B}` | -| `\ce{A ->[H2O] B}` | $`\ce{A ->[H2O] B}` | -| `\ce{A ->[{text above}][{text below}] B}` | $`\ce{A ->[{text above}][{text below}] B}` | -| `\ce{A ->[$x$][$x_i$] B}` | $`\ce{A ->[$x$][$x_i$] B}` | - -## Parentheses, Brackets, Braces - -| Source | Temml | -|------------------------|------------------| -| `\ce{(NH4)2S}` | $`\ce{(NH4)2S}` | -| `\ce{[\{(X2)3\}2]^3+}` | $`\ce{[\{(X2)3\}2]^3+}` | -| `\ce{CH4 + 2 $\left( \ce{O2 + 79/21 N2} \right)$}` | $`\ce{CH4 + 2 $\left( \ce{O2 + 79/21 N2} \right) $}` | - -## States of Aggregation - -| Source | Temml | -|--------------------------|-----------------------------| -| `\ce{H2(aq)}` | $`\ce{H2(aq)}` | -| `\ce{CO3^2-_{(aq)}}` | $`\ce{CO3^2-_{(aq)}}` | -| `\ce{NaOH(aq,$\infty$)}` | $`\ce{NaOH(aq, $\infty $)}` | - -## Crystal Systems - -| Source | Temml | -|--------------------|---------------------| -| `\ce{ZnS($c$)}` | $`\ce{ZnS($c$)}` | -| `\ce{ZnS(\ca$c$)}` | $`\ce{ZnS(\ca$c$)}` | - -## Variables - -+--------------------------------+--------------------------------+ -| Source | Temml | -+================================+================================+ -| `\ce{NO_x}` | $`\ce{NO_x}` | -+--------------------------------+--------------------------------+ -| `\ce{Fe^n+}` | $`\ce{Fe^n+}` | -+--------------------------------+--------------------------------+ -| \ce{x Na(NH4)HPO4 ->[\Delta] \ | $`\ce{x Na(NH4)HPO4 ->[\Delta] | -| (NaPO3)_x + x NH3 ^ + x H2O} | (NaPO3)_x + x NH3 ^ + x H2O}` | -+--------------------------------+--------------------------------+ - -## Greek Characters - -| Source | Temml | -|------------------------------------|---------------------| -| `\ce{\mu-Cl}` | $`\ce{\mu-Cl}` | -| `\ce{[Pt(\eta^2-C2H4)Cl3]-}` | $`\ce{[Pt(\eta^2-C2H4)Cl3]-}` | -| `\ce{\beta +}` | $`\ce{\beta +}` | -| `\ce{^40_18Ar + \gamma{} + \nu_e}` | $`\ce{^40_18Ar + \gamma{} + \nu_e}` | - -## (Italic) Math - -| Source | Temml | -|-------------------------------|------------------| -| `\ce{NaOH(aq,$\infty$)}` | $`\ce{NaOH(aq,$\infty$)}` | -| `\ce{Fe(CN)_{$\frac{6}{2}$}}` | $`\ce{Fe(CN)_{{$\frac{6}{2}$}}}` | -| `\ce{X_{$i$}^{$x$}}` | $`\ce{X_{$i$}^{$x$}}` | -| `\ce{X_$i$^$x$}` | $`\ce{X_{$i$}^{$x$}}` | - -## Italic Text - -| Source | Temml | -|-------------------------------|------------------| -| `\ce{$cis${-}[PtCl2(NH3)2]}` | $`\ce{$cis${-}[PtCl2(NH3)2]}` | -| `\ce{CuS($hP12$)}` | $`\ce{CuS($hP12$)}` | - -## Upright Text, Escape Parsing - -| Source | Temml | -|---------------------------------|------------------| -| `\ce{{Gluconic Acid} + H2O2}` | $`\ce{{Gluconic Acid} + H2O2}` | -| `\ce{X_{{red}}}` | $`\ce{X_{{red}}}` | -| `\ce{{(+)}_589{-}[Co(en)3]Cl3}` | $`\ce{{(+)}_589{-}[Co(en)3]Cl3}` | - -## Bonds - -| Source | Temml | -|------------------------------------------|------------------| -| `\ce{C6H5-CHO}` | $`\ce{C6H5-CHO}` | -| `\ce{A-B=C#D}` | $`\ce{A-B=C#D}` | -| `\ce{A\bond{-}B\bond{=}C\bond{#}D}` | $`\ce{A\bond{-}B\bond{=}C\bond{#}D}` | -| `\ce{A\bond{1}B\bond{2}C\bond{3}D}` | $`\ce{A\bond{1}B\bond{2}C\bond{3}D}` | -| `\ce{A\bond{~}B\bond{~-}C}` | $`\ce{A\bond{~}B\bond{~-}C}` | -| `\ce{A\bond{~--}B\bond{~=}C\bond{-~-}D}` | $`\ce{A\bond{~--}B\bond{~=}C\bond{-~-}D}` | -| `\ce{A\bond{...}B\bond{....}C}` | $`\ce{A\bond{...}B\bond{....}C}` | -| `\ce{A\bond{->}B\bond{<-}C}` | $`\ce{A\bond{->}B\bond{<-}C}` | - -## Addition Compounds - -| Source | Temml | -|---------------------------|------------------| -| `\ce{KCr(SO4)2*12H2O}` | $`\ce{KCr(SO4)2*12H2O}` | -| `\ce{KCr(SO4)2.12H2O}` | $`\ce{KCr(SO4)2.12H2O}` | -| `\ce{KCr(SO4)2 * 12 H2O}` | $`\ce{KCr(SO4)2 * 12 H2O}` | - -## Oxidation States - -| Source | Temml | -|---------------------------|------------------| -| `\ce{Fe^{II}Fe^{III}2O4}` | $`\ce{Fe^{II}Fe^{III}2O4}` | - -## Unpaired Electrons, Radical Dots - -| Source | Temml | -|-------------------|--------------------| -| `\ce{OCO^{.-}}` | $`\ce{OCO^{.-}}` | -| `\ce{NO^{(2.)-}}` | $`\ce{NO^{(2.)-}}` | - -## Kröger-Vink Notation - -+------------------------------------+---------------------------------------+ -| Source | Temml | -+====================================+=======================================+ -| `\ce{Li^x_{Li,1-2x}Mg^._{Li,x}` \ | $``\ce{Li^x_{Li,1-2x}Mg^._{Li,x} | -| ``$V$'_{Li,x}Cl^x_{Cl}}`` | $V$'_{Li,x}Cl^x_{Cl}}`` | -+------------------------------------+---------------------------------------+ -| ```\ce{O''_{i,x}}``` | $```\ce{O''_{i,x}}``` | -+------------------------------------+---------------------------------------+ -| `\ce{M^{..}_i}` | $`\ce{M^{..}_i}` | -+------------------------------------+---------------------------------------+ -| ``\ce{$V$^{4'}_{Ti}}`` | $``\ce{ $V $^{4'}_{Ti}}`` | -+------------------------------------+---------------------------------------+ -| `\ce{V_{V,1}C_{C,0.8}$V$_{C,0.2}}` | $`\ce{V_{V,1}C_{C,0.8} $V $_{C,0.2}}` | -+------------------------------------+---------------------------------------+ - -## Equation Operators - -| Source | Temml | -|----------------|-----------------| -| `\ce{A + B}` | $`\ce{A + B}` | -| `\ce{A - B}` | $`\ce{A - B}` | -| `\ce{A = B}` | $`\ce{A = B}` | -| `\ce{A \pm B}` | $`\ce{A \pm B}` | - -## Precipitate and Gas - -| Source | Temml | -|----------------------------------|------------------| -| `\ce{SO4^2- + Ba^2+ -> BaSO4 v}` | $`\ce{SO4^2- + Ba^2+ -> BaSO4 v}` | -| `\ce{A v B (v) -> B ^ B (^)}` | $`\ce{A v B (v) -> B ^ B (^)}` | - -## Other Symbols and Shortcuts - -| Source | Temml | -|---------------------|----------------| -| `\ce{NO^*}` | $`\ce{NO^*}` | -| `\ce{1s^2-N}` | $`\ce{1s^2-N}` | -| `\ce{n-Pr}` | $`\ce{n-Pr}` | -| `\ce{iPr}` | $`\ce{iPr}` | -| `\ce{\ca Fe}` | $`\ce{\ca Fe}` | -| `\ce{A, B, C; F}` | $`\ce{A, B, C; F}` | -| `\ce{{and others}}` | $`\ce{{and others}}` | - -## Complex Examples - -+------------------------------------------+------------------------------------------+ -| Source | Temml | -+==========================================+==========================================+ -| \ce{Zn^2+ <=>[+ 2OH-][+ 2H+] \ | $`\ce{Zn^2+ <=>[+ 2OH-][+ 2H+] | -| $\underset{\text{amphoteres Hydroxid}} \ | $\underset{\text{amphoteres Hydroxid}} | -| {\ce{Zn(OH)2 v}}$ <=>[+ 2OH-][+ 2H+] \ | {\ce{Zn(OH)2 v}} $ <=>[+ 2OH-][+ 2H+] | -| $\underset{\text{Hydroxozikat}} \ | {$\underset{\text{Hydroxozikat}} | -| {\ce{[Zn(OH)4]^2-}}$} | {\ce{[Zn(OH)4]^2-}}$}}` | -+------------------------------------------+------------------------------------------+ -| \ce{$K = \frac{[\ce{Hg^2+}][\ce{Hg}]} \ | $`\ce{ $K = \frac{[\ce{Hg^2+}][\ce{Hg}]} | -| {[\ce{Hg2^2+}]}$} | {[\ce{Hg2^2+}]} $}` | -+------------------------------------------+------------------------------------------+ -| \ce{$K = \ | $`\ce{ $K = | -| \ce{\frac{[Hg^2+][Hg]}{[Hg2^2+]}}$} | \ce{\frac{[Hg^2+][Hg]}{[Hg2^2+]}} $}` | -+------------------------------------------+------------------------------------------+ -| \ce{Hg^2+ ->[I-] \ | $`\ce{Hg^2+ ->[I-] | -| $\underset{\mathrm{red}}{\ce{HgI2}}$ \ | $\underset{\mathrm{red}}{\ce{HgI2}} $ | -| ->[I-] $\underset{\mathrm{red}} \ | ->[I-] $\underset{\mathrm{red}} | -| {\ce{[Hg^{II}I4]^2-}}$} | {\ce{[Hg^{II}I4]^2-}} $}` | -+------------------------------------------+------------------------------------------+ - -## Physical Units - -| Source | Temml | -|---------------------|-----------------| -| `\pu{123 kJ}` | $`\pu{123 kJ}` | -| `\pu{123 mm2}` | $`\pu{123 mm2}` | -| `\pu{123 J s}` | $`\pu{123 J s}` | -| `\pu{123 J*s}` | $`\pu{123 J*s}` | -| `\pu{123 kJ/mol}` | $`\pu{123 kJ/mol}` | -| `\pu{123 kJ//mol}` | $`\pu{123 kJ//mol}` | -| `\pu{123 kJ mol-1}` | $`\pu{123 kJ mol-1}` | -| `\pu{123 kJ*mol-1}` | $`\pu{123 kJ*mol-1}` | -| `\pu{1.2e3 kJ}` | $`\pu{1.2e3 kJ}` | -| `\pu{1,2e3 kJ}` | $`\pu{1,2e3 kJ}` | -| `\pu{1.2E3 kJ}` | $`\pu{1.2E3 kJ}` | -| `\pu{1,2E3 kJ}` | $`\pu{1,2E3 kJ}` | - - - \ No newline at end of file diff --git a/test/mozilla-tests.md b/test/mozilla-tests.md deleted file mode 100644 index e0e4633c..00000000 --- a/test/mozilla-tests.md +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - Temml Mozilla Tests - - - - - - - - -# Mozilla Torture Test - -This page reproduces the tests from \ -https://www-archive.mozilla.org/projects/mathml/demo/texvsmml.xhtml and \ -https://fred-wang.github.io/MathFonts/mozilla\_mathml\_test/ - -Images from LaTeX are also included for comparison. - -
- -+----+------------------------------+------------------------------+-----------+--------------+ -| | Source | Temml | LaTeX | Comment | -+====+==============================+==============================+===========+==============+ -| 1 | x^2y^2 | $$x^2y^2$$ | ![ex1][] | TeXbook p128 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 2 | \_2F\_3 | $$_2F_3$$ | ![ex2][] | TeXbook p128 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 3 | x+y^2\over k+1 | $$x+y^2\over k+1$$ | ![ex3][] | TeXbook p139 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 4 | x+y^{2\over k+1} | $$x+y^{2\over k+1}$$ | ![ex4][] | TeXbook p139 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 5 | a\over{b/2} | $$a\over{b/2}$$ | ![ex5][] | TeXbook p139 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 6 | a\_0 + \cfrac{1}{a\_1 + \ | $$a_0 + \cfrac{1}{a_1 + | ![ex6][] | TeXbook p142 | -| | \cfrac{1}{a\_2 + \ | \cfrac{1}{a_2 + | | | -| | \cfrac{1}{a\_3 + \ | \cfrac{1}{a_3 + | | | -| | \cfrac{1}{a\_4}}}} | \cfrac{1}{a_4}}}}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 7 | a\_0+{1\over a\_1+{1\over \ | $$a_0+{1\over a_1+{1\over | ![ex7][] | TeXbook p142 | -| | a\_2+{1\over a\_3+ \ | a_2+{1\over a_3+ | | | -| | {1\over a\_4}}}} | {1\over a_4}}}}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 8 | n\choose {k / 2} | $$n\choose {k / 2}$$ | ![ex8][] | TeXbook p143 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 9 | {p \choose 2} x^2 y^{p-2} \ | $${p \choose 2} x^2 y^{p-2} | ![ex9][] | TeXbook p143 | -| | - {1\over{1-x}} \ | - {1\over{1-x}} | | | -| | {1\over{1-x^2}} | {1\over{1-x^2}}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 10 | \sum\_{\scriptstyle 0 \le\ | $$\sum_{\scriptstyle 0 \le | ![ex10][] | TeXbook p145 | -| | i \le m \atop \scriptstyle\ | i \le m \atop \scriptstyle | | | -| | 0 < j < n} P(i, j) | 0 < j < n} P(i, j)$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 11 | x^{2y} | $$x^{2y}$$ | ![ex11][] | TeXbook p128 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 12 | \sum\_{i=1}^p \ | $$\sum_{i=1}^p | ![ex12][] | TeXbook p145 | -| | \sum\_{j=1}^q \ | \sum_{j=1}^q | | | -| | \sum\_{k=1}^r \ | \sum_{k=1}^r | | | -| | a\_{ij}b\_{jk}c\_{ki} | a_{ij}b_{jk}c_{ki}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 13 | \sqrt{1+\sqrt{1+\sqrt{1+ \ | $$\sqrt{1+\sqrt{1+\sqrt{1+ | ![ex13][] | TeXbook p145 | -| | \sqrt{1+\sqrt{1+\sqrt{1+ \ | \sqrt{1+\sqrt{1+\sqrt{1+ | | | -| | \sqrt{1+x}}}}}}} | \sqrt{1+x}}}}}}}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 14 | \bigg(\frac{\partial^2} \ | $$\bigg(\frac{\partial^2} | ![ex14][] | TeXbook p147 | -| | {\partial x^2} + \frac \ | {\partial x^2} + \frac | | | -| | {\partial^2}{\partial y^2}\ | {\partial^2}{\partial y^2} | | | -| | \bigg) \big\lvert\varphi \ | \bigg) \big\lvert\varphi | | | -| | (x+iy)\big\rvert^2 | (x+iy)\big\rvert^2$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 15 | 2^{2^{2^x}} | $$2^{2^{2^x}}$$ | ![ex15][] | TeXbook p128 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 16 | \int\_1^x {dt\over t} | $$\int_1^x {dt\over t}$$ | ![ex16][] | TeXbook p168 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 17 | \int\\!\\!\\!\int\_D dx\,dy | $$\int\!\!\!\int_D dx\,dy$$ | ![ex17][] | TeXbook p169 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 18 | f(x) = \begin{cases}1/3 & \ | $$f(x) = \begin{cases}1/3 & | ![ex18][] | TeXbook p175 | -| | \text{if }0 \le x \le 1; \ | \text{if }0 \le x \le 1; \\ | | | -| | \\\\ \ | 2/3 & \text{if }3\le x \le | | | -| | 2/3 & \text{if }3\le x \le \ | 4;\\ 0 & \text{elsewhere.} | | | -| | 4;\\\\ 0 &\text{elsewhere.}\ | \end{cases}$$ | | | -| | \end{cases} | | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 19 | \overbrace{x +\cdots + x} \ | $$\overbrace{x +\cdots + x} | ![ex19][] | TeXbook p176 | -| | ^{k \text{ times}} | ^{k \text{ times}}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 20 | y\_{x^2} | $$y_{x^2}$$ | ![ex20][] | TeXbook p128 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 21 | \sum\_{p\text{ prime}} \ | $$\sum_{p\text{ prime}}f(p) | ![ex21][] | TeXbook p181 | -| | f(p)=\int\_{t>1} f(t)d\pi(t) | =\int_{t>1} f(t)d\pi(t)$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 22 | \{\underbrace{\overbrace{ \ | $$\{\underbrace{\overbrace{ | ![ex22][] | TeXbook p181 | -| | \mathstrut a,\dots,a}^{k \ | \mathstrut a,\dots,a}^{k | | | -| | \,a\rq\text{s}},\overbrace{\ | \,a\rq\text{s}},\overbrace{ | | | -| | \mathstrut b,\dots,b}^{l\,\ | \mathstrut b,\dots,b}^{l\, | | | -| | b\rq\text{s}}}\_{k+l \ | b\rq\text{s}}}_{k+l | | | -| | \text{ elements}}\} | \text{ elements}}\}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 23 | \begin{pmatrix} \ | $$\begin{pmatrix} | ![ex23][] | TeXbook p181 | -| | \begin{pmatrix}a&b\\\\c&d \ | \begin{pmatrix}a&b\\c&d | | | -| | \end{pmatrix} & \ | \end{pmatrix} & | | | -| | \begin{pmatrix}e&f\\\\g&h \ | \begin{pmatrix}e&f\\g&h | | | -| | \end{pmatrix} \\\\ 0 & \ | \end{pmatrix} \\ 0 & | | | -| | \begin{pmatrix}i&j\\\\k&l \ | \begin{pmatrix}i&j\\k&l | | | -| | \end{pmatrix} \ | \end{pmatrix} | | | -| | \end{pmatrix} | \end{pmatrix}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 24 | `\det\begin{vmatrix}` \ | $$\det\begin{vmatrix} | ![ex24][] | TeXbook p181 | -| | `c_0&c_1&c_2&\dots& c_n\\`\ `| c_0&c_1&c_2&\dots& c_n\\ | | | -| | `c_1 & c_2 & c_3 & \dots &`\ | c_1 & c_2 & c_3 & \dots & | | | -| | `c_{n+1}\\ c_2 & c_3 & c_4`\ | c_{n+1}\\ c_2 & c_3 & c_4 | | | -| | `&\dots & c_{n+2}\\ \vdots`\ | &\dots & c_{n+2}\\ \vdots | | | -| | `&\vdots&\vdots & &\vdots` \ | &\vdots&\vdots & &\vdots | | | -| | `\\c_n & c_{n+1} & c_{n+2}`\ | \\c_n & c_{n+1} & c_{n+2} | | | -| | `&\dots&c_{2n}` \ | &\dots&c_{2n} | | | -| | `\end{vmatrix} > 0` | \end{vmatrix} > 0$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 25 | y\_{x\_2} | $$y_{x_2}$$ | ![ex25][] | TeXbook p128 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 26 | x\_{92}^{31415} + \pi | $$x_{92}^{31415} + \pi$$ | ![ex26][] | TeXbook p129 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 27 | x\_{y^a\_b}^{z^c\_d} | $$x_{y^a_b}^{z^c_d}$$ | ![ex27][] | TeXbook p129 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 28 | y\_3''' | $$y_3'''$$ | ![ex28][] | TeXbook p130 | -+----+------------------------------+------------------------------+-----------+--------------+ -| 29 | \lim\_{n\rightarrow+\infty}\ | $$\lim_{n\rightarrow+\infty} | ![ex29][] | | -| | {\sqrt{2\pi n}\over n!} \ | {\sqrt{2\pi n}\over n!} | | | -| | {\binom{n}{e}}^n = 1 | {\binom{n}{e}}^n = 1$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ -| 30 | \det(A) = \sum\_{\sigma \ | $$\det(A) = \sum_{\sigma | ![ex30][] | | -| | \in S_n} \epsilon(\sigma) \ | \in S_n} \epsilon(\sigma) | | | -| | \prod\_{i=1}^n \ | \prod_{i=1}^n | | | -| | a\_{i, \sigma\_i} | a_{i, \sigma_i}$$ | | | -+----+------------------------------+------------------------------+-----------+--------------+ - -[ex1]: images/ex1.gif -[ex2]: images/ex2.gif -[ex3]: images/ex3.gif -[ex4]: images/ex4.gif -[ex5]: images/ex5.gif -[ex6]: images/ex6.gif -[ex7]: images/ex7.gif -[ex8]: images/ex8.gif -[ex9]: images/ex9.gif -[ex10]: images/ex10.gif -[ex11]: images/ex11.gif -[ex12]: images/ex12.gif -[ex13]: images/ex13.gif -[ex14]: images/ex14.gif -[ex15]: images/ex15.gif -[ex16]: images/ex16.gif -[ex17]: images/ex17.gif -[ex18]: images/ex18.gif -[ex19]: images/ex19.gif -[ex20]: images/ex20.gif -[ex21]: images/ex21.gif -[ex22]: images/ex22.gif -[ex23]: images/ex23.gif -[ex24]: images/ex24.gif -[ex25]: images/ex25.gif -[ex26]: images/ex26.gif -[ex27]: images/ex27.gif -[ex28]: images/ex28.gif -[ex29]: images/ex29.png -[ex30]: images/ex30.png - - - diff --git a/test/processTests.js b/test/processTests.js deleted file mode 100644 index 7b0cda00..00000000 --- a/test/processTests.js +++ /dev/null @@ -1,6 +0,0 @@ -const fs = require("fs") // Node.js file system - -let str = fs.readFileSync('./test/katex-spec1.js').toString('utf8') -str = str.replace(/Expect(`[^`]*`)/g, - 'Expect($1)') -fs.writeFileSync('./test/katex-spec2.js', str) diff --git a/test/repl.html b/test/repl.html deleted file mode 100644 index 76468a7f..00000000 --- a/test/repl.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Temml REPL - - - - - - - - - - - - - - - -
- - diff --git a/test/temml.js b/test/temml.js deleted file mode 100644 index 539c035a..00000000 --- a/test/temml.js +++ /dev/null @@ -1,11204 +0,0 @@ -var temml = (function () { - 'use strict'; - - /** - * This is the ParseError class, which is the main error thrown by Temml - * functions when something has gone wrong. This is used to distinguish internal - * errors from errors in the expression that the user provided. - * - * If possible, a caller should provide a Token or ParseNode with information - * about where in the source string the problem occurred. - */ - class ParseError { - constructor( - message, // The error message - token // An object providing position information - ) { - let error = " " + message; - let start; - - const loc = token && token.loc; - if (loc && loc.start <= loc.end) { - // If we have the input and a position, make the error a bit fancier - - // Get the input - const input = loc.lexer.input; - - // Prepend some information - start = loc.start; - const end = loc.end; - if (start === input.length) { - error += " at end of input: "; - } else { - error += " at position " + (start + 1) + ": "; - } - - // Underline token in question using combining underscores - const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); - - // Extract some context from the input and add it to the error - let left; - if (start > 15) { - left = "…" + input.slice(start - 15, start); - } else { - left = input.slice(0, start); - } - let right; - if (end + 15 < input.length) { - right = input.slice(end, end + 15) + "…"; - } else { - right = input.slice(end); - } - error += left + underlined + right; - } - - // Some hackery to make ParseError a prototype of Error - // See http://stackoverflow.com/a/8460753 - const self = new Error(error); - self.name = "ParseError"; - self.__proto__ = ParseError.prototype; - self.position = start; - return self; - } - } - - ParseError.prototype.__proto__ = Error.prototype; - - // - /** - * This file contains a list of utility functions which are useful in other - * files. - */ - - /** - * Return whether an element is contained in a list - */ - const contains = function(list, elem) { - return list.indexOf(elem) !== -1; - }; - - /** - * Provide a default value if a setting is undefined - */ - const deflt = function(setting, defaultIfUndefined) { - return setting === undefined ? defaultIfUndefined : setting; - }; - - // hyphenate and escape adapted from Facebook's React under Apache 2 license - - const uppercase = /([A-Z])/g; - const hyphenate = function(str) { - return str.replace(uppercase, "-$1").toLowerCase(); - }; - - const ESCAPE_LOOKUP = { - "&": "&", - ">": ">", - "<": "<", - '"': """, - "'": "'" - }; - - const ESCAPE_REGEX = /[&><"']/g; - - /** - * Escapes text to prevent scripting attacks. - */ - function escape(text) { - return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); - } - - /** - * Sometimes we want to pull out the innermost element of a group. In most - * cases, this will just be the group itself, but when ordgroups and colors have - * a single element, we want to pull that out. - */ - const getBaseElem = function(group) { - if (group.type === "ordgroup") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "color") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "font") { - return getBaseElem(group.body); - } else { - return group; - } - }; - - /** - * TeXbook algorithms often reference "character boxes", which are simply groups - * with a single character in them. To decide if something is a character box, - * we find its innermost group, and see if it is a single character. - */ - const isCharacterBox = function(group) { - const baseElem = getBaseElem(group); - - // These are all the types of groups which hold single characters - return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom" - }; - - const assert = function(value) { - if (!value) { - throw new Error("Expected non-null, but got " + String(value)); - } - return value; - }; - - /** - * Return the protocol of a URL, or "_relative" if the URL does not specify a - * protocol (and thus is relative). - */ - const protocolFromUrl = function(url) { - const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); - return protocol != null ? protocol[1] : "_relative"; - }; - - /** - * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook - * gives an acceptable rounding error of 100sp (which would be the nearest - * 1/6551.6em with our ptPerEm = 10): - * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69 - */ - const round = function(n) { - return +n.toFixed(4); - }; - - const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - const mtext = mrow.children[0]; - if (!mtext.attributes || mtext.type !== "mtext") { return mrow } - const variant = mtext.attributes.mathvariant || ""; - for (let i = 1; i < mrow.children.length; i++) { - // Check each child and, if possible, copy the character into child[0]. - const localVariant = mrow.children[i].attributes.mathvariant || ""; - if (mrow.children[i].type === "mrow") { - const childRow = mrow.children[i]; - for (let j = 0; j < childRow.children.length; j++) { - // We'll also check the children of a mrow. One level only. No recursion. - const childVariant = childRow.children[j].attributes.mathvariant || ""; - if (childVariant !== variant || childRow.children[j].type !== "mtext") { - return mrow // At least one element cannot be consolidated. Get out. - } else { - mtext.children[0].text += childRow.children[j].children[0].text; - } - } - } else if (localVariant !== variant || mrow.children[i].type !== "mtext") { - return mrow - } else { - mtext.children[0].text += mrow.children[i].children[0].text; - } - } - // Since we have gotten here, the text has been loaded into a single mtext node. - // Next, consolidate the children into a single element. - mtext.children.splice(1, mtext.children.length - 1); - // Firefox does not render a space at either end of an string. - // To get proper rendering, we replace leading or trailing spaces with no-break spaces. - if (mtext.children[0].text.charAt(0) === " ") { - mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1); - } - const L = mtext.children[0].text.length; - if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") { - mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0"; - } - return mtext - }; - - var utils = { - contains, - deflt, - escape, - hyphenate, - getBaseElem, - isCharacterBox, - protocolFromUrl, - round, - consolidateText - }; - - /** - * This is a module for storing settings passed into Temml. It correctly handles - * default settings. - */ - - /** - * The main Settings object - */ - class Settings { - constructor(options) { - // allow null options - options = options || {}; - this.displayMode = utils.deflt(options.displayMode, false); // boolean - this.annotate = utils.deflt(options.annotate, false); // boolean - this.elementIsMath = utils.deflt(options.elementIsMath, false); // boolean - this.leqno = utils.deflt(options.leqno, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.preventTagLap = utils.deflt(options.preventTagLap, false); // boolean - this.macros = options.macros || {}; - this.xml = utils.deflt(options.xml, false); // boolean - this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean - this.strict = utils.deflt(options.strict, false); // boolean - this.trust = utils.deflt(options.trust, false); // trust context. See html.js. - this.maxSize = (options.maxSize === undefined - ? [Infinity, Infinity] - : Array.isArray(options.maxSize) - ? options.maxSize - : [Infinity, Infinity] - ); - this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number - } - - /** - * Check whether to test potentially dangerous input, and return - * `true` (trusted) or `false` (untrusted). The sole argument `context` - * should be an object with `command` field specifying the relevant LaTeX - * command (as a string starting with `\`), and any other arguments, etc. - * If `context` has a `url` field, a `protocol` field will automatically - * get added by this function (changing the specified object). - */ - isTrusted(context) { - if (context.url && !context.protocol) { - context.protocol = utils.protocolFromUrl(context.url); - } - const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; - return Boolean(trust); - } - } - - /** - * All registered functions. - * `functions.js` just exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary. - */ - const _functions = {}; - - /** - * All MathML builders. Should be only used in the `define*` and the `build*ML` - * functions. - */ - const _mathmlGroupBuilders = {}; - - function defineFunction({ - type, - names, - props, - handler, - mathmlBuilder - }) { - // Set default values of functions - const data = { - type, - numArgs: props.numArgs, - argTypes: props.argTypes, - allowedInArgument: !!props.allowedInArgument, - allowedInText: !!props.allowedInText, - allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, - numOptionalArgs: props.numOptionalArgs || 0, - infix: !!props.infix, - primitive: !!props.primitive, - handler: handler - }; - for (let i = 0; i < names.length; ++i) { - _functions[names[i]] = data; - } - if (type) { - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } - } - } - - /** - * Use this to register only the MathML builder for a function(e.g. - * if the function's ParseNode is generated in Parser.js rather than via a - * stand-alone handler provided to `defineFunction`). - */ - function defineFunctionBuilders({ type, mathmlBuilder }) { - defineFunction({ - type, - names: [], - props: { numArgs: 0 }, - handler() { - throw new Error("Should never be called.") - }, - mathmlBuilder - }); - } - - const normalizeArgument = function(arg) { - return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg - }; - - // Since the corresponding buildMathML function expects a - // list of elements, we normalize for different kinds of arguments - const ordargument = function(arg) { - return arg.type === "ordgroup" ? arg.body : [arg] - }; - - /** - * This node represents a document fragment, which contains elements, but when - * placed into the DOM doesn't have any representation itself. It only contains - * children and doesn't have any DOM node properties. - */ - class DocumentFragment { - constructor(children) { - this.children = children; - this.classes = []; - this.style = {}; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - /** Convert the fragment into a node. */ - toNode() { - const frag = document.createDocumentFragment(); - - for (let i = 0; i < this.children.length; i++) { - frag.appendChild(this.children[i].toNode()); - } - - return frag; - } - - /** Convert the fragment into HTML markup. */ - toMarkup() { - let markup = ""; - - // Simply concatenate the markup for the children together. - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText. Applies to - * MathDomNode's only. - */ - toText() { - // To avoid this, we would subclass documentFragment separately for - // MathML, but polyfills for subclassing is expensive per PR 1469. - const toText = (child) => child.toText(); - return this.children.map(toText).join(""); - } - } - - /** - * These objects store the data about the DOM nodes we create, as well as some - * extra data. They can then be transformed into real DOM nodes with the - * `toNode` function or HTML markup using `toMarkup`. They are useful for both - * storing extra properties on the nodes, as well as providing a way to easily - * work with the DOM. - * - * Similar functions for working with MathML nodes exist in mathMLTree.js. - * - */ - - /** - * Create an HTML className based on a list of classes. In addition to joining - * with spaces, we also remove empty classes. - */ - const createClass = function(classes) { - return classes.filter((cls) => cls).join(" "); - }; - - const initNode = function(classes, style) { - this.classes = classes || []; - this.attributes = {}; - this.style = style || {}; - }; - - /** - * Convert into an HTML node - */ - const toNode = function(tagName) { - const node = document.createElement(tagName); - - // Apply the class - node.className = createClass(this.classes); - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - // Apply attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - // Append the children, also as HTML nodes - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; - }; - - /** - * Convert into an HTML markup string - */ - const toMarkup = function(tagName) { - let markup = `<${tagName}`; - - // Add the class - if (this.classes.length) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; - } - } - - markup += ">"; - - // Add the markup of the children, also as markup - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ``; - - return markup; - }; - - /** - * This node represents a span node, with a className, a list of children, and - * an inline style. - * - */ - class Span { - constructor(classes, children, style) { - initNode.call(this, classes, style); - this.children = children || []; - } - - setAttribute(attribute, value) { - this.attributes[attribute] = value; - } - - toNode() { - return toNode.call(this, "span"); - } - - toMarkup() { - return toMarkup.call(this, "span"); - } - } - - class TextNode$1 { - constructor(text) { - this.text = text; - } - toNode() { - return document.createTextNode(this.text); - } - toMarkup() { - return utils.escape(this.text); - } - } - - /** - * This node represents an image embed () element. - */ - class Img { - constructor(src, alt, style) { - this.alt = alt; - this.src = src; - this.classes = ["mord"]; - this.style = style; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - toNode() { - const node = document.createElement("img"); - node.src = this.src; - node.alt = this.alt; - node.className = "mord"; - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - return node; - } - - toMarkup() { - let markup = `${this.alt}` and - * `` tags). - */ - class MathNode { - constructor(type, children, classes, style) { - this.type = type; - this.attributes = {}; - this.children = children || []; - this.classes = classes || []; - this.style = style || {}; // Used for elements - } - - /** - * Sets an attribute on a MathML node. MathML depends on attributes to convey a - * semantic content, so this is used heavily. - */ - setAttribute(name, value) { - this.attributes[name] = value; - } - - /** - * Gets an attribute on a MathML node. - */ - getAttribute(name) { - return this.attributes[name]; - } - - /** - * Converts the math node into a MathML-namespaced DOM element. - */ - toNode() { - const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); - - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - if (this.classes.length > 0) { - node.className = createClass(this.classes); - } - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; - } - - /** - * Converts the math node into an HTML markup string. - */ - toMarkup() { - let markup = "<" + this.type; - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - markup += " " + attr + '="'; - markup += utils.escape(this.attributes[attr]); - markup += '"'; - } - } - - if (this.classes.length > 0) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - markup += ">"; - - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ""; - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText, but escaped. - */ - toText() { - return this.children.map((child) => child.toText()).join(""); - } - } - - /** - * This node represents a piece of text. - */ - class TextNode { - constructor(text) { - this.text = text; - } - - /** - * Converts the text node into a DOM text node. - */ - toNode() { - return document.createTextNode(this.text); - } - - /** - * Converts the text node into escaped HTML markup - * (representing the text itself). - */ - toMarkup() { - return utils.escape(this.toText()); - } - - /** - * Converts the text node into a string - * (representing the text iteself). - */ - toText() { - return this.text; - } - } - - // Do not make an the only child of a . - // An acts as its own implicit . - const wrapWithMstyle = expression => { - let node; - if (expression.length === 1 && expression[0].type === "mrow") { - node = expression.pop(); - node.type = "mstyle"; - } else { - node = new MathNode("mstyle", expression); - } - return node - }; - - var mathMLTree = { - MathNode, - TextNode, - newDocumentFragment - }; - - /** - * This file provides support for building horizontal stretchy elements. - */ - - const stretchyCodePoint = { - widehat: "^", - widecheck: "ˇ", - widetilde: "~", - wideparen: "⏜", // \u23dc - utilde: "~", - overleftarrow: "\u2190", - underleftarrow: "\u2190", - xleftarrow: "\u2190", - overrightarrow: "\u2192", - underrightarrow: "\u2192", - xrightarrow: "\u2192", - underbrace: "\u23df", - overbrace: "\u23de", - overgroup: "\u23e0", - overparen: "⏜", - undergroup: "\u23e1", - underparen: "\u23dd", - overleftrightarrow: "\u2194", - underleftrightarrow: "\u2194", - xleftrightarrow: "\u2194", - Overrightarrow: "\u21d2", - xRightarrow: "\u21d2", - overleftharpoon: "\u21bc", - xleftharpoonup: "\u21bc", - overrightharpoon: "\u21c0", - xrightharpoonup: "\u21c0", - xLeftarrow: "\u21d0", - xLeftrightarrow: "\u21d4", - xhookleftarrow: "\u21a9", - xhookrightarrow: "\u21aa", - xmapsto: "\u21a6", - xrightharpoondown: "\u21c1", - xleftharpoondown: "\u21bd", - xtwoheadleftarrow: "\u219e", - xtwoheadrightarrow: "\u21a0", - xlongequal: "=", - xrightleftarrows: "\u21c4", - yields: "\u2192", - yieldsLeft: "\u2190", - mesomerism: "\u2194", - longrightharpoonup: "\u21c0", - longleftharpoondown: "\u21bd", - eqrightharpoonup: "\u21c0", - eqleftharpoondown: "\u21bd", - "\\cdrightarrow": "\u2192", - "\\cdleftarrow": "\u2190", - "\\cdlongequal": "=" - }; - - const mathMLnode = function(label) { - const child = new mathMLTree.TextNode(stretchyCodePoint[label.slice(1)]); - const node = new mathMLTree.MathNode("mo", [child]); - node.setAttribute("stretchy", "true"); - return node - }; - - var stretchy = { - mathMLnode - }; - - /** - * This file holds a list of all no-argument functions and single-character - * symbols (like 'a' or ';'). - * - * For each of the symbols, there are two properties they can have: - * - group (required): the ParseNode group type the symbol should have (i.e. - "textord", "mathord", etc). - * - replace: the character that this symbol or function should be - * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi - * character in the main font). - * - * The outermost map in the table indicates what mode the symbols should be - * accepted in (e.g. "math" or "text"). - */ - - // Some of these have a "-token" suffix since these are also used as `ParseNode` - // types for raw text tokens, and we want to avoid conflicts with higher-level - // `ParseNode` types. These `ParseNode`s are constructed within `Parser` by - // looking up the `symbols` map. - const ATOMS = { - bin: 1, - close: 1, - inner: 1, - open: 1, - punct: 1, - rel: 1 - }; - const NON_ATOMS = { - "accent-token": 1, - mathord: 1, - "op-token": 1, - spacing: 1, - textord: 1 - }; - - const symbols = { - math: {}, - text: {} - }; - - /** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ - function defineSymbol(mode, group, replace, name, acceptUnicodeChar) { - symbols[mode][name] = { group, replace }; - - if (acceptUnicodeChar && replace) { - symbols[mode][replace] = symbols[mode][name]; - } - } - - // Some abbreviations for commonly used strings. - // This helps minify the code, and also spotting typos using jshint. - - // modes: - const math = "math"; - const text = "text"; - - // groups: - const accent = "accent-token"; - const bin = "bin"; - const close = "close"; - const inner = "inner"; - const mathord = "mathord"; - const op = "op-token"; - const open = "open"; - const punct = "punct"; - const rel = "rel"; - const spacing = "spacing"; - const textord = "textord"; - - // Now comes the symbol table - - // Relation Symbols - defineSymbol(math, rel, "\u2261", "\\equiv", true); - defineSymbol(math, rel, "\u227a", "\\prec", true); - defineSymbol(math, rel, "\u227b", "\\succ", true); - defineSymbol(math, rel, "\u223c", "\\sim", true); - defineSymbol(math, rel, "\u27c2", "\\perp", true); - defineSymbol(math, rel, "\u2aaf", "\\preceq", true); - defineSymbol(math, rel, "\u2ab0", "\\succeq", true); - defineSymbol(math, rel, "\u2243", "\\simeq", true); - defineSymbol(math, rel, "\u224c", "\\backcong", true); - defineSymbol(math, rel, "|", "\\mid", true); - defineSymbol(math, rel, "\u226a", "\\ll", true); - defineSymbol(math, rel, "\u226b", "\\gg", true); - defineSymbol(math, rel, "\u224d", "\\asymp", true); - defineSymbol(math, rel, "\u2225", "\\parallel"); - defineSymbol(math, rel, "\u22c8", "\\bowtie", true); - defineSymbol(math, rel, "\u2323", "\\smile", true); - defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true); - defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true); - defineSymbol(math, rel, "\u2250", "\\doteq", true); - defineSymbol(math, rel, "\u2322", "\\frown", true); - defineSymbol(math, rel, "\u220b", "\\ni", true); - defineSymbol(math, rel, "\u220c", "\\notni", true); - defineSymbol(math, rel, "\u221d", "\\propto", true); - defineSymbol(math, rel, "\u22a2", "\\vdash", true); - defineSymbol(math, rel, "\u22a3", "\\dashv", true); - defineSymbol(math, rel, "\u220b", "\\owns"); - defineSymbol(math, rel, "\u2258", "\\arceq", true); - defineSymbol(math, rel, "\u2259", "\\wedgeq", true); - defineSymbol(math, rel, "\u225a", "\\veeeq", true); - defineSymbol(math, rel, "\u225b", "\\stareq", true); - defineSymbol(math, rel, "\u225d", "\\eqdef", true); - defineSymbol(math, rel, "\u225e", "\\measeq", true); - defineSymbol(math, rel, "\u225f", "\\questeq", true); - defineSymbol(math, rel, "\u2260", "\\ne", true); - defineSymbol(math, rel, "\u2260", "\\neq"); - // mathtools.sty - defineSymbol(math, rel, "\u2237", "\\dblcolon", true); - defineSymbol(math, rel, "\u2254", "\\coloneqq", true); - defineSymbol(math, rel, "\u2255", "\\eqqcolon", true); - defineSymbol(math, rel, "\u2239", "\\eqcolon", true); - defineSymbol(math, rel, "\u2A74", "\\Coloneqq", true); - - // Punctuation - defineSymbol(math, punct, "\u002e", "\\ldotp"); - defineSymbol(math, punct, "\u00b7", "\\cdotp"); - - // Misc Symbols - defineSymbol(math, textord, "\u0023", "\\#"); - defineSymbol(text, textord, "\u0023", "\\#"); - defineSymbol(math, textord, "\u0026", "\\&"); - defineSymbol(text, textord, "\u0026", "\\&"); - defineSymbol(math, textord, "\u2135", "\\aleph", true); - defineSymbol(math, textord, "\u2200", "\\forall", true); - defineSymbol(math, textord, "\u210f", "\\hbar", true); - defineSymbol(math, textord, "\u2203", "\\exists", true); - defineSymbol(math, textord, "\u2207", "\\nabla", true); - defineSymbol(math, textord, "\u266d", "\\flat", true); - defineSymbol(math, textord, "\u2113", "\\ell", true); - defineSymbol(math, textord, "\u266e", "\\natural", true); - defineSymbol(math, textord, "Å", "\\AA", true); - defineSymbol(text, textord, "Å", "\\AA", true); - defineSymbol(math, textord, "\u2663", "\\clubsuit", true); - defineSymbol(math, textord, "\u2667", "\\varclubsuit", true); - defineSymbol(math, textord, "\u2118", "\\wp", true); - defineSymbol(math, textord, "\u266f", "\\sharp", true); - defineSymbol(math, textord, "\u2662", "\\diamondsuit", true); - defineSymbol(math, textord, "\u2666", "\\vardiamondsuit", true); - defineSymbol(math, textord, "\u211c", "\\Re", true); - defineSymbol(math, textord, "\u2661", "\\heartsuit", true); - defineSymbol(math, textord, "\u2665", "\\varheartsuit", true); - defineSymbol(math, textord, "\u2111", "\\Im", true); - defineSymbol(math, textord, "\u2660", "\\spadesuit", true); - defineSymbol(math, textord, "\u2664", "\\varspadesuit", true); - defineSymbol(math, textord, "\u2640", "\\female", true); - defineSymbol(math, textord, "\u2642", "\\male", true); - defineSymbol(math, textord, "\u00a7", "\\S", true); - defineSymbol(text, textord, "\u00a7", "\\S"); - defineSymbol(math, textord, "\u00b6", "\\P", true); - defineSymbol(text, textord, "\u00b6", "\\P"); - defineSymbol(text, textord, "\u263a", "\\smiley", true); - defineSymbol(math, textord, "\u263a", "\\smiley", true); - - // Math and Text - defineSymbol(math, textord, "\u2020", "\\dag"); - defineSymbol(text, textord, "\u2020", "\\dag"); - defineSymbol(text, textord, "\u2020", "\\textdagger"); - defineSymbol(math, textord, "\u2021", "\\ddag"); - defineSymbol(text, textord, "\u2021", "\\ddag"); - defineSymbol(text, textord, "\u2021", "\\textdaggerdbl"); - - // Large Delimiters - defineSymbol(math, close, "\u23b1", "\\rmoustache", true); - defineSymbol(math, open, "\u23b0", "\\lmoustache", true); - defineSymbol(math, close, "\u27ef", "\\rgroup", true); - defineSymbol(math, open, "\u27ee", "\\lgroup", true); - - // Binary Operators - defineSymbol(math, bin, "\u2213", "\\mp", true); - defineSymbol(math, bin, "\u2296", "\\ominus", true); - defineSymbol(math, bin, "\u228e", "\\uplus", true); - defineSymbol(math, bin, "\u2293", "\\sqcap", true); - defineSymbol(math, bin, "\u2217", "\\ast"); - defineSymbol(math, bin, "\u2294", "\\sqcup", true); - defineSymbol(math, bin, "\u25ef", "\\bigcirc", true); - defineSymbol(math, bin, "\u2219", "\\bullet", true); - defineSymbol(math, bin, "\u2021", "\\ddagger"); - defineSymbol(math, bin, "\u2240", "\\wr", true); - defineSymbol(math, bin, "\u2a3f", "\\amalg"); - defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath - - // Arrow Symbols - defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true); - defineSymbol(math, rel, "\u21d0", "\\Leftarrow", true); - defineSymbol(math, rel, "\u27f8", "\\Longleftarrow", true); - defineSymbol(math, rel, "\u27f6", "\\longrightarrow", true); - defineSymbol(math, rel, "\u21d2", "\\Rightarrow", true); - defineSymbol(math, rel, "\u27f9", "\\Longrightarrow", true); - defineSymbol(math, rel, "\u2194", "\\leftrightarrow", true); - defineSymbol(math, rel, "\u27f7", "\\longleftrightarrow", true); - defineSymbol(math, rel, "\u21d4", "\\Leftrightarrow", true); - defineSymbol(math, rel, "\u27fa", "\\Longleftrightarrow", true); - defineSymbol(math, rel, "\u21a6", "\\mapsto", true); - defineSymbol(math, rel, "\u27fc", "\\longmapsto", true); - defineSymbol(math, rel, "\u2197", "\\nearrow", true); - defineSymbol(math, rel, "\u21a9", "\\hookleftarrow", true); - defineSymbol(math, rel, "\u21aa", "\\hookrightarrow", true); - defineSymbol(math, rel, "\u2198", "\\searrow", true); - defineSymbol(math, rel, "\u21bc", "\\leftharpoonup", true); - defineSymbol(math, rel, "\u21c0", "\\rightharpoonup", true); - defineSymbol(math, rel, "\u2199", "\\swarrow", true); - defineSymbol(math, rel, "\u21bd", "\\leftharpoondown", true); - defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true); - defineSymbol(math, rel, "\u2196", "\\nwarrow", true); - defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true); - defineSymbol(math, mathord, "\u21af", "\\lightning", true); - defineSymbol(math, mathord, "\u2030", "\\permil", true); - defineSymbol(text, textord, "\u2030", "\\permil"); - - // AMS Negated Binary Relations - defineSymbol(math, rel, "\u226e", "\\nless", true); - // Symbol names preceeded by "@" each have a corresponding macro. - defineSymbol(math, rel, "\u2a87", "\\lneq", true); - defineSymbol(math, rel, "\u2268", "\\lneqq", true); - defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq"); - defineSymbol(math, rel, "\u22e6", "\\lnsim", true); - defineSymbol(math, rel, "\u2a89", "\\lnapprox", true); - defineSymbol(math, rel, "\u2280", "\\nprec", true); - // unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. - defineSymbol(math, rel, "\u22e0", "\\npreceq", true); - defineSymbol(math, rel, "\u22e8", "\\precnsim", true); - defineSymbol(math, rel, "\u2ab9", "\\precnapprox", true); - defineSymbol(math, rel, "\u2241", "\\nsim", true); - defineSymbol(math, rel, "\u2224", "\\nmid", true); - defineSymbol(math, rel, "\u2224", "\\nshortmid"); - defineSymbol(math, rel, "\u22ac", "\\nvdash", true); - defineSymbol(math, rel, "\u22ad", "\\nvDash", true); - defineSymbol(math, rel, "\u22ea", "\\ntriangleleft"); - defineSymbol(math, rel, "\u22ec", "\\ntrianglelefteq", true); - defineSymbol(math, rel, "\u2284", "\\nsubset", true); - defineSymbol(math, rel, "\u2285", "\\nsupset", true); - defineSymbol(math, rel, "\u228a", "\\subsetneq", true); - defineSymbol(math, rel, "\u228a\ufe00", "\\varsubsetneq"); - defineSymbol(math, rel, "\u2acb", "\\subsetneqq", true); - defineSymbol(math, rel, "\u2acb\ufe00", "\\varsubsetneqq"); - defineSymbol(math, rel, "\u226f", "\\ngtr", true); - defineSymbol(math, rel, "\u2a88", "\\gneq", true); - defineSymbol(math, rel, "\u2269", "\\gneqq", true); - defineSymbol(math, rel, "\u2269\ufe00", "\\gvertneqq"); - defineSymbol(math, rel, "\u22e7", "\\gnsim", true); - defineSymbol(math, rel, "\u2a8a", "\\gnapprox", true); - defineSymbol(math, rel, "\u2281", "\\nsucc", true); - // unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. - defineSymbol(math, rel, "\u22e1", "\\nsucceq", true); - defineSymbol(math, rel, "\u22e9", "\\succnsim", true); - defineSymbol(math, rel, "\u2aba", "\\succnapprox", true); - // unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. - defineSymbol(math, rel, "\u2246", "\\ncong", true); - defineSymbol(math, rel, "\u2226", "\\nparallel", true); - defineSymbol(math, rel, "\u2226", "\\nshortparallel"); - defineSymbol(math, rel, "\u22af", "\\nVDash", true); - defineSymbol(math, rel, "\u22eb", "\\ntriangleright"); - defineSymbol(math, rel, "\u22ed", "\\ntrianglerighteq", true); - defineSymbol(math, rel, "\u228b", "\\supsetneq", true); - defineSymbol(math, rel, "\u228b", "\\varsupsetneq"); - defineSymbol(math, rel, "\u2acc", "\\supsetneqq", true); - defineSymbol(math, rel, "\u2acc\ufe00", "\\varsupsetneqq"); - defineSymbol(math, rel, "\u22ae", "\\nVdash", true); - defineSymbol(math, rel, "\u2ab5", "\\precneqq", true); - defineSymbol(math, rel, "\u2ab6", "\\succneqq", true); - defineSymbol(math, bin, "\u22b4", "\\unlhd"); - defineSymbol(math, bin, "\u22b5", "\\unrhd"); - - // AMS Negated Arrows - defineSymbol(math, rel, "\u219a", "\\nleftarrow", true); - defineSymbol(math, rel, "\u219b", "\\nrightarrow", true); - defineSymbol(math, rel, "\u21cd", "\\nLeftarrow", true); - defineSymbol(math, rel, "\u21cf", "\\nRightarrow", true); - defineSymbol(math, rel, "\u21ae", "\\nleftrightarrow", true); - defineSymbol(math, rel, "\u21ce", "\\nLeftrightarrow", true); - - // AMS Misc - defineSymbol(math, rel, "\u25b3", "\\vartriangle"); - defineSymbol(math, textord, "\u210f", "\\hslash"); - defineSymbol(math, textord, "\u25bd", "\\triangledown"); - defineSymbol(math, textord, "\u25ca", "\\lozenge"); - defineSymbol(math, textord, "\u24c8", "\\circledS"); - defineSymbol(math, textord, "\u00ae", "\\circledR", true); - defineSymbol(text, textord, "\u00ae", "\\circledR"); - defineSymbol(text, textord, "\u00ae", "\\textregistered"); - defineSymbol(math, textord, "\u2221", "\\measuredangle", true); - defineSymbol(math, textord, "\u2204", "\\nexists"); - defineSymbol(math, textord, "\u2127", "\\mho"); - defineSymbol(math, textord, "\u2132", "\\Finv", true); - defineSymbol(math, textord, "\u2141", "\\Game", true); - defineSymbol(math, textord, "\u2035", "\\backprime"); - defineSymbol(math, textord, "\u25b2", "\\blacktriangle"); - defineSymbol(math, textord, "\u25bc", "\\blacktriangledown"); - defineSymbol(math, textord, "\u25a0", "\\blacksquare"); - defineSymbol(math, textord, "\u29eb", "\\blacklozenge"); - defineSymbol(math, textord, "\u2605", "\\bigstar"); - defineSymbol(math, textord, "\u2222", "\\sphericalangle", true); - defineSymbol(math, textord, "\u2201", "\\complement", true); - // unicode-math maps U+F0 to \matheth. We map to AMS function \eth - defineSymbol(math, textord, "\u00f0", "\\eth", true); - defineSymbol(text, textord, "\u00f0", "\u00f0"); - defineSymbol(math, textord, "\u2571", "\\diagup"); - defineSymbol(math, textord, "\u2572", "\\diagdown"); - defineSymbol(math, textord, "\u25a1", "\\square"); - defineSymbol(math, textord, "\u25a1", "\\Box"); - defineSymbol(math, textord, "\u25ca", "\\Diamond"); - // unicode-math maps U+A5 to \mathyen. We map to AMS function \yen - defineSymbol(math, textord, "\u00a5", "\\yen", true); - defineSymbol(text, textord, "\u00a5", "\\yen", true); - defineSymbol(math, textord, "\u2713", "\\checkmark", true); - defineSymbol(text, textord, "\u2713", "\\checkmark"); - defineSymbol(math, textord, "\u2717", "\\ballotx", true); - defineSymbol(text, textord, "\u2717", "\\ballotx"); - defineSymbol(text, textord, "\u2022", "\\textbullet"); - - // AMS Hebrew - defineSymbol(math, textord, "\u2136", "\\beth", true); - defineSymbol(math, textord, "\u2138", "\\daleth", true); - defineSymbol(math, textord, "\u2137", "\\gimel", true); - - // AMS Greek - defineSymbol(math, textord, "\u03dd", "\\digamma", true); - defineSymbol(math, textord, "\u03f0", "\\varkappa"); - - // AMS Delimiters - defineSymbol(math, open, "\u231C", "\\ulcorner", true); - defineSymbol(math, close, "\u231D", "\\urcorner", true); - defineSymbol(math, open, "\u231E", "\\llcorner", true); - defineSymbol(math, close, "\u231F", "\\lrcorner", true); - - // AMS Binary Relations - defineSymbol(math, rel, "\u2266", "\\leqq", true); - defineSymbol(math, rel, "\u2a7d", "\\leqslant", true); - defineSymbol(math, rel, "\u2a95", "\\eqslantless", true); - defineSymbol(math, rel, "\u2272", "\\lesssim", true); - defineSymbol(math, rel, "\u2a85", "\\lessapprox", true); - defineSymbol(math, rel, "\u224a", "\\approxeq", true); - defineSymbol(math, bin, "\u22d6", "\\lessdot"); - defineSymbol(math, rel, "\u22d8", "\\lll", true); - defineSymbol(math, rel, "\u2276", "\\lessgtr", true); - defineSymbol(math, rel, "\u22da", "\\lesseqgtr", true); - defineSymbol(math, rel, "\u2a8b", "\\lesseqqgtr", true); - defineSymbol(math, rel, "\u2251", "\\doteqdot"); - defineSymbol(math, rel, "\u2253", "\\risingdotseq", true); - defineSymbol(math, rel, "\u2252", "\\fallingdotseq", true); - defineSymbol(math, rel, "\u223d", "\\backsim", true); - defineSymbol(math, rel, "\u22cd", "\\backsimeq", true); - defineSymbol(math, rel, "\u2ac5", "\\subseteqq", true); - defineSymbol(math, rel, "\u22d0", "\\Subset", true); - defineSymbol(math, rel, "\u228f", "\\sqsubset", true); - defineSymbol(math, rel, "\u227c", "\\preccurlyeq", true); - defineSymbol(math, rel, "\u22de", "\\curlyeqprec", true); - defineSymbol(math, rel, "\u227e", "\\precsim", true); - defineSymbol(math, rel, "\u2ab7", "\\precapprox", true); - defineSymbol(math, rel, "\u22b2", "\\vartriangleleft"); - defineSymbol(math, rel, "\u22b4", "\\trianglelefteq"); - defineSymbol(math, rel, "\u22a8", "\\vDash", true); - defineSymbol(math, rel, "\u22aa", "\\Vvdash", true); - defineSymbol(math, rel, "\u2323", "\\smallsmile"); - defineSymbol(math, rel, "\u2322", "\\smallfrown"); - defineSymbol(math, rel, "\u224f", "\\bumpeq", true); - defineSymbol(math, rel, "\u224e", "\\Bumpeq", true); - defineSymbol(math, rel, "\u2267", "\\geqq", true); - defineSymbol(math, rel, "\u2a7e", "\\geqslant", true); - defineSymbol(math, rel, "\u2a96", "\\eqslantgtr", true); - defineSymbol(math, rel, "\u2273", "\\gtrsim", true); - defineSymbol(math, rel, "\u2a86", "\\gtrapprox", true); - defineSymbol(math, bin, "\u22d7", "\\gtrdot"); - defineSymbol(math, rel, "\u22d9", "\\ggg", true); - defineSymbol(math, rel, "\u2277", "\\gtrless", true); - defineSymbol(math, rel, "\u22db", "\\gtreqless", true); - defineSymbol(math, rel, "\u2a8c", "\\gtreqqless", true); - defineSymbol(math, rel, "\u2256", "\\eqcirc", true); - defineSymbol(math, rel, "\u2257", "\\circeq", true); - defineSymbol(math, rel, "\u225c", "\\triangleq", true); - defineSymbol(math, rel, "\u223c", "\\thicksim"); - defineSymbol(math, rel, "\u2248", "\\thickapprox"); - defineSymbol(math, rel, "\u2ac6", "\\supseteqq", true); - defineSymbol(math, rel, "\u22d1", "\\Supset", true); - defineSymbol(math, rel, "\u2290", "\\sqsupset", true); - defineSymbol(math, rel, "\u227d", "\\succcurlyeq", true); - defineSymbol(math, rel, "\u22df", "\\curlyeqsucc", true); - defineSymbol(math, rel, "\u227f", "\\succsim", true); - defineSymbol(math, rel, "\u2ab8", "\\succapprox", true); - defineSymbol(math, rel, "\u22b3", "\\vartriangleright"); - defineSymbol(math, rel, "\u22b5", "\\trianglerighteq"); - defineSymbol(math, rel, "\u22a9", "\\Vdash", true); - defineSymbol(math, rel, "\u2223", "\\shortmid"); - defineSymbol(math, rel, "\u2225", "\\shortparallel"); - defineSymbol(math, rel, "\u226c", "\\between", true); - defineSymbol(math, rel, "\u22d4", "\\pitchfork", true); - defineSymbol(math, rel, "\u221d", "\\varpropto"); - defineSymbol(math, rel, "\u25c0", "\\blacktriangleleft"); - // unicode-math says that \therefore is a mathord atom. - // We kept the amssymb atom type, which is rel. - defineSymbol(math, rel, "\u2234", "\\therefore", true); - defineSymbol(math, rel, "\u220d", "\\backepsilon"); - defineSymbol(math, rel, "\u25b6", "\\blacktriangleright"); - // unicode-math says that \because is a mathord atom. - // We kept the amssymb atom type, which is rel. - defineSymbol(math, rel, "\u2235", "\\because", true); - defineSymbol(math, rel, "\u22d8", "\\llless"); - defineSymbol(math, rel, "\u22d9", "\\gggtr"); - defineSymbol(math, bin, "\u22b2", "\\lhd"); - defineSymbol(math, bin, "\u22b3", "\\rhd"); - defineSymbol(math, rel, "\u2242", "\\eqsim", true); - defineSymbol(math, rel, "\u22c8", "\\Join"); - defineSymbol(math, rel, "\u2251", "\\Doteq", true); - defineSymbol(math, rel, "\u297d", "\\strictif", true); - defineSymbol(math, rel, "\u297c", "\\strictfi", true); - - // AMS Binary Operators - defineSymbol(math, bin, "\u2214", "\\dotplus", true); - defineSymbol(math, bin, "\u2216", "\\smallsetminus"); - defineSymbol(math, bin, "\u22d2", "\\Cap", true); - defineSymbol(math, bin, "\u22d3", "\\Cup", true); - defineSymbol(math, bin, "\u2a5e", "\\doublebarwedge", true); - defineSymbol(math, bin, "\u229f", "\\boxminus", true); - defineSymbol(math, bin, "\u229e", "\\boxplus", true); - defineSymbol(math, bin, "\u22c7", "\\divideontimes", true); - defineSymbol(math, bin, "\u22c9", "\\ltimes", true); - defineSymbol(math, bin, "\u22ca", "\\rtimes", true); - defineSymbol(math, bin, "\u22cb", "\\leftthreetimes", true); - defineSymbol(math, bin, "\u22cc", "\\rightthreetimes", true); - defineSymbol(math, bin, "\u22cf", "\\curlywedge", true); - defineSymbol(math, bin, "\u22ce", "\\curlyvee", true); - defineSymbol(math, bin, "\u229d", "\\circleddash", true); - defineSymbol(math, bin, "\u229b", "\\circledast", true); - defineSymbol(math, bin, "\u22ba", "\\intercal", true); - defineSymbol(math, bin, "\u22d2", "\\doublecap"); - defineSymbol(math, bin, "\u22d3", "\\doublecup"); - defineSymbol(math, bin, "\u22a0", "\\boxtimes", true); - - // AMS Arrows - // Note: unicode-math maps \u21e2 to their own function \rightdasharrow. - // We'll map it to AMS function \dashrightarrow. It produces the same atom. - defineSymbol(math, rel, "\u21e2", "\\dashrightarrow", true); - // unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. - defineSymbol(math, rel, "\u21e0", "\\dashleftarrow", true); - defineSymbol(math, rel, "\u21c7", "\\leftleftarrows", true); - defineSymbol(math, rel, "\u21c6", "\\leftrightarrows", true); - defineSymbol(math, rel, "\u21da", "\\Lleftarrow", true); - defineSymbol(math, rel, "\u219e", "\\twoheadleftarrow", true); - defineSymbol(math, rel, "\u21a2", "\\leftarrowtail", true); - defineSymbol(math, rel, "\u21ab", "\\looparrowleft", true); - defineSymbol(math, rel, "\u21cb", "\\leftrightharpoons", true); - defineSymbol(math, rel, "\u21b6", "\\curvearrowleft", true); - // unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. - defineSymbol(math, rel, "\u21ba", "\\circlearrowleft", true); - defineSymbol(math, rel, "\u21b0", "\\Lsh", true); - defineSymbol(math, rel, "\u21c8", "\\upuparrows", true); - defineSymbol(math, rel, "\u21bf", "\\upharpoonleft", true); - defineSymbol(math, rel, "\u21c3", "\\downharpoonleft", true); - defineSymbol(math, rel, "\u22b6", "\\origof", true); - defineSymbol(math, rel, "\u22b7", "\\imageof", true); - defineSymbol(math, rel, "\u22b8", "\\multimap", true); - defineSymbol(math, rel, "\u21ad", "\\leftrightsquigarrow", true); - defineSymbol(math, rel, "\u21c9", "\\rightrightarrows", true); - defineSymbol(math, rel, "\u21c4", "\\rightleftarrows", true); - defineSymbol(math, rel, "\u21a0", "\\twoheadrightarrow", true); - defineSymbol(math, rel, "\u21a3", "\\rightarrowtail", true); - defineSymbol(math, rel, "\u21ac", "\\looparrowright", true); - defineSymbol(math, rel, "\u21b7", "\\curvearrowright", true); - // unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. - defineSymbol(math, rel, "\u21bb", "\\circlearrowright", true); - defineSymbol(math, rel, "\u21b1", "\\Rsh", true); - defineSymbol(math, rel, "\u21ca", "\\downdownarrows", true); - defineSymbol(math, rel, "\u21be", "\\upharpoonright", true); - defineSymbol(math, rel, "\u21c2", "\\downharpoonright", true); - defineSymbol(math, rel, "\u21dd", "\\rightsquigarrow", true); - defineSymbol(math, rel, "\u21dd", "\\leadsto"); - defineSymbol(math, rel, "\u21db", "\\Rrightarrow", true); - defineSymbol(math, rel, "\u21be", "\\restriction"); - - defineSymbol(math, textord, "\u2018", "`"); - defineSymbol(math, textord, "$", "\\$"); - defineSymbol(text, textord, "$", "\\$"); - defineSymbol(text, textord, "$", "\\textdollar"); - defineSymbol(math, textord, "%", "\\%"); - defineSymbol(text, textord, "%", "\\%"); - defineSymbol(math, textord, "_", "\\_"); - defineSymbol(text, textord, "_", "\\_"); - defineSymbol(text, textord, "_", "\\textunderscore"); - defineSymbol(text, textord, "\u2423", "\\textvisiblespace", true); - defineSymbol(math, textord, "\u2220", "\\angle", true); - defineSymbol(math, textord, "\u221e", "\\infty", true); - defineSymbol(math, textord, "\u2032", "\\prime"); - defineSymbol(math, textord, "\u25b3", "\\triangle"); - defineSymbol(text, textord, "\u0391", "\\Alpha", true); - defineSymbol(text, textord, "\u0392", "\\Beta", true); - defineSymbol(text, textord, "\u0393", "\\Gamma", true); - defineSymbol(text, textord, "\u0394", "\\Delta", true); - defineSymbol(text, textord, "\u0395", "\\Epsilon", true); - defineSymbol(text, textord, "\u0396", "\\Zeta", true); - defineSymbol(text, textord, "\u0397", "\\Eta", true); - defineSymbol(text, textord, "\u0398", "\\Theta", true); - defineSymbol(text, textord, "\u0399", "\\Iota", true); - defineSymbol(text, textord, "\u039a", "\\Kappa", true); - defineSymbol(text, textord, "\u039b", "\\Lambda", true); - defineSymbol(text, textord, "\u039c", "\\Mu", true); - defineSymbol(text, textord, "\u039d", "\\Nu", true); - defineSymbol(text, textord, "\u039e", "\\Xi", true); - defineSymbol(text, textord, "\u039f", "\\Omicron", true); - defineSymbol(text, textord, "\u03a0", "\\Pi", true); - defineSymbol(text, textord, "\u03a1", "\\Rho", true); - defineSymbol(text, textord, "\u03a3", "\\Sigma", true); - defineSymbol(text, textord, "\u03a4", "\\Tau", true); - defineSymbol(text, textord, "\u03a5", "\\Upsilon", true); - defineSymbol(text, textord, "\u03a6", "\\Phi", true); - defineSymbol(text, textord, "\u03a7", "\\Chi", true); - defineSymbol(text, textord, "\u03a8", "\\Psi", true); - defineSymbol(text, textord, "\u03a9", "\\Omega", true); - defineSymbol(math, mathord, "\u0391", "\\Alpha", true); - defineSymbol(math, mathord, "\u0392", "\\Beta", true); - defineSymbol(math, mathord, "\u0393", "\\Gamma", true); - defineSymbol(math, mathord, "\u0394", "\\Delta", true); - defineSymbol(math, mathord, "\u0395", "\\Epsilon", true); - defineSymbol(math, mathord, "\u0396", "\\Zeta", true); - defineSymbol(math, mathord, "\u0397", "\\Eta", true); - defineSymbol(math, mathord, "\u0398", "\\Theta", true); - defineSymbol(math, mathord, "\u0399", "\\Iota", true); - defineSymbol(math, mathord, "\u039a", "\\Kappa", true); - defineSymbol(math, mathord, "\u039b", "\\Lambda", true); - defineSymbol(math, mathord, "\u039c", "\\Mu", true); - defineSymbol(math, mathord, "\u039d", "\\Nu", true); - defineSymbol(math, mathord, "\u039e", "\\Xi", true); - defineSymbol(math, mathord, "\u039f", "\\Omicron", true); - defineSymbol(math, mathord, "\u03a0", "\\Pi", true); - defineSymbol(math, mathord, "\u03a1", "\\Rho", true); - defineSymbol(math, mathord, "\u03a3", "\\Sigma", true); - defineSymbol(math, mathord, "\u03a4", "\\Tau", true); - defineSymbol(math, mathord, "\u03a5", "\\Upsilon", true); - defineSymbol(math, mathord, "\u03a6", "\\Phi", true); - defineSymbol(math, mathord, "\u03a7", "\\Chi", true); - defineSymbol(math, mathord, "\u03a8", "\\Psi", true); - defineSymbol(math, mathord, "\u03a9", "\\Omega", true); - defineSymbol(math, open, "\u00ac", "\\neg", true); - defineSymbol(math, open, "\u00ac", "\\lnot"); - defineSymbol(math, textord, "\u22a4", "\\top"); - defineSymbol(math, textord, "\u22a5", "\\bot"); - defineSymbol(math, textord, "\u2205", "\\emptyset"); - defineSymbol(math, textord, "\u00f8", "\\varnothing"); - defineSymbol(math, mathord, "\u03b1", "\\alpha", true); - defineSymbol(math, mathord, "\u03b2", "\\beta", true); - defineSymbol(math, mathord, "\u03b3", "\\gamma", true); - defineSymbol(math, mathord, "\u03b4", "\\delta", true); - defineSymbol(math, mathord, "\u03f5", "\\epsilon", true); - defineSymbol(math, mathord, "\u03b6", "\\zeta", true); - defineSymbol(math, mathord, "\u03b7", "\\eta", true); - defineSymbol(math, mathord, "\u03b8", "\\theta", true); - defineSymbol(math, mathord, "\u03b9", "\\iota", true); - defineSymbol(math, mathord, "\u03ba", "\\kappa", true); - defineSymbol(math, mathord, "\u03bb", "\\lambda", true); - defineSymbol(math, mathord, "\u03bc", "\\mu", true); - defineSymbol(math, mathord, "\u03bd", "\\nu", true); - defineSymbol(math, mathord, "\u03be", "\\xi", true); - defineSymbol(math, mathord, "\u03bf", "\\omicron", true); - defineSymbol(math, mathord, "\u03c0", "\\pi", true); - defineSymbol(math, mathord, "\u03c1", "\\rho", true); - defineSymbol(math, mathord, "\u03c3", "\\sigma", true); - defineSymbol(math, mathord, "\u03c4", "\\tau", true); - defineSymbol(math, mathord, "\u03c5", "\\upsilon", true); - defineSymbol(math, mathord, "\u03d5", "\\phi", true); - defineSymbol(math, mathord, "\u03c7", "\\chi", true); - defineSymbol(math, mathord, "\u03c8", "\\psi", true); - defineSymbol(math, mathord, "\u03c9", "\\omega", true); - defineSymbol(math, mathord, "\u03b5", "\\varepsilon", true); - defineSymbol(math, mathord, "\u03d1", "\\vartheta", true); - defineSymbol(math, mathord, "\u03d6", "\\varpi", true); - defineSymbol(math, mathord, "\u03f1", "\\varrho", true); - defineSymbol(math, mathord, "\u03c2", "\\varsigma", true); - defineSymbol(math, mathord, "\u03c6", "\\varphi", true); - defineSymbol(math, mathord, "\u03d8", "\\Coppa", true); - defineSymbol(math, mathord, "\u03d9", "\\coppa", true); - defineSymbol(math, mathord, "\u03d9", "\\varcoppa", true); - defineSymbol(math, mathord, "\u03de", "\\Koppa", true); - defineSymbol(math, mathord, "\u03df", "\\koppa", true); - defineSymbol(math, mathord, "\u03e0", "\\Sampi", true); - defineSymbol(math, mathord, "\u03e1", "\\sampi", true); - defineSymbol(math, mathord, "\u03da", "\\Stigma", true); - defineSymbol(math, mathord, "\u03db", "\\stigma", true); - defineSymbol(math, mathord, "\u2aeb", "\\Bot"); - defineSymbol(math, bin, "\u2217", "\u2217", true); - defineSymbol(math, bin, "+", "+"); - defineSymbol(math, bin, "*", "*"); - defineSymbol(math, bin, "\u2044", "\u2044"); - defineSymbol(math, bin, "\u2212", "-", true); - defineSymbol(math, bin, "\u22c5", "\\cdot", true); - defineSymbol(math, bin, "\u2218", "\\circ", true); - defineSymbol(math, bin, "\u00f7", "\\div", true); - defineSymbol(math, bin, "\u00b1", "\\pm", true); - defineSymbol(math, bin, "\u00d7", "\\times", true); - defineSymbol(math, bin, "\u2229", "\\cap", true); - defineSymbol(math, bin, "\u222a", "\\cup", true); - defineSymbol(math, bin, "\u2216", "\\setminus", true); - defineSymbol(math, bin, "\u2227", "\\land"); - defineSymbol(math, bin, "\u2228", "\\lor"); - defineSymbol(math, bin, "\u2227", "\\wedge", true); - defineSymbol(math, bin, "\u2228", "\\vee", true); - defineSymbol(math, open, "\u27e6", "\\llbracket", true); // stmaryrd/semantic packages - defineSymbol(math, close, "\u27e7", "\\rrbracket", true); - defineSymbol(math, open, "\u27e8", "\\langle", true); - defineSymbol(math, open, "|", "\\lvert"); - defineSymbol(math, open, "\u2016", "\\lVert"); - defineSymbol(math, textord, "!", "\\oc"); // cmll package - defineSymbol(math, textord, "?", "\\wn"); - defineSymbol(math, textord, "\u2193", "\\shpos"); - defineSymbol(math, textord, "\u2195", "\\shift"); - defineSymbol(math, textord, "\u2191", "\\shneg"); - defineSymbol(math, close, "?", "?"); - defineSymbol(math, close, "!", "!"); - defineSymbol(math, close, "‼", "‼"); - defineSymbol(math, close, "\u27e9", "\\rangle", true); - defineSymbol(math, close, "|", "\\rvert"); - defineSymbol(math, close, "\u2016", "\\rVert"); - defineSymbol(math, open, "\u2983", "\\lBrace", true); // stmaryrd/semantic packages - defineSymbol(math, close, "\u2984", "\\rBrace", true); - defineSymbol(math, rel, "=", "\\equal", true); - defineSymbol(math, rel, ":", ":"); - defineSymbol(math, rel, "\u2248", "\\approx", true); - defineSymbol(math, rel, "\u2245", "\\cong", true); - defineSymbol(math, rel, "\u2265", "\\ge"); - defineSymbol(math, rel, "\u2265", "\\geq", true); - defineSymbol(math, rel, "\u2190", "\\gets"); - defineSymbol(math, rel, ">", "\\gt", true); - defineSymbol(math, rel, "\u2208", "\\in", true); - defineSymbol(math, rel, "\u2209", "\\notin", true); - defineSymbol(math, rel, "\ue020", "\\@not"); - defineSymbol(math, rel, "\u2282", "\\subset", true); - defineSymbol(math, rel, "\u2283", "\\supset", true); - defineSymbol(math, rel, "\u2286", "\\subseteq", true); - defineSymbol(math, rel, "\u2287", "\\supseteq", true); - defineSymbol(math, rel, "\u2288", "\\nsubseteq", true); - defineSymbol(math, rel, "\u2288", "\\nsubseteqq"); - defineSymbol(math, rel, "\u2289", "\\nsupseteq", true); - defineSymbol(math, rel, "\u2289", "\\nsupseteqq"); - defineSymbol(math, rel, "\u22a8", "\\models"); - defineSymbol(math, rel, "\u2190", "\\leftarrow", true); - defineSymbol(math, rel, "\u2264", "\\le"); - defineSymbol(math, rel, "\u2264", "\\leq", true); - defineSymbol(math, rel, "<", "\\lt", true); - defineSymbol(math, rel, "\u2192", "\\rightarrow", true); - defineSymbol(math, rel, "\u2192", "\\to"); - defineSymbol(math, rel, "\u2271", "\\ngeq", true); - defineSymbol(math, rel, "\u2271", "\\ngeqq"); - defineSymbol(math, rel, "\u2271", "\\ngeqslant"); - defineSymbol(math, rel, "\u2270", "\\nleq", true); - defineSymbol(math, rel, "\u2270", "\\nleqq"); - defineSymbol(math, rel, "\u2270", "\\nleqslant"); - defineSymbol(math, rel, "\u2aeb", "\\Perp", true); //cmll package - defineSymbol(math, spacing, "\u00a0", "\\ "); - defineSymbol(math, spacing, "\u00a0", "\\space"); - // Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% - defineSymbol(math, spacing, "\u00a0", "\\nobreakspace"); - defineSymbol(text, spacing, "\u00a0", "\\ "); - defineSymbol(text, spacing, "\u00a0", " "); - defineSymbol(text, spacing, "\u00a0", "\\space"); - defineSymbol(text, spacing, "\u00a0", "\\nobreakspace"); - defineSymbol(math, spacing, null, "\\nobreak"); - defineSymbol(math, spacing, null, "\\allowbreak"); - defineSymbol(math, punct, ",", ","); - defineSymbol(text, punct, ":", ":"); - defineSymbol(math, punct, ";", ";"); - defineSymbol(math, bin, "\u22bc", "\\barwedge", true); - defineSymbol(math, bin, "\u22bb", "\\veebar", true); - defineSymbol(math, bin, "\u2299", "\\odot", true); - defineSymbol(math, bin, "\u2295", "\\oplus", true); - defineSymbol(math, bin, "\u2297", "\\otimes", true); - defineSymbol(math, textord, "\u2202", "\\partial", true); - defineSymbol(math, bin, "\u2298", "\\oslash", true); - defineSymbol(math, bin, "\u229a", "\\circledcirc", true); - defineSymbol(math, bin, "\u22a1", "\\boxdot", true); - defineSymbol(math, bin, "\u25b3", "\\bigtriangleup"); - defineSymbol(math, bin, "\u25bd", "\\bigtriangledown"); - defineSymbol(math, bin, "\u2020", "\\dagger"); - defineSymbol(math, bin, "\u22c4", "\\diamond"); - defineSymbol(math, bin, "\u22c6", "\\star"); - defineSymbol(math, bin, "\u25c3", "\\triangleleft"); - defineSymbol(math, bin, "\u25b9", "\\triangleright"); - defineSymbol(math, open, "{", "\\{"); - defineSymbol(text, textord, "{", "\\{"); - defineSymbol(text, textord, "{", "\\textbraceleft"); - defineSymbol(math, close, "}", "\\}"); - defineSymbol(text, textord, "}", "\\}"); - defineSymbol(text, textord, "}", "\\textbraceright"); - defineSymbol(math, open, "{", "\\lbrace"); - defineSymbol(math, close, "}", "\\rbrace"); - defineSymbol(math, open, "[", "\\lbrack", true); - defineSymbol(text, textord, "[", "\\lbrack", true); - defineSymbol(math, close, "]", "\\rbrack", true); - defineSymbol(text, textord, "]", "\\rbrack", true); - defineSymbol(math, open, "(", "\\lparen", true); - defineSymbol(math, close, ")", "\\rparen", true); - defineSymbol(text, textord, "<", "\\textless", true); // in T1 fontenc - defineSymbol(text, textord, ">", "\\textgreater", true); // in T1 fontenc - defineSymbol(math, open, "\u230a", "\\lfloor", true); - defineSymbol(math, close, "\u230b", "\\rfloor", true); - defineSymbol(math, open, "\u2308", "\\lceil", true); - defineSymbol(math, close, "\u2309", "\\rceil", true); - defineSymbol(math, textord, "\\", "\\backslash"); - defineSymbol(math, textord, "|", "|"); - defineSymbol(math, textord, "|", "\\vert"); - defineSymbol(text, textord, "|", "\\textbar", true); // in T1 fontenc - defineSymbol(math, textord, "\u2016", "\\|"); - defineSymbol(math, textord, "\u2016", "\\Vert"); - defineSymbol(text, textord, "\u2016", "\\textbardbl"); - defineSymbol(text, textord, "~", "\\textasciitilde"); - defineSymbol(text, textord, "\\", "\\textbackslash"); - defineSymbol(text, textord, "^", "\\textasciicircum"); - defineSymbol(math, rel, "\u2191", "\\uparrow", true); - defineSymbol(math, rel, "\u21d1", "\\Uparrow", true); - defineSymbol(math, rel, "\u2193", "\\downarrow", true); - defineSymbol(math, rel, "\u21d3", "\\Downarrow", true); - defineSymbol(math, rel, "\u2195", "\\updownarrow", true); - defineSymbol(math, rel, "\u21d5", "\\Updownarrow", true); - defineSymbol(math, op, "\u2210", "\\coprod"); - defineSymbol(math, op, "\u22c1", "\\bigvee"); - defineSymbol(math, op, "\u22c0", "\\bigwedge"); - defineSymbol(math, op, "\u2a04", "\\biguplus"); - defineSymbol(math, op, "\u22c2", "\\bigcap"); - defineSymbol(math, op, "\u22c3", "\\bigcup"); - defineSymbol(math, op, "\u222b", "\\int"); - defineSymbol(math, op, "\u222b", "\\intop"); - defineSymbol(math, op, "\u222c", "\\iint"); - defineSymbol(math, op, "\u222d", "\\iiint"); - defineSymbol(math, op, "\u220f", "\\prod"); - defineSymbol(math, op, "\u2211", "\\sum"); - defineSymbol(math, op, "\u2a02", "\\bigotimes"); - defineSymbol(math, op, "\u2a01", "\\bigoplus"); - defineSymbol(math, op, "\u2a00", "\\bigodot"); - defineSymbol(math, op, "\u222e", "\\oint"); - defineSymbol(math, op, "\u222f", "\\oiint"); - defineSymbol(math, op, "\u2230", "\\oiiint"); - defineSymbol(math, op, "\u2231", "\\intclockwise"); - defineSymbol(math, op, "\u2232", "\\varointclockwise"); - defineSymbol(math, op, "\u2a0c", "\\iiiint"); - defineSymbol(math, op, "\u2a0d", "\\intbar"); - defineSymbol(math, op, "\u2a0e", "\\intBar"); - defineSymbol(math, op, "\u2a0f", "\\fint"); - defineSymbol(math, op, "\u2a12", "\\rppolint"); - defineSymbol(math, op, "\u2a13", "\\scpolint"); - defineSymbol(math, op, "\u2a15", "\\pointint"); - defineSymbol(math, op, "\u2a16", "\\sqint"); - defineSymbol(math, op, "\u2a17", "\\intlarhk"); - defineSymbol(math, op, "\u2a18", "\\intx"); - defineSymbol(math, op, "\u2a19", "\\intcap"); - defineSymbol(math, op, "\u2a1a", "\\intcup"); - defineSymbol(math, op, "\u2a05", "\\bigsqcap"); - defineSymbol(math, op, "\u2a06", "\\bigsqcup"); - defineSymbol(math, op, "\u222b", "\\smallint"); - defineSymbol(text, inner, "\u2026", "\\textellipsis"); - defineSymbol(math, inner, "\u2026", "\\mathellipsis"); - defineSymbol(text, inner, "\u2026", "\\ldots", true); - defineSymbol(math, inner, "\u2026", "\\ldots", true); - defineSymbol(math, inner, "\u22f0", "\\iddots", true); - defineSymbol(math, inner, "\u22ef", "\\@cdots", true); - defineSymbol(math, inner, "\u22f1", "\\ddots", true); - defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro - defineSymbol(math, accent, "\u02ca", "\\acute"); - defineSymbol(math, accent, "\u0060", "\\grave"); - defineSymbol(math, accent, "\u00a8", "\\ddot"); - defineSymbol(math, accent, "\u20db", "\\dddot"); - defineSymbol(math, accent, "\u20dc", "\\ddddot"); - defineSymbol(math, accent, "\u007e", "\\tilde"); - defineSymbol(math, accent, "\u203e", "\\bar"); - defineSymbol(math, accent, "\u02d8", "\\breve"); - defineSymbol(math, accent, "\u02c7", "\\check"); - defineSymbol(math, accent, "\u005e", "\\hat"); - defineSymbol(math, accent, "\u20d7", "\\vec"); - defineSymbol(math, accent, "\u02d9", "\\dot"); - defineSymbol(math, accent, "\u02da", "\\mathring"); - defineSymbol(math, mathord, "\u0131", "\\imath", true); - defineSymbol(math, mathord, "\u0237", "\\jmath", true); - defineSymbol(math, textord, "\u0131", "\u0131"); - defineSymbol(math, textord, "\u0237", "\u0237"); - defineSymbol(text, textord, "\u0131", "\\i", true); - defineSymbol(text, textord, "\u0237", "\\j", true); - defineSymbol(text, textord, "\u00df", "\\ss", true); - defineSymbol(text, textord, "\u00e6", "\\ae", true); - defineSymbol(text, textord, "\u0153", "\\oe", true); - defineSymbol(text, textord, "\u00f8", "\\o", true); - defineSymbol(math, mathord, "\u00f8", "\\o", true); - defineSymbol(text, textord, "\u00c6", "\\AE", true); - defineSymbol(text, textord, "\u0152", "\\OE", true); - defineSymbol(text, textord, "\u00d8", "\\O", true); - defineSymbol(math, mathord, "\u00d8", "\\O", true); - defineSymbol(text, accent, "\u02ca", "\\'"); // acute - defineSymbol(text, accent, "\u02cb", "\\`"); // grave - defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex - defineSymbol(text, accent, "\u02dc", "\\~"); // tilde - defineSymbol(text, accent, "\u02c9", "\\="); // macron - defineSymbol(text, accent, "\u02d8", "\\u"); // breve - defineSymbol(text, accent, "\u02d9", "\\."); // dot above - defineSymbol(text, accent, "\u00b8", "\\c"); // cedilla - defineSymbol(text, accent, "\u02da", "\\r"); // ring above - defineSymbol(text, accent, "\u02c7", "\\v"); // caron - defineSymbol(text, accent, "\u00a8", '\\"'); // diaresis - defineSymbol(text, accent, "\u02dd", "\\H"); // double acute - defineSymbol(math, accent, "\u02ca", "\\'"); // acute - defineSymbol(math, accent, "\u02cb", "\\`"); // grave - defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex - defineSymbol(math, accent, "\u02dc", "\\~"); // tilde - defineSymbol(math, accent, "\u02c9", "\\="); // macron - defineSymbol(math, accent, "\u02d8", "\\u"); // breve - defineSymbol(math, accent, "\u02d9", "\\."); // dot above - defineSymbol(math, accent, "\u00b8", "\\c"); // cedilla - defineSymbol(math, accent, "\u02da", "\\r"); // ring above - defineSymbol(math, accent, "\u02c7", "\\v"); // caron - defineSymbol(math, accent, "\u00a8", '\\"'); // diaresis - defineSymbol(math, accent, "\u02dd", "\\H"); // double acute - - // These ligatures are detected and created in Parser.js's `formLigatures`. - const ligatures = { - "--": true, - "---": true, - "``": true, - "''": true - }; - - defineSymbol(text, textord, "\u2013", "--", true); - defineSymbol(text, textord, "\u2013", "\\textendash"); - defineSymbol(text, textord, "\u2014", "---", true); - defineSymbol(text, textord, "\u2014", "\\textemdash"); - defineSymbol(text, textord, "\u2018", "`", true); - defineSymbol(text, textord, "\u2018", "\\textquoteleft"); - defineSymbol(text, textord, "\u2019", "'", true); - defineSymbol(text, textord, "\u2019", "\\textquoteright"); - defineSymbol(text, textord, "\u201c", "``", true); - defineSymbol(text, textord, "\u201c", "\\textquotedblleft"); - defineSymbol(text, textord, "\u201d", "''", true); - defineSymbol(text, textord, "\u201d", "\\textquotedblright"); - // \degree from gensymb package - defineSymbol(math, textord, "\u00b0", "\\degree", true); - defineSymbol(text, textord, "\u00b0", "\\degree"); - // \textdegree from inputenc package - defineSymbol(text, textord, "\u00b0", "\\textdegree", true); - // TODO: In LaTeX, \pounds can generate a different character in text and math - // mode, but among our fonts, only Main-Regular defines this character "163". - defineSymbol(math, textord, "\u00a3", "\\pounds"); - defineSymbol(math, textord, "\u00a3", "\\mathsterling", true); - defineSymbol(text, textord, "\u00a3", "\\pounds"); - defineSymbol(text, textord, "\u00a3", "\\textsterling", true); - defineSymbol(math, textord, "\u2720", "\\maltese"); - defineSymbol(text, textord, "\u2720", "\\maltese"); - defineSymbol(math, textord, "\u20ac", "\\euro", true); - defineSymbol(text, textord, "\u20ac", "\\euro", true); - defineSymbol(text, textord, "\u20ac", "\\texteuro"); - defineSymbol(math, textord, "\u00a9", "\\copyright", true); - defineSymbol(text, textord, "\u00a9", "\\textcopyright"); - - // Italic Greek - defineSymbol(math, textord, "𝛤", "\\varGamma"); - defineSymbol(math, textord, "𝛥", "\\varDelta"); - defineSymbol(math, textord, "𝛩", "\\varTheta"); - defineSymbol(math, textord, "𝛬", "\\varLambda"); - defineSymbol(math, textord, "𝛯", "\\varXi"); - defineSymbol(math, textord, "𝛱", "\\varPi"); - defineSymbol(math, textord, "𝛴", "\\varSigma"); - defineSymbol(math, textord, "𝛶", "\\varUpsilon"); - defineSymbol(math, textord, "𝛷", "\\varPhi"); - defineSymbol(math, textord, "𝛹", "\\varPsi"); - defineSymbol(math, textord, "𝛺", "\\varOmega"); - defineSymbol(text, textord, "𝛤", "\\varGamma"); - defineSymbol(text, textord, "𝛥", "\\varDelta"); - defineSymbol(text, textord, "𝛩", "\\varTheta"); - defineSymbol(text, textord, "𝛬", "\\varLambda"); - defineSymbol(text, textord, "𝛯", "\\varXi"); - defineSymbol(text, textord, "𝛱", "\\varPi"); - defineSymbol(text, textord, "𝛴", "\\varSigma"); - defineSymbol(text, textord, "𝛶", "\\varUpsilon"); - defineSymbol(text, textord, "𝛷", "\\varPhi"); - defineSymbol(text, textord, "𝛹", "\\varPsi"); - defineSymbol(text, textord, "𝛺", "\\varOmega"); - - - // There are lots of symbols which are the same, so we add them in afterwards. - // All of these are textords in math mode - const mathTextSymbols = '0123456789/@."'; - for (let i = 0; i < mathTextSymbols.length; i++) { - const ch = mathTextSymbols.charAt(i); - defineSymbol(math, textord, ch, ch); - } - - // All of these are textords in text mode - const textSymbols = '0123456789!@*()-=+";:?/.,'; - for (let i = 0; i < textSymbols.length; i++) { - const ch = textSymbols.charAt(i); - defineSymbol(text, textord, ch, ch); - } - - // All of these are textords in text mode, and mathords in math mode - const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - for (let i = 0; i < letters.length; i++) { - const ch = letters.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); - } - - // Some more letters in Unicode Basic Multilingual Plane. - const narrow = "ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ"; - for (let i = 0; i < narrow.length; i++) { - const ch = narrow.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); - } - - // The next loop loads wide (surrogate pair) characters. - // We support some letters in the Unicode range U+1D400 to U+1D7FF, - // Mathematical Alphanumeric Symbols. - let wideChar = ""; - for (let i = 0; i < letters.length; i++) { - // The hex numbers in the next line are a surrogate pair. - // 0xD835 is the high surrogate for all letters in the range we support. - // 0xDC00 is the low surrogate for bold A. - wideChar = String.fromCharCode(0xd835, 0xdc00 + i); // A-Z a-z bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc34 + i); // A-Z a-z italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc68 + i); // A-Z a-z bold italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd04 + i); // A-Z a-z Fractur - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdda0 + i); // A-Z a-z sans-serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xddd4 + i); // A-Z a-z sans bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde08 + i); // A-Z a-z sans italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde70 + i); // A-Z a-z monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd38 + i); // A-Z a-z double struck - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - const ch = letters.charAt(i); - wideChar = String.fromCharCode(0xd835, 0xdc9c + i); // A-Z a-z calligraphic - defineSymbol(math, mathord, ch, wideChar); - defineSymbol(text, textord, ch, wideChar); - } - - // Next, some wide character numerals - for (let i = 0; i < 10; i++) { - wideChar = String.fromCharCode(0xd835, 0xdfce + i); // 0-9 bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfe2 + i); // 0-9 sans serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfec + i); // 0-9 bold sans - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdff6 + i); // 0-9 monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - } - - /* - * Neither Firefox nor Chrome support hard line breaks or soft line breaks. - * (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs) - * So Temml has work-arounds for both hard and soft breaks. - * The work-arounds sadly do not work simultaneously. Any top-level hard - * break makes soft line breaks impossible. - * - * Hard breaks are simulated by creating a and putting each line in its own . - * - * To create soft line breaks, Temml avoids using the and tags. - * Then the top level of a element can be occupied by elements, and the browser - * will break after a if the expression extends beyond the container limit. - * - * We want the expression to render with soft line breaks after each top-level binary or - * relational operator, per TeXbook p. 173. So we gather the expression into s so that - * each ends in a binary or relational operator. - * - * Soft line breaks will not work in Chromium and Safari, only Firefox. - * - * Hopefully browsers will someday do their own linebreaking and we will be able to delete - * much of this module. - */ - - function setLineBreaks(expression, isDisplayMode, isAnnotated, color = undefined) { - if (color === undefined) { - // First, make one pass through the expression and split any color nodes. - const upperLimit = expression.length - 1; - for (let i = upperLimit; i >= 0; i--) { - const node = expression[i]; - if (node.type === "mstyle" && node.attributes.mathcolor) { - const color = node.attributes.mathcolor; - const fragment = setLineBreaks(node.children, isDisplayMode, isAnnotated, color); - if (!(fragment.type && fragment.type !== "mtable")) { - expression.splice(i, 1, ...fragment.children); - - } - } - } - } - - const tagName = color ? "mstyle" : "mrow"; - - const mtrs = []; - let mrows = []; - let block = []; - let canBeBIN = false; // The first node cannot be an infix binary operator. - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type && node.type === "mstyle" && node.attributes.mathcolor) { - // Start a new block. (Insert a soft linebreak.) - mrows.push(new mathMLTree.MathNode(tagName, block)); - // Insert the mstyle - mrows.push(node); - block = []; - continue - } - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(new mathMLTree.MathNode(tagName, block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - continue - } - block.push(node); - if (node.type && node.type === "mo" && !isDisplayMode && !isAnnotated) { - // This may be a place for a soft line break. - if (canBeBIN && !node.attributes.form) { - // Check if the following node is a \nobreak text node, e.g. "~"" - const next = i < expression.length - 1 ? expression[i + 1] : null; - let glueIsFreeOfNobreak = true; - if ( - !( - next && - next.type === "mtext" && - next.attributes.linebreak && - next.attributes.linebreak === "nobreak" - ) - ) { - // We may need to start a new block. - // First, put any post-operator glue on same line as operator. - for (let j = i + 1; j < expression.length; j++) { - const nd = expression[j]; - if ( - nd.type && - nd.type === "mspace" && - !(nd.attributes.linebreak && nd.attributes.linebreak === "newline") - ) { - block.push(nd); - i += 1; - if ( - nd.attributes && - nd.attributes.linebreak && - nd.attributes.linebreak === "nobreak" - ) { - glueIsFreeOfNobreak = false; - } - } else { - break; - } - } - } - if (glueIsFreeOfNobreak) { - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - block = []; - } - canBeBIN = false; - } - const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"; - // Any operator that follows an open delimiter is unary. - canBeBIN = !(node.attributes.separator || isOpenDelimiter); - } else { - canBeBIN = true; - } - } - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - const mtr = new mathMLTree.MathNode("mtr", [mtd]); - mtrs.push(mtr); - const mtable = new mathMLTree.MathNode("mtable", mtrs); - if (!isDisplayMode) { - mtable.setAttribute("columnalign", "left"); - mtable.setAttribute("rowspacing", "0em"); - } - return mtable - } - return mathMLTree.newDocumentFragment(mrows); - } - - /** - * This file converts a parse tree into a cooresponding MathML tree. The main - * entry point is the `buildMathML` function, which takes a parse tree from the - * parser. - */ - - /** - * Takes a symbol and converts it into a MathML text node after performing - * optional replacement from symbols.js. - */ - const makeText = function(text, mode, style) { - if ( - symbols[mode][text] && - symbols[mode][text].replace && - text.charCodeAt(0) !== 0xd835 && - !( - Object.prototype.hasOwnProperty.call(ligatures, text) && - style && - ((style.fontFamily && style.fontFamily.slice(4, 6) === "tt") || - (style.font && style.font.slice(4, 6) === "tt")) - ) - ) { - text = symbols[mode][text].replace; - } - - return new mathMLTree.TextNode(text); - }; - - /** - * Wrap the given array of nodes in an node if needed, i.e., - * unless the array has length 1. Always returns a single node. - */ - const makeRow = function(body) { - if (body.length === 1) { - return body[0]; - } else { - return new mathMLTree.MathNode("mrow", body); - } - }; - - const isRel = item => { - return (item.type === "atom" && item.family === "rel") || - (item.type === "mclass" && item.mclass === "mrel") - }; - - /** - * Takes a list of nodes, builds them, and returns a list of the generated - * MathML nodes. Also do a couple chores along the way: - * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}. - * (2) Suppress spacing between two adjacent relations. - */ - const buildExpression = function(expression, style, isOrdgroup) { - if (expression.length === 1) { - const group = buildGroup$1(expression[0], style); - if (isOrdgroup && group instanceof MathNode && group.type === "mo") { - // When TeX writers want to suppress spacing on an operator, - // they often put the operator by itself inside braces. - group.setAttribute("lspace", "0em"); - group.setAttribute("rspace", "0em"); - } - return [group]; - } - - const groups = []; - for (let i = 0; i < expression.length; i++) { - const group = buildGroup$1(expression[i], style); - // Suppress spacing between adjacent relations - if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) { - group.setAttribute("rspace", "0em"); - } - if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) { - group.setAttribute("lspace", "0em"); - } - groups.push(group); - } - return groups; - }; - - /** - * Equivalent to buildExpression, but wraps the elements in an - * if there's more than one. Returns a single node instead of an array. - */ - const buildExpressionRow = function(expression, style, isOrdgroup) { - return makeRow(buildExpression(expression, style, isOrdgroup)); - }; - - /** - * Takes a group from the parser and calls the appropriate groupBuilders function - * on it to produce a MathML node. - */ - const buildGroup$1 = function(group, style) { - if (!group) { - return new mathMLTree.MathNode("mrow"); - } - - if (_mathmlGroupBuilders[group.type]) { - // Call the groupBuilders function - const result = _mathmlGroupBuilders[group.type](group, style); - return result; - } else { - throw new ParseError("Got group of unknown type: '" + group.type + "'"); - } - }; - - const glue = _ => { - const glueNode = new mathMLTree.MathNode("mtd", []); - glueNode.setAttribute("style", "padding: 0;width: 50%;"); - return glueNode - }; - - const taggedExpression = (expression, tag, style, leqno, preventTagLap) => { - tag = buildExpressionRow(tag[0].body, style); - tag = utils.consolidateText(tag); - tag.classes = ["tml-tag"]; - if (!preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - tag.setAttribute((leqno ? "rspace" : "lspace"), "-1width"); - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = leqno - ? [tag, glue(), expression, glue()] - : [glue(), expression, glue(), tag]; - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.setAttribute("width", "100%"); - table.setAttribute("displaystyle", "true"); - return table - }; - - /** - * Takes a full parse tree and settings and builds a MathML representation of - * it. - */ - function buildMathML(tree, texExpression, style, settings) { - // Strip off outer tag wrapper for processing below. - let tag = null; - if (tree.length === 1 && tree[0].type === "tag") { - tag = tree[0].tag; - tree = tree[0].body; - } - - const expression = buildExpression(tree, style); - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - && !(n1.type === "mstyle" && n1.attributes.mathcolor) - ? expression[0] - : setLineBreaks(expression, settings.displayMode, settings.annotate); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno, settings.preventTagLap); - } - - let semantics; - if (settings.annotate) { - // Build a TeX annotation of the source - const annotation = new mathMLTree.MathNode( - "annotation", [new mathMLTree.TextNode(texExpression)]); - annotation.setAttribute("encoding", "application/x-tex"); - semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = settings.annotate - ? new mathMLTree.MathNode("math", [semantics]) - : new mathMLTree.MathNode("math", [wrapper]); - - if (settings.xml) { - math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); - } - if (settings.displayMode) { - math.setAttribute("display", "block"); - } - return math; - } - - const mathmlBuilder$a = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.mathMLnode(group.label) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup$1(group.base, style), accentNode] - ); - - node.setAttribute("accent", "true"); - return node; - }; - - const NON_STRETCHY_ACCENT_REGEX = new RegExp( - [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" - ] - .map((accent) => `\\${accent}`) - .join("|") - ); - - // Accents - defineFunction({ - type: "accent", - names: [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring", - "\\overparen", - "\\widecheck", - "\\widehat", - "\\wideparen", - "\\widetilde", - "\\overrightarrow", - "\\overleftarrow", - "\\Overrightarrow", - "\\overleftrightarrow", - "\\overgroup", - "\\overleftharpoon", - "\\overrightharpoon" - ], - props: { - numArgs: 1 - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - - const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); - const isShifty = - !isStretchy || - context.funcName === "\\widehat" || - context.funcName === "\\widetilde" || - context.funcName === "\\widecheck"; - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - isShifty: isShifty, - base: base - }; - }, - mathmlBuilder: mathmlBuilder$a - }); - - // Text-mode accents - defineFunction({ - type: "accent", - names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\c", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"], - props: { - numArgs: 1, - allowedInText: true, - allowedInMath: true, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - const mode = context.parser.mode; - - if (mode === "math" && context.parser.settings.strict) { - // LaTeX only writes a warning. It doesn't stop. We'll issue the same warning. - // eslint-disable-next-line no-console - console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`); - } - - return { - type: "accent", - mode: mode, - label: context.funcName, - isStretchy: false, - isShifty: true, - base: base - }; - }, - mathmlBuilder: mathmlBuilder$a - }); - - defineFunction({ - type: "accentUnder", - names: [ - "\\underleftarrow", - "\\underrightarrow", - "\\underleftrightarrow", - "\\undergroup", - "\\underparen", - "\\utilde" - ], - props: { - numArgs: 1 - }, - handler: ({ parser, funcName }, args) => { - const base = args[0]; - return { - type: "accentUnder", - mode: parser.mode, - label: funcName, - base: base - }; - }, - mathmlBuilder: (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - const node = new mathMLTree.MathNode("munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - node.setAttribute("accentunder", "true"); - return node; - } - }); - - /** - * This file does conversion between units. In particular, it provides - * calculateSize to convert other units into CSS units. - */ - - const ptPerUnit = { - // Convert to CSS (Postscipt) points, not TeX points - // https://en.wikibooks.org/wiki/LaTeX/Lengths and - // https://tex.stackexchange.com/a/8263 - pt: 800 / 803, // convert TeX point to CSS (Postscript) point - pc: (12 * 800) / 803, // pica - dd: ((1238 / 1157) * 800) / 803, // didot - cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot) - nd: ((685 / 642) * 800) / 803, // new didot - nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot) - sp: ((1 / 65536) * 800) / 803, // scaled point (TeX's internal smallest unit) - mm: (25.4 / 72), - cm: (2.54 / 72), - in: (1 / 72), - px: (96 / 72) - }; - - /** - * Determine whether the specified unit (either a string defining the unit - * or a "size" parse node containing a unit field) is valid. - */ - const validUnits = [ - "em", - "ex", - "mu", - "pt", - "mm", - "cm", - "in", - "px", - "bp", - "pc", - "dd", - "cc", - "nd", - "nc", - "sp" - ]; - - const validUnit = function(unit) { - if (typeof unit !== "string") { - unit = unit.unit; - } - return validUnits.indexOf(unit) > -1 - }; - - const emScale = styleLevel => { - const scriptLevel = Math.max(styleLevel - 1, 0); - return [1, 0.7, 0.5][scriptLevel] - }; - - /* - * Convert a "size" parse node (with numeric "number" and string "unit" fields, - * as parsed by functions.js argType "size") into a CSS value. - */ - const calculateSize = function(sizeValue, style) { - let number = sizeValue.number; - if (style.maxSize[0] < 0 && number > 0) { - return { number: 0, unit: "em" } - } - const unit = sizeValue.unit; - switch (unit) { - case "mm": - case "cm": - case "in": - case "px": { - const numInCssPts = number * ptPerUnit[unit]; - if (numInCssPts > style.maxSize[1]) { - return { number: style.maxSize[1], unit: "pt" } - } - return { number, unit }; // absolute CSS units. - } - case "em": - case "ex": { - // In TeX, em and ex do not change size in \scriptstyle. - if (unit === "ex") { number *= 0.431; } - number = Math.min(number / emScale(style.level), style.maxSize[0]); - return { number: utils.round(number), unit: "em" }; - } - case "bp": { - if (number > style.maxSize[1]) { number = style.maxSize[1]; } - return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch). - } - case "pt": - case "pc": - case "dd": - case "cc": - case "nd": - case "nc": - case "sp": { - number = Math.min(number * ptPerUnit[unit], style.maxSize[1]); - return { number: utils.round(number), unit: "pt" } - } - case "mu": { - number = Math.min(number / 18, style.maxSize[0]); - return { number: utils.round(number), unit: "em" } - } - default: - throw new ParseError("Invalid unit: '" + unit + "'") - } - }; - - // Helper functions - const paddedNode = (group, width, lspace = "0.3em") => { - const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); - node.setAttribute("width", width); - node.setAttribute("lspace", lspace); - return node; - }; - - const labelSize = (size, scriptLevel) => (size / emScale(scriptLevel)).toFixed(4) + "em"; - - const munderoverNode = (name, body, below, style) => { - const arrowNode = stretchy.mathMLnode(name); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = name.slice(1, 3) === "eq"; - const minWidth = name.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are 1.75em long - : name.slice(2, 4) === "cd" - ? "3.0" // cd package arrows - : isEq - ? "1.0" // The shorter harpoon of a mhchem equilibrium arrow - : "2.0"; // other mhchem arrows - arrowNode.setAttribute("minsize", String(minWidth) + "em"); - arrowNode.setAttribute("lspace", "0"); - arrowNode.setAttribute("rspace", (isEq ? "0.5em" : "0")); - - // upper and lower labels are set to scriptlevel by MathML - // So we have to adjust our dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3); - const emptyLabelWidth = labelSize(minWidth, labelStyle.level); - const lspace = labelSize((isEq ? 0 : 0.3), labelStyle.level); - let widthAdder = labelSize((isEq ? -0.4 : 0.6), labelStyle.level); - if (widthAdder.charAt(0) !== "-") { widthAdder = "+" + widthAdder; } - - const upperNode = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)) - ? paddedNode(buildGroup$1(body, labelStyle), widthAdder, lspace) - // Since Firefox does not recognize minsize set on the arrow, - // create an upper node w/correct width. - : paddedNode(null, emptyLabelWidth, "0"); - const lowerNode = (below && below.body && - (below.body.body || below.body.length > 0)) - ? paddedNode(buildGroup$1(below, labelStyle), widthAdder, lspace) - : paddedNode(null, emptyLabelWidth, "0"); - const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - return node - }; - - // Stretchy arrows with an optional argument - defineFunction({ - type: "xArrow", - names: [ - "\\xleftarrow", - "\\xrightarrow", - "\\xLeftarrow", - "\\xRightarrow", - "\\xleftrightarrow", - "\\xLeftrightarrow", - "\\xhookleftarrow", - "\\xhookrightarrow", - "\\xmapsto", - "\\xrightharpoondown", - "\\xrightharpoonup", - "\\xleftharpoondown", - "\\xleftharpoonup", - "\\xlongequal", - "\\xtwoheadrightarrow", - "\\xtwoheadleftarrow", - // The next 7 functions are here only to support mhchem - "\\yields", - "\\yieldsLeft", - "\\mesomerism", - "\\longrightharpoonup", - "\\longleftharpoondown", - // The next 3 functions are here only to support the {CD} environment. - "\\\\cdrightarrow", - "\\\\cdleftarrow", - "\\\\cdlongequal" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - return { - type: "xArrow", - mode: parser.mode, - name: funcName, - body: args[0], - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - // Build the arrow and its labels. - const node = munderoverNode(group.name, group.body, group.below, style); - // Create operator spacing for a relation. - const wrapper = new mathMLTree.MathNode("mpadded", [node]); - wrapper.setAttribute("lspace", "0.2778em"); - wrapper.setAttribute("width", "+0.5556em"); - return wrapper - } - }); - - const arrowComponent = { - "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"], - "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"], - "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"], - "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"], - // The next three all get the same harpoon glyphs. Only the lengths and paddings differ. - "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"], - "\\equilibriumRight": ["\\longrightharpoonup", "\\eqleftharpoondown"], - "\\equilibriumLeft": ["\\eqrightharpoonup", "\\longleftharpoondown"] - }; - - // Browsers are not good at stretching a glyph that contains a pair of stacked arrows such as ⇄. - // So we stack a pair of single arrows. - defineFunction({ - type: "stackedArrow", - names: [ - "\\xtofrom", // expfeil - "\\xleftrightharpoons", // mathtools - "\\xrightleftharpoons", // mathtools - "\\yieldsLeftRight", // mhchem - "\\equilibrium", // mhchem - "\\equilibriumRight", - "\\equilibriumLeft" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - const lowerArrowBody = args[0] - ? { - type: "hphantom", - mode: parser.mode, - body: args[0] - } - : null; - const upperArrowBelow = optArgs[0] - ? { - type: "hphantom", - mode: parser.mode, - body: optArgs[0] - } - : null; - return { - type: "stackedArrow", - mode: parser.mode, - name: funcName, - body: args[0], - upperArrowBelow, - lowerArrowBody, - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - const topLabel = arrowComponent[group.name][0]; - const botLabel = arrowComponent[group.name][1]; - const topArrow = munderoverNode(topLabel, group.body, group.upperArrowBelow, style); - const botArrow = munderoverNode(botLabel, group.lowerArrowBody, group.below, style); - let wrapper; - - const raiseNode = new mathMLTree.MathNode("mpadded", [topArrow]); - raiseNode.setAttribute("voffset", "0.3em"); - raiseNode.setAttribute("height", "+0.3em"); - raiseNode.setAttribute("depth", "-0.3em"); - // One of the arrows is given ~zero width. so the other has the same horzontal alignment. - if (group.name === "\\equilibriumLeft") { - const botNode = new mathMLTree.MathNode("mpadded", [botArrow]); - botNode.setAttribute("width", "0.5em"); - wrapper = new mathMLTree.MathNode("mpadded", [botNode, raiseNode]); - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")); - wrapper = new mathMLTree.MathNode("mpadded", [raiseNode, botArrow]); - } - - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("width", "+0.5556em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - wrapper.setAttribute("lspace", "0.2778em"); - return wrapper - } - }); - - defineFunction({ - type: "cancelto", - names: ["\\cancelto"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "cancelto", - mode: parser.mode, - value: args[0], - expression: args[1] - }; - }, - mathmlBuilder(group, style) { - const value = new mathMLTree.MathNode( - "mpadded", - [buildGroup$1(group.value, style)] - ); - value.setAttribute("depth", `-0.1em`); - value.setAttribute("height", `+0.1em`); - value.setAttribute("voffset", `0.1em`); - - const expression = new mathMLTree.MathNode( - "menclose", - [buildGroup$1(group.expression, style)] - ); - expression.setAttribute("notation", `updiagonalarrow`); - - return new mathMLTree.MathNode("msup", [expression, value]) - } - }); - - /** - * Asserts that the node is of the given type and returns it with stricter - * typing. Throws if the node's type does not match. - */ - function assertNodeType(node, type) { - if (!node || node.type !== type) { - throw new Error( - `Expected node of type ${type}, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return node; - } - - /** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ - function assertSymbolNodeType(node) { - const typedNode = checkSymbolNodeType(node); - if (!typedNode) { - throw new Error( - `Expected node of symbol group type, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return typedNode; - } - - /** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ - function checkSymbolNodeType(node) { - if (node && (node.type === "atom" || - Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) { - return node; - } - return null; - } - - const cdArrowFunctionName = { - ">": "\\\\cdrightarrow", - "<": "\\\\cdleftarrow", - "=": "\\\\cdlongequal", - A: "\\uparrow", - V: "\\downarrow", - "|": "\\Vert", - ".": "no arrow" - }; - - const newCell = () => { - // Create an empty cell, to be filled below with parse nodes. - return { type: "styling", body: [], mode: "math", scriptLevel: "display" }; - }; - - const isStartOfArrow = (node) => { - return node.type === "textord" && node.text === "@"; - }; - - const isLabelEnd = (node, endChar) => { - return (node.type === "mathord" || node.type === "atom") && node.text === endChar; - }; - - function cdArrow(arrowChar, labels, parser) { - // Return a parse tree of an arrow and its labels. - // This acts in a way similar to a macro expansion. - const funcName = cdArrowFunctionName[arrowChar]; - switch (funcName) { - case "\\\\cdrightarrow": - case "\\\\cdleftarrow": - return parser.callFunction(funcName, [labels[0]], [labels[1]]); - case "\\uparrow": - case "\\downarrow": { - const leftLabel = parser.callFunction("\\\\cdleft", [labels[0]], []); - const bareArrow = { - type: "atom", - text: funcName, - mode: "math", - family: "rel" - }; - const sizedArrow = parser.callFunction("\\Big", [bareArrow], []); - const rightLabel = parser.callFunction("\\\\cdright", [labels[1]], []); - const arrowGroup = { - type: "ordgroup", - mode: "math", - body: [leftLabel, sizedArrow, rightLabel] - }; - return parser.callFunction("\\\\cdparent", [arrowGroup], []); - } - case "\\\\cdlongequal": - return parser.callFunction("\\\\cdlongequal", [], []); - case "\\Vert": { - const arrow = { type: "textord", text: "\\Vert", mode: "math" }; - return parser.callFunction("\\Big", [arrow], []); - } - default: - return { type: "textord", text: " ", mode: "math" }; - } - } - - function parseCD(parser) { - // Get the array's parse nodes with \\ temporarily mapped to \cr. - const parsedRows = []; - parser.gullet.beginGroup(); - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - parser.gullet.beginGroup(); - while (true) { // eslint-disable-line no-constant-condition - // Get the parse nodes for the next row. - parsedRows.push(parser.parseExpression(false, "\\\\")); - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - const next = parser.fetch().text; - if (next === "&" || next === "\\\\") { - parser.consume(); - } else if (next === "\\end") { - if (parsedRows[parsedRows.length - 1].length === 0) { - parsedRows.pop(); // final row ended in \\ - } - break; - } else { - throw new ParseError("Expected \\\\ or \\cr or \\end", parser.nextToken); - } - } - - let row = []; - const body = [row]; - - // Loop thru the parse nodes. Collect them into cells and arrows. - for (let i = 0; i < parsedRows.length; i++) { - // Start a new row. - const rowNodes = parsedRows[i]; - // Create the first cell. - let cell = newCell(); - - for (let j = 0; j < rowNodes.length; j++) { - if (!isStartOfArrow(rowNodes[j])) { - // If a parseNode is not an arrow, it goes into a cell. - cell.body.push(rowNodes[j]); - } else { - // Parse node j is an "@", the start of an arrow. - // Before starting on the arrow, push the cell into `row`. - row.push(cell); - - // Now collect parseNodes into an arrow. - // The character after "@" defines the arrow type. - j += 1; - const arrowChar = assertSymbolNodeType(rowNodes[j]).text; - - // Create two empty label nodes. We may or may not use them. - const labels = new Array(2); - labels[0] = { type: "ordgroup", mode: "math", body: [] }; - labels[1] = { type: "ordgroup", mode: "math", body: [] }; - - // Process the arrow. - if ("=|.".indexOf(arrowChar) > -1) ; else if ("<>AV".indexOf(arrowChar) > -1) { - // Four arrows, `@>>>`, `@<<<`, `@AAA`, and `@VVV`, each take - // two optional labels. E.g. the right-point arrow syntax is - // really: @>{optional label}>{optional label}> - // Collect parseNodes into labels. - for (let labelNum = 0; labelNum < 2; labelNum++) { - let inLabel = true; - for (let k = j + 1; k < rowNodes.length; k++) { - if (isLabelEnd(rowNodes[k], arrowChar)) { - inLabel = false; - j = k; - break; - } - if (isStartOfArrow(rowNodes[k])) { - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[k] - ); - } - - labels[labelNum].body.push(rowNodes[k]); - } - if (inLabel) { - // isLabelEnd never returned a true. - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[j] - ); - } - } - } else { - throw new ParseError(`Expected one of "<>AV=|." after @.`); - } - - // Now join the arrow to its labels. - const arrow = cdArrow(arrowChar, labels, parser); - - // Wrap the arrow in a styling node - row.push(arrow); - // In CD's syntax, cells are implicit. That is, everything that - // is not an arrow gets collected into a cell. So create an empty - // cell now. It will collect upcoming parseNodes. - cell = newCell(); - } - } - if (i % 2 === 0) { - // Even-numbered rows consist of: cell, arrow, cell, arrow, ... cell - // The last cell is not yet pushed into `row`, so: - row.push(cell); - } else { - // Odd-numbered rows consist of: vert arrow, empty cell, ... vert arrow - // Remove the empty cell that was placed at the beginning of `row`. - row.shift(); - } - row = []; - body.push(row); - } - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - // define column separation. - const cols = new Array(body[0].length).fill({ - type: "align", - align: "c" - }); - - return { - type: "array", - mode: "math", - body, - arraystretch: 1, - addJot: true, - rowGaps: [null], - cols, - colSeparationType: "CD", - hLinesBeforeRow: new Array(body.length + 1).fill([]) - }; - } - - // The functions below are not available for general use. - // They are here only for internal use by the {CD} environment in placing labels - // next to vertical arrows. - - // We don't need any such functions for horizontal arrows because we can reuse - // the functionality that already exists for extensible arrows. - - defineFunction({ - type: "cdlabel", - names: ["\\\\cdleft", "\\\\cdright"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "cdlabel", - mode: parser.mode, - side: funcName.slice(4), - label: args[0] - }; - }, - mathmlBuilder(group, style) { - let label = new mathMLTree.MathNode("mrow", [buildGroup$1(group.label, style)]); - label = new mathMLTree.MathNode("mpadded", [label]); - label.setAttribute("width", "0"); - if (group.side === "left") { - label.setAttribute("lspace", "-1width"); - } - // We have to guess at vertical alignment. We know the arrow is 1.8em tall, - // But we don't know the height or depth of the label. - label.setAttribute("voffset", "0.7em"); - label = new mathMLTree.MathNode("mstyle", [label]); - label.setAttribute("displaystyle", "false"); - label.setAttribute("scriptlevel", "1"); - return label; - } - }); - - defineFunction({ - type: "cdlabelparent", - names: ["\\\\cdparent"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - return { - type: "cdlabelparent", - mode: parser.mode, - fragment: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow", [buildGroup$1(group.fragment, style)]); - } - }); - - // \@char is an internal function that takes a grouped decimal argument like - // {123} and converts into symbol with code 123. It is used by the *macro* - // \char defined in macros.js. - defineFunction({ - type: "textord", - names: ["\\@char"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser, token }, args) { - const arg = assertNodeType(args[0], "ordgroup"); - const group = arg.body; - let number = ""; - for (let i = 0; i < group.length; i++) { - const node = assertNodeType(group[i], "textord"); - number += node.text; - } - const code = parseInt(number); - if (isNaN(code)) { - throw new ParseError(`\\@char has non-numeric argument ${number}`, token) - } - return { - type: "textord", - mode: parser.mode, - text: String.fromCodePoint(code) - } - } - }); - - // Helpers - const htmlRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6})$/i; - const htmlOrNameRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i; - const RGBregEx = /^ *\d{1,3} *(?:, *\d{1,3} *){2}$/; - const rgbRegEx = /^ *[10](?:\.\d*)? *(?:, *[10](?:\.\d*)? *){2}$/; - const xcolorHtmlRegEx = /^[a-f0-9]{6}$/i; - const toHex = num => { - let str = num.toString(16); - if (str.length === 1) { str = "0" + str; } - return str - }; - - // Colors from Tables 4.1 and 4.2 of the xcolor package. - // Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx. - // Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable - // conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274. - const xcolors = JSON.parse(`{ - "Apricot": "#ffb484", - "Aquamarine": "#08b4bc", - "Bittersweet": "#c84c14", - "blue": "#0000FF", - "Blue": "#303494", - "BlueGreen": "#08b4bc", - "BlueViolet": "#503c94", - "BrickRed": "#b8341c", - "brown": "#BF8040", - "Brown": "#802404", - "BurntOrange": "#f8941c", - "CadetBlue": "#78749c", - "CarnationPink": "#f884b4", - "Cerulean": "#08a4e4", - "CornflowerBlue": "#40ace4", - "cyan": "#00FFFF", - "Cyan": "#08acec", - "Dandelion": "#ffbc44", - "darkgray": "#404040", - "DarkOrchid": "#a8548c", - "Emerald": "#08ac9c", - "ForestGreen": "#089c54", - "Fuchsia": "#90348c", - "Goldenrod": "#ffdc44", - "gray": "#808080", - "Gray": "#98949c", - "green": "#00FF00", - "Green": "#08a44c", - "GreenYellow": "#e0e474", - "JungleGreen": "#08ac9c", - "Lavender": "#f89cc4", - "lightgray": "#c0c0c0", - "lime": "#BFFF00", - "LimeGreen": "#90c43c", - "magenta": "#FF00FF", - "Magenta": "#f0048c", - "Mahogany": "#b0341c", - "Maroon": "#b03434", - "Melon": "#f89c7c", - "MidnightBlue": "#086494", - "Mulberry": "#b03c94", - "NavyBlue": "#086cbc", - "olive": "#7F7F00", - "OliveGreen": "#407c34", - "orange": "#FF8000", - "Orange": "#f8843c", - "OrangeRed": "#f0145c", - "Orchid": "#b074ac", - "Peach": "#f8945c", - "Periwinkle": "#8074bc", - "PineGreen": "#088c74", - "pink": "#ff7f7f", - "Plum": "#98248c", - "ProcessBlue": "#08b4ec", - "purple": "#BF0040", - "Purple": "#a0449c", - "RawSienna": "#983c04", - "red": "#ff0000", - "Red": "#f01c24", - "RedOrange": "#f86434", - "RedViolet": "#a0246c", - "Rhodamine": "#f0549c", - "Royallue": "#0874bc", - "RoyalPurple": "#683c9c", - "RubineRed": "#f0047c", - "Salmon": "#f8948c", - "SeaGreen": "#30bc9c", - "Sepia": "#701404", - "SkyBlue": "#48c4dc", - "SpringGreen": "#c8dc64", - "Tan": "#e09c74", - "teal": "#007F7F", - "TealBlue": "#08acb4", - "Thistle": "#d884b4", - "Turquoise": "#08b4cc", - "violet": "#800080", - "Violet": "#60449c", - "VioletRed": "#f054a4", - "WildStrawberry": "#f0246c", - "yellow": "#FFFF00", - "Yellow": "#fff404", - "YellowGreen": "#98cc6c", - "YellowOrange": "#ffa41c" -}`); - - const colorFromSpec = (model, spec) => { - let color = ""; - if (model === "HTML") { - if (!htmlRegEx.test(spec)) { - throw new ParseError("Invalid HTML input.") - } - color = spec; - } else if (model === "RGB") { - if (!RGBregEx.test(spec)) { - throw new ParseError("Invalid RGB input.") - } - spec.split(",").map(e => { color += toHex(Number(e.trim())); }); - } else { - if (!rgbRegEx.test(spec)) { - throw new ParseError("Invalid rbg input.") - } - spec.split(",").map(e => { - const num = Number(e.trim()); - if (num > 1) { throw new ParseError("Color rgb input must be < 1.") } - color += toHex((num * 255)); - }); - } - if (color.charAt(0) !== "#") { color = "#" + color; } - return color - }; - - const validateColor = (color, macros, token) => { - const macroName = `\\\\color@${color}`; // from \defineColor. - const match = htmlOrNameRegEx.exec(color); - if (!match) { throw new ParseError("Invalid color: '" + color + "'", token) } - // We allow a 6-digit HTML color spec without a leading "#". - // This follows the xcolor package's HTML color model. - // Predefined color names are all missed by this RegEx pattern. - if (xcolorHtmlRegEx.test(color)) { - return "#" + color - } else if (color.charAt(0) === "#") { - return color - } else if (macros.has(macroName)) { - color = macros.get(macroName).tokens[0].text; - } else if (xcolors[color]) { - color = xcolors[color]; - } - return color - }; - - const mathmlBuilder$9 = (group, style) => { - const inner = buildExpression(group.body, style.withColor(group.color)); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("mathcolor", group.color); - // Wrap w/. We get better operator spacing that way. - return new mathMLTree.MathNode("mrow", [node]) - }; - - defineFunction({ - type: "color", - names: ["\\textcolor"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "original"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token); - } - const body = args[1]; - return { - type: "color", - mode: parser.mode, - color, - body: ordargument(body) - } - }, - mathmlBuilder: mathmlBuilder$9 - }); - - defineFunction({ - type: "color", - names: ["\\color"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token); - } - - // Set macro \current@color in current namespace to store the current - // color, mimicking the behavior of color.sty. - // This is currently used just to correctly color a \right - // that follows a \color command. - parser.gullet.macros.set("\\current@color", color); - - // Parse out the implicit body that should be colored. - // Since \color nodes should not be nested, break on \color. - const body = parser.parseExpression(true, "\\color"); - - return { - type: "color", - mode: parser.mode, - color, - body - } - }, - mathmlBuilder: mathmlBuilder$9 - }); - - defineFunction({ - type: "color", - names: ["\\definecolor"], - props: { - numArgs: 3, - allowedInText: true, - argTypes: ["raw", "raw", "raw"] - }, - handler({ parser, funcName, token }, args) { - const name = assertNodeType(args[0], "raw").string; - if (!/^[A-Za-z]+$/.test(name)) { - throw new ParseError("Color name must be latin letters.", token) - } - const model = assertNodeType(args[1], "raw").string; - if (!["HTML", "RGB", "rgb"].includes(model)) { - throw new ParseError("Color model must be HTML, RGB, or rgb.", token) - } - const spec = assertNodeType(args[2], "raw").string; - const color = colorFromSpec(model, spec); - parser.gullet.macros.set(`\\\\color@${name}`, { tokens: [{ text: color }], numArgs: 0 }); - return { type: "internal", mode: parser.mode } - } - // No mathmlBuilder. The point of \definecolor is to set a macro. - }); - - // Row breaks within tabular environments, and line breaks at top level - - // \DeclareRobustCommand\\{...\@xnewline} - defineFunction({ - type: "cr", - names: ["\\\\"], - props: { - numArgs: 0, - numOptionalArgs: 1, - argTypes: ["size"], - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = optArgs[0]; - const newLine = !parser.settings.displayMode; - return { - type: "cr", - mode: parser.mode, - newLine, - size: size && assertNodeType(size, "size").value - } - }, - - // The following builder is called only at the top level, - // not within tabular/array environments. - - mathmlBuilder(group, style) { - // MathML 3.0 calls for newline to occur in an or an . - // Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.linebreaking - const node = new mathMLTree.MathNode("mo"); - if (group.newLine) { - node.setAttribute("linebreak", "newline"); - if (group.size) { - const size = calculateSize(group.size, style); - node.setAttribute("height", size.number + size.unit); - } - } - return node - } - }); - - const checkControlSequence = (tok) => { - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - return name; - }; - - const getRHS = (parser) => { - let tok = parser.gullet.popToken(); - if (tok.text === "=") { - // consume optional equals - tok = parser.gullet.popToken(); - if (tok.text === " ") { - // consume one optional space - tok = parser.gullet.popToken(); - } - } - return tok; - }; - - const letCommand = (parser, name, tok) => { - let macro = parser.gullet.macros.get(tok.text); - if (macro == null) { - // don't expand it later even if a macro with the same name is defined - // e.g., \let\foo=\frac \def\frac{\relax} \frac12 - tok.noexpand = true; - macro = { - tokens: [tok], - numArgs: 0, - // reproduce the same behavior in expansion - unexpandable: !parser.gullet.isExpandable(tok.text) - }; - } - parser.gullet.macros.set(name, macro); - }; - - // Basic support for macro definitions: \def - // -> - // -> - defineFunction({ - type: "internal", - names: ["\\def", "\\edef"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let tok = parser.gullet.popToken(); - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - - let numArgs = 0; - let insert; - const delimiters = [[]]; - // contains no braces - while (parser.gullet.future().text !== "{") { - tok = parser.gullet.popToken(); - if (tok.text === "#") { - // If the very last character of the is #, so that - // this # is immediately followed by {, TeX will behave as if the { - // had been inserted at the right end of both the parameter text - // and the replacement text. - if (parser.gullet.future().text === "{") { - insert = parser.gullet.future(); - delimiters[numArgs].push("{"); - break; - } - - // A parameter, the first appearance of # must be followed by 1, - // the next by 2, and so on; up to nine #’s are allowed - tok = parser.gullet.popToken(); - if (!/^[1-9]$/.test(tok.text)) { - throw new ParseError(`Invalid argument number "${tok.text}"`); - } - if (parseInt(tok.text) !== numArgs + 1) { - throw new ParseError(`Argument number "${tok.text}" out of order`); - } - numArgs++; - delimiters.push([]); - } else if (tok.text === "EOF") { - throw new ParseError("Expected a macro definition"); - } else { - delimiters[numArgs].push(tok.text); - } - } - // replacement text, enclosed in '{' and '}' and properly nested - let { tokens } = parser.gullet.consumeArg(); - if (insert) { - tokens.unshift(insert); - } - - if (funcName === "\\edef") { - tokens = parser.gullet.expandTokens(tokens); - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set(name, { tokens, numArgs, delimiters } - ); - return { type: "internal", mode: parser.mode }; - } - }); - - // -> - // -> \futurelet - // | \let - // -> |= - defineFunction({ - type: "internal", - names: ["\\let"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.consumeSpaces(); - const tok = getRHS(parser); - letCommand(parser, name, tok); - return { type: "internal", mode: parser.mode }; - } - }); - - // ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf - defineFunction({ - type: "internal", - names: ["\\futurelet"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - const middle = parser.gullet.popToken(); - const tok = parser.gullet.popToken(); - letCommand(parser, name, tok); - parser.gullet.pushToken(tok); - parser.gullet.pushToken(middle); - return { type: "internal", mode: parser.mode }; - } - }); - - defineFunction({ - type: "internal", - names: ["\\newcommand", "\\renewcommand", "\\providecommand"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let name = ""; - const tok = parser.gullet.popToken(); - if (tok.text === "{") { - name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.popToken(); - } else { - name = checkControlSequence(tok); - } - - const exists = parser.gullet.isDefined(name); - if (exists && funcName === "\\newcommand") { - throw new ParseError( - `\\newcommand{${name}} attempting to redefine ${name}; use \\renewcommand` - ); - } - if (!exists && funcName === "\\renewcommand") { - throw new ParseError( - `\\renewcommand{${name}} when command ${name} does not yet exist; use \\newcommand` - ); - } - - let numArgs = 0; - if (parser.gullet.future().text === "[") { - let tok = parser.gullet.popToken(); - tok = parser.gullet.popToken(); - if (!/^[0-9]$/.test(tok.text)) { - throw new ParseError(`Invalid number of arguments: "${tok.text}"`); - } - numArgs = parseInt(tok.text); - tok = parser.gullet.popToken(); - if (tok.text !== "]") { - throw new ParseError(`Invalid argument "${tok.text}"`); - } - } - - // replacement text, enclosed in '{' and '}' and properly nested - const { tokens } = parser.gullet.consumeArg(); - - parser.gullet.macros.set(name, { tokens, numArgs }); - - return { type: "internal", mode: parser.mode }; - - } - }); - - // Extra data needed for the delimiter handler down below - const delimiterSizes = { - "\\bigl": { mclass: "mopen", size: 1 }, - "\\Bigl": { mclass: "mopen", size: 2 }, - "\\biggl": { mclass: "mopen", size: 3 }, - "\\Biggl": { mclass: "mopen", size: 4 }, - "\\bigr": { mclass: "mclose", size: 1 }, - "\\Bigr": { mclass: "mclose", size: 2 }, - "\\biggr": { mclass: "mclose", size: 3 }, - "\\Biggr": { mclass: "mclose", size: 4 }, - "\\bigm": { mclass: "mrel", size: 1 }, - "\\Bigm": { mclass: "mrel", size: 2 }, - "\\biggm": { mclass: "mrel", size: 3 }, - "\\Biggm": { mclass: "mrel", size: 4 }, - "\\big": { mclass: "mord", size: 1 }, - "\\Big": { mclass: "mord", size: 2 }, - "\\bigg": { mclass: "mord", size: 3 }, - "\\Bigg": { mclass: "mord", size: 4 } - }; - - const delimiters = [ - "(", - "\\lparen", - ")", - "\\rparen", - "[", - "\\lbrack", - "]", - "\\rbrack", - "\\{", - "\\lbrace", - "\\}", - "\\rbrace", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lt", - "\\gt", - "\\lvert", - "\\rvert", - "\\lVert", - "\\rVert", - "\\lgroup", - "\\rgroup", - "\u27ee", - "\u27ef", - "\\lmoustache", - "\\rmoustache", - "\u23b0", - "\u23b1", - "\\llbracket", - "\\rrbracket", - "\u27e6", - "\u27e6", - "\\lBrace", - "\\rBrace", - "\u2983", - "\u2984", - "/", - "\\backslash", - "|", - "\\vert", - "\\|", - "\\Vert", - "\\uparrow", - "\\Uparrow", - "\\downarrow", - "\\Downarrow", - "\\updownarrow", - "\\Updownarrow", - "." - ]; - - // Metrics of the different sizes. Found by looking at TeX's output of - // $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ - // Used to create stacked delimiters of appropriate sizes in makeSizedDelim. - const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; - - // Delimiter functions - function checkDelimiter(delim, context) { - if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") { - // Recover "/" from the zero spacing group. (See macros.js) - delim = { type: "textord", text: "/", mode: "math" }; - } - const symDelim = checkSymbolNodeType(delim); - if (symDelim && utils.contains(delimiters, symDelim.text)) { - // If a character is not in the MathML operator dictionary, it will not stretch. - // Replace such characters w/characters that will stretch. - if (utils.contains(["<", "\\lt"], symDelim.text)) { symDelim.text = "⟨"; } - if (utils.contains([">", "\\gt"], symDelim.text)) { symDelim.text = "⟩"; } - if (symDelim.text === "/") { symDelim.text = "\u2215"; } - if (symDelim.text === "\\backslash") { symDelim.text = "\u2216"; } - return symDelim; - } else if (symDelim) { - throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim); - } else { - throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim); - } - } - - defineFunction({ - type: "delimsizing", - names: [ - "\\bigl", - "\\Bigl", - "\\biggl", - "\\Biggl", - "\\bigr", - "\\Bigr", - "\\biggr", - "\\Biggr", - "\\bigm", - "\\Bigm", - "\\biggm", - "\\Biggm", - "\\big", - "\\Big", - "\\bigg", - "\\Bigg" - ], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - return { - type: "delimsizing", - mode: context.parser.mode, - size: delimiterSizes[context.funcName].size, - mclass: delimiterSizes[context.funcName].mclass, - delim: delim.text - }; - }, - mathmlBuilder: (group) => { - const children = []; - - if (group.delim === ".") { group.delim = ""; } - children.push(makeText(group.delim, group.mode)); - - const node = new mathMLTree.MathNode("mo", children); - - if (group.mclass === "mopen" || group.mclass === "mclose") { - // Only some of the delimsizing functions act as fences, and they - // return "mopen" or "mclose" mclass. - node.setAttribute("fence", "true"); - } else { - // Explicitly disable fencing if it's not a fence, to override the - // defaults. - node.setAttribute("fence", "false"); - } - if (group.delim === "\u2216") { - // \backslash is not in the operator dictionary, - // so we have to explicitly set stretchy to true. - node.setAttribute("stretchy", "true"); - } - - node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox. - node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em"); - node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em"); - - return node; - } - }); - - function assertParsed(group) { - if (!group.body) { - throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); - } - } - - defineFunction({ - type: "leftright-right", - names: ["\\right"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - // \left case below triggers parsing of \right in - // `const right = parser.parseFunction();` - // uses this return value. - const color = context.parser.gullet.macros.get("\\current@color"); - if (color && typeof color !== "string") { - throw new ParseError("\\current@color set to non-string in \\right"); - } - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text, - color // undefined if not set via \color - }; - } - }); - - defineFunction({ - type: "leftright", - names: ["\\left"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - const parser = context.parser; - // Parse out the implicit body - ++parser.leftrightDepth; - // parseExpression stops before '\\right' - const body = parser.parseExpression(false); - --parser.leftrightDepth; - // Check the next token - parser.expect("\\right", false); - const right = assertNodeType(parser.parseFunction(), "leftright-right"); - return { - type: "leftright", - mode: parser.mode, - body, - left: delim.text, - right: right.delim, - rightColor: right.color - }; - }, - mathmlBuilder: (group, style) => { - assertParsed(group); - const inner = buildExpression(group.body, style); - - if (group.left === ".") { group.left = ""; } - const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]); - leftNode.setAttribute("fence", "true"); - leftNode.setAttribute("form", "prefix"); - if (group.left === "\u2216") { leftNode.setAttribute("stretchy", "true"); } - inner.unshift(leftNode); - - if (group.right === ".") { group.right = ""; } - const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]); - rightNode.setAttribute("fence", "true"); - rightNode.setAttribute("form", "postfix"); - if (group.right === "\u2216") { rightNode.setAttribute("stretchy", "true"); } - if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor); } - inner.push(rightNode); - - return makeRow(inner); - } - }); - - defineFunction({ - type: "middle", - names: ["\\middle"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - if (!context.parser.leftrightDepth) { - throw new ParseError("\\middle without preceding \\left", delim); - } - - return { - type: "middle", - mode: context.parser.mode, - delim: delim.text - }; - }, - mathmlBuilder: (group, style) => { - const textNode = makeText(group.delim, group.mode); - const middleNode = new mathMLTree.MathNode("mo", [textNode]); - middleNode.setAttribute("fence", "true"); - // MathML gives 5/18em spacing to each element. - // \middle should get delimiter spacing instead. - middleNode.setAttribute("lspace", "0.05em"); - middleNode.setAttribute("rspace", "0.05em"); - return middleNode; - } - }); - - const mathmlBuilder$8 = (group, style) => { - const node = new mathMLTree.MathNode( - group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", - [buildGroup$1(group.body, style)] - ); - switch (group.label) { - case "\\cancel": - node.setAttribute("notation", "updiagonalstrike"); - break; - case "\\bcancel": - node.setAttribute("notation", "downdiagonalstrike"); - break; - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break; - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break; - case "\\sout": - node.setAttribute("notation", "horizontalstrike"); - break; - case "\\fbox": - node.setAttribute("notation", "box"); - break; - case "\\angl": - node.setAttribute("notation", "actuarial"); - break; - case "\\fcolorbox": - case "\\colorbox": { - // doesn't have a good notation option for \colorbox. - // So use instead. Set some attributes that come - // included with . - const fboxsep = 3; // 3 pt from LaTeX source2e - node.setAttribute("width", `+${2 * fboxsep}pt`); - node.setAttribute("height", `+${2 * fboxsep}pt`); - node.setAttribute("lspace", `${fboxsep}pt`); // - node.setAttribute("voffset", `${fboxsep}pt`); - if (group.label === "\\fcolorbox") { - node.setAttribute("style", "border: 0.06em solid " + String(group.borderColor)); - } - break; - } - case "\\xcancel": - node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); - break; - } - if (group.backgroundColor) { - node.setAttribute("mathbackground", group.backgroundColor); - } - return node; - }; - - defineFunction({ - type: "enclose", - names: ["\\colorbox"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - const body = args[1]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor: color, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 - }); - - defineFunction({ - type: "enclose", - names: ["\\fcolorbox"], - props: { - numArgs: 3, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let borderColor = ""; - let backgroundColor; - if (model) { - const borderSpec = assertNodeType(args[0], "raw").string; - const backgroundSpec = assertNodeType(args[0], "raw").string; - borderColor = colorFromSpec(model, borderSpec); - backgroundColor = colorFromSpec(model, backgroundSpec); - } else { - borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros); - } - const body = args[2]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor, - borderColor, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 - }); - - defineFunction({ - type: "enclose", - names: ["\\fbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "enclose", - mode: parser.mode, - label: "\\fbox", - body: args[0] - }; - } - }); - - defineFunction({ - type: "enclose", - names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\angl", "\\phase", "\\longdiv"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 - }); - - /** - * All registered environments. - * `environments.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `environments.js`. - */ - const _environments = {}; - - function defineEnvironment({ type, names, props, handler, mathmlBuilder }) { - // Set default values of environments. - const data = { - type, - numArgs: props.numArgs || 0, - allowedInText: false, - numOptionalArgs: 0, - handler - }; - for (let i = 0; i < names.length; ++i) { - _environments[names[i]] = data; - } - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } - } - - // In TeX, there are actually three sets of dimensions, one for each of - - // Math style is not quite the same thing as script level. - const StyleLevel = { - DISPLAY: 0, - TEXT: 1, - SCRIPT: 2, - SCRIPTSCRIPT: 3 - }; - - // Helper functions - function getHLines(parser) { - // Return an array. The array length = number of hlines. - // Each element in the array tells if the line is dashed. - const hlineInfo = []; - parser.consumeSpaces(); - let nxt = parser.fetch().text; - while (nxt === "\\hline" || nxt === "\\hdashline") { - parser.consume(); - hlineInfo.push(nxt === "\\hdashline"); - parser.consumeSpaces(); - nxt = parser.fetch().text; - } - return hlineInfo; - } - - const validateAmsEnvironmentContext = context => { - const settings = context.parser.settings; - if (!settings.displayMode) { - throw new ParseError(`{${context.envName}} can be used only in display mode.`); - } - }; - - const getTag = (group, style, rowNum) => { - let tag; - const tagContents = group.tags.shift(); - if (tagContents) { - // The author has written a \tag or a \notag in this row. - if (tagContents.body) { - tag = buildExpressionRow(tagContents.body, style); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } - } else if (group.colSeparationType === "multline" && - ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) { - // A multiline that does not receive a tag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a post-processor. - tag = new mathMLTree.MathNode("mtext", [], ["tml-eqn"]); - } - if (!group.preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - if (!group.leqno) { tag.setAttribute("lspace", "-1width"); } - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!group.preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - return tag - }; - - /** - * Parse the body of the environment, with rows delimited by \\ and - * columns delimited by &, and create a nested list in row-major order - * with one group per cell. If given an optional argument scriptLevel - * ("text", "display", etc.), then each cell is cast into that scriptLevel. - */ - function parseArray( - parser, - { - hskipBeforeAndAfter, // boolean - addJot, // boolean - cols, // [{ type: string , align: l|c|r|null }] - arraystretch, // number - colSeparationType, // "align" | "alignat" | "gather" | "small" | "CD" | "multline" - addEqnNum, // boolean - singleRow, // boolean - emptySingleRow, // boolean - maxNumCols, // number - leqno // boolean - }, - scriptLevel - ) { - parser.gullet.beginGroup(); - if (!singleRow) { - // \cr is equivalent to \\ without the optional size argument (see below) - // TODO: provide helpful error when \cr is used outside array environment - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - } - if (addEqnNum) { - parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // Get current arraystretch if it's not set by the environment - if (arraystretch === undefined || Number.isNaN(arraystretch)) { - const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); - if (stretch == null) { - // Default \arraystretch from lttab.dtx - arraystretch = 1; - } else { - arraystretch = parseFloat(stretch); - if (!arraystretch || arraystretch < 0) { - throw new ParseError(`Invalid \\arraystretch: ${stretch}`); - } - } - } - - // Start group for first cell - parser.gullet.beginGroup(); - - let row = []; - const body = [row]; - const rowGaps = []; - const tags = []; - let rowTag; - const hLinesBeforeRow = []; - - // Test for \hline at the top of the array. - hLinesBeforeRow.push(getHLines(parser)); - - // eslint-disable-next-line no-constant-condition - while (true) { - // Parse each cell in its own group (namespace) - let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\"); - - if (addEqnNum && !rowTag) { - // Check if the author wrote a \tag{} inside this cell. - for (let i = 0; i < cell.length; i++) { - if (cell[i].type === "envTag" || cell[i].type === "noTag") { - // Get the contents of the \text{} nested inside the \env@Tag{} - rowTag = cell[i].type === "envTag" - ? cell.splice(i, 1)[0].body.body[0] - : { body: null }; - break - } - } - } - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - - cell = { - type: "ordgroup", - mode: parser.mode, - body: cell - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (colSeparationType === "split") { - throw new ParseError("The split environment accepts no more than two columns", - parser.nextToken); - } else if (colSeparationType === "array") { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else { - throw new ParseError("The equation environment accepts only one column", - parser.nextToken) - } - } - parser.consume(); - } else if (next === "\\end") { - // Arrays terminate newlines with `\crcr` which consumes a `\cr` if - // the last line is empty. However, AMS environments keep the - // empty row if it's the only one. - // NOTE: Currently, `cell` is the last item added into `row`. - if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) { - body.pop(); - } - if (hLinesBeforeRow.length < body.length + 1) { - hLinesBeforeRow.push([]); - } - break; - } else if (next === "\\\\") { - parser.consume(); - let size; - // \def\Let@{\let\\\math@cr} - // \def\math@cr{...\math@cr@} - // \def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}} - // \def\math@cr@@[#1]{...\math@cr@@@...} - // \def\math@cr@@@{\cr} - if (parser.gullet.future().text !== " ") { - size = parser.parseSizeGroup(true); - } - rowGaps.push(size ? size.value : null); - - tags.push(rowTag); - - // check for \hline(s) following the row separator - hLinesBeforeRow.push(getHLines(parser)); - - row = []; - rowTag = null; - body.push(row); - } else { - throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); - } - } - - // End cell group - parser.gullet.endGroup(); - // End array group defining \cr - parser.gullet.endGroup(); - - tags.push(rowTag); - - return { - type: "array", - mode: parser.mode, - addJot, - arraystretch, - body, - cols, - rowGaps, - hskipBeforeAndAfter, - hLinesBeforeRow, - colSeparationType, - addEqnNum, - scriptLevel, - tags, - leqno, - preventTagLap: parser.settings.preventTagLap - }; - } - - // Decides on a scriptLevel for cells in an array according to whether the given - // environment name starts with the letter 'd'. - function dCellStyle(envName) { - return envName.slice(0, 1) === "d" ? "display" : "text" - } - - const alignMap = { - c: "center ", - l: "left ", - r: "right " - }; - - const mathmlBuilder$7 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - let glue; - if (group.addEqnNum) { - glue = new mathMLTree.MathNode("mtd", [], []); - const glueStyle = "padding: 0;width: " + - (group.colSeparationType === "multline" ? "7.5%" : "50%"); - glue.setAttribute("style", glueStyle); - } - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellStyle = group.scriptLevel === "text" - ? StyleLevel.TEXT - : group.scriptLevel === "script" - ? StyleLevel.SCRIPT - : StyleLevel.DISPLAY; - - for (let j = 0; j < rw.length; j++) { - const mtd = new mathMLTree.MathNode( - "mtd", - [buildGroup$1(rw[j], style.withLevel(cellStyle))] - ); - if (group.colSeparationType === "multline") { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue); - row.push(glue); - const tag = getTag(group, style.withLevel(cellStyle), i); - if (group.leqno) { - row.unshift(tag); - } else { - row.push(tag); - } - } - // If group.addEqnNum, insert a breadcrumb to be found by temmlPostProcess(). - tbl.push(new mathMLTree.MathNode("mtr", row, group.addEqnNum ? ["tml-tageqn"] : [] )); - } - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - // Set column alignment, row spacing, column spacing, and - // array lines by setting attributes on the table element. - - // Set the row spacing. In MathML, we specify a gap distance. - // We do not use rowGap[] because MathML automatically increases - // cell height with the height/depth of the element content. - - // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. - // We simulate this by adding (arraystretch - 1)em to the gap. This - // does a reasonable job of adjusting arrays containing 1 em tall content. - - // The 0.16 and 0.09 values are found emprically. They produce an array - // similar to LaTeX and in which content does not interfere with \hines. - const gap = - group.arraystretch === 0 - ? 0 // {subarray} - : group.arraystretch === 0.5 - ? 0.1 // {smallmatrix} - : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); - table.setAttribute("rowspacing", utils.round(gap) + "em"); - - if (group.addEqnNum || group.colSeparationType === "multline") { - table.setAttribute("width", "100%"); - } - - // MathML table lines go only between cells. - // To place a line on an edge we'll use , if necessary. - let menclose = ""; - let align = ""; - - if (group.cols && group.cols.length > 0) { - // Find column alignment, column spacing, and vertical lines. - const cols = group.cols; - let columnLines = ""; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - if (cols[0].type === "separator") { - menclose += "left "; - iStart = 1; - } - if (cols[cols.length - 1].type === "separator") { - menclose += "right "; - iEnd -= 1; - } - - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - align += alignMap[cols[i].align]; - - if (prevTypeWasAlign) { - columnLines += "none "; - } - prevTypeWasAlign = true; - } else if (cols[i].type === "separator") { - // MathML accepts only single lines between cells. - // So we read only the first of consecutive separators. - if (prevTypeWasAlign) { - columnLines += cols[i].separator === "|" ? "solid " : "dashed "; - prevTypeWasAlign = false; - } - } - } - if (group.addEqnNum) { - align = "left " + align + "right "; // allow for glue cells on each side - align = group.leqno ? "left " + align : align += "right"; // eqn num cell - } - - table.setAttribute("columnalign", align.trim()); - - if (/[sd]/.test(columnLines)) { - table.setAttribute("columnlines", columnLines.trim()); - } - } - - // Set column spacing. - switch (group.colSeparationType) { - case "gather": - case "gathered": - case "alignedat": - case "alignat": - case "alignat*": - table.setAttribute("columnspacing", "0em"); - break - case "small": - table.setAttribute("columnspacing", "0.2778em"); - break - case "CD": - table.setAttribute("columnspacing", "0.5em"); - break - case "align": - case "align*": { - const cols = group.cols || []; - let spacing = group.addEqnNum ? "0em " : ""; - for (let i = 1; i < cols.length; i++) { - spacing += i % 2 ? "0em " : "1em "; - } - if (group.addEqnNum) { spacing += "0em"; } - table.setAttribute("columnspacing", spacing.trim()); - break - } - default: - table.setAttribute("columnspacing", "1em"); - } - - // Address \hline and \hdashline - let rowLines = ""; - const hlines = group.hLinesBeforeRow; - - menclose += hlines[0].length > 0 ? "top " : ""; - menclose += hlines[hlines.length - 1].length > 0 ? "bottom " : ""; - - for (let i = 1; i < hlines.length - 1; i++) { - rowLines += - hlines[i].length === 0 - ? "none " - : // MathML accepts only a single line between rows. Read one element. - hlines[i][0] - ? "dashed " - : "solid "; - } - if (/[sd]/.test(rowLines)) { - table.setAttribute("rowlines", rowLines.trim()); - } - - if (menclose !== "") { - table = new mathMLTree.MathNode("menclose", [table]); - table.setAttribute("notation", menclose.trim()); - } - - if (!Number.isNaN(group.arraystretch) && group.arraystretch < 1) { - // A small array. Wrap in scriptstyle so row gap is not too large. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table; - }; - - // Convenience function for align, align*, aligned, alignat, alignat*, alignedat. - const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addJot: true, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - colSeparationType: context.envName, - maxNumCols: context.envName === "split" ? 2 : undefined, - leqno: context.parser.settings.leqno - }, - "display" - ); - - // Determining number of columns. - // 1. If the first argument is given, we use it as a number of columns, - // and makes sure that each row doesn't exceed that number. - // 2. Otherwise, just count number of columns = maximum number - // of cells in each row ("aligned" mode -- isAligned will be true). - // - // At the same time, prepend empty group {} at beginning of every second - // cell in each row (starting with second cell) so that operators become - // binary. This behavior is implemented in amsmath's \start@aligned. - let numMaths; - let numCols = 0; - if (args[0] && args[0].type === "ordgroup") { - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - const isAligned = !numCols; - res.body.forEach(function(row) { - if (!isAligned) { - // Case 1 - const curMaths = row.length / 2; - if (numMaths < curMaths) { - throw new ParseError( - "Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, - row[0] - ); - } - } else if (numCols < row.length) { - // Case 2 - numCols = row.length; - } - }); - - // Adjusting alignment. - // In aligned mode, we add one \qquad between columns; - // otherwise we add nothing. - for (let i = 0; i < numCols; ++i) { - let align = "r"; - if (i % 2 === 1) { - align = "l"; - } - cols[i] = { - type: "align", - align: align - }; - } - res.colSeparationType = isAligned ? "align" : "alignat"; - return res; - }; - - // Arrays are part of LaTeX, defined in lttab.dtx so its documentation - // is part of the source2e.pdf file of LaTeX2e source documentation. - // {darray} is an {array} environment where cells are set in \displaystyle, - // as defined in nccmath.sty. - defineEnvironment({ - type: "array", - names: ["array", "darray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Since no types are specified above, the two possibilities are - // - The argument is wrapped in {} or [], in which case Parser's - // parseGroup() returns an "ordgroup" wrapping some symbol node. - // - The argument is a bare symbol node. - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - if ("lcr".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } else if (ca === "|") { - return { - type: "separator", - separator: "|" - }; - } else if (ca === ":") { - return { - type: "separator", - separator: ":" - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - const res = { - cols, - colSeparationType: "array", - hskipBeforeAndAfter: true, // \@preamble in lttab.dtx - maxNumCols: cols.length - }; - return parseArray(context.parser, res, dCellStyle(context.envName)); - }, - mathmlBuilder: mathmlBuilder$7 - }); - - // The matrix environments of amsmath builds on the array environment - // of LaTeX, which is discussed above. - // The mathtools package adds starred versions of the same environments. - // These have an optional argument to choose left|center|right justification. - defineEnvironment({ - type: "array", - names: [ - "matrix", - "pmatrix", - "bmatrix", - "Bmatrix", - "vmatrix", - "Vmatrix", - "matrix*", - "pmatrix*", - "bmatrix*", - "Bmatrix*", - "vmatrix*", - "Vmatrix*" - ], - props: { - numArgs: 0 - }, - handler(context) { - const delimiters = { - matrix: null, - pmatrix: ["(", ")"], - bmatrix: ["[", "]"], - Bmatrix: ["\\{", "\\}"], - vmatrix: ["|", "|"], - Vmatrix: ["\\Vert", "\\Vert"] - }[context.envName.replace("*", "")]; - // \hskip -\arraycolsep in amsmath - let colAlign = "c"; - const payload = { - hskipBeforeAndAfter: false, - colSeparationType: "matrix", - cols: [{ type: "align", align: colAlign }] - }; - if (context.envName.charAt(context.envName.length - 1) === "*") { - // It's one of the mathtools starred functions. - // Parse the optional alignment argument. - const parser = context.parser; - parser.consumeSpaces(); - if (parser.fetch().text === "[") { - parser.consume(); - parser.consumeSpaces(); - colAlign = parser.fetch().text; - if ("lcr".indexOf(colAlign) === -1) { - throw new ParseError("Expected l or c or r", parser.nextToken); - } - parser.consume(); - parser.consumeSpaces(); - parser.expect("]"); - parser.consume(); - payload.cols = [{ type: "align", align: colAlign }]; - } - } - const res = parseArray(context.parser, payload, "text"); - // Populate cols with the correct number of column alignment specs. - const numCols = Math.max(0, ...res.body.map((row) => row.length)); - res.cols = new Array(numCols).fill({ type: "align", align: colAlign }); - return delimiters - ? { - type: "leftright", - mode: context.mode, - body: [res], - left: delimiters[0], - right: delimiters[1], - rightColor: undefined // \right uninfluenced by \color in array - } - : res; - }, - mathmlBuilder: mathmlBuilder$7 - }); - - defineEnvironment({ - type: "array", - names: ["smallmatrix"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { arraystretch: 0.5 }; - const res = parseArray(context.parser, payload, "script"); - res.colSeparationType = "small"; - return res; - }, - mathmlBuilder: mathmlBuilder$7 - }); - - defineEnvironment({ - type: "array", - names: ["subarray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Parsing of {subarray} is similar to {array} - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - // {subarray} only recognizes "l" & "c" - if ("lc".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - if (cols.length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - let res = { - cols, - hskipBeforeAndAfter: false, - colSeparationType: "array", - arraystretch: 0 - }; - res = parseArray(context.parser, res, "script"); - if (res.body.length > 0 && res.body[0].length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - return res; - }, - mathmlBuilder: mathmlBuilder$7 - }); - - // A cases environment (in amsmath.sty) is almost equivalent to - // \def - // \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. - // {dcases} is a {cases} environment where cells are set in \displaystyle, - // as defined in mathtools.sty. - // {rcases} is another mathtools environment. It's brace is on the right side. - defineEnvironment({ - type: "array", - names: ["cases", "dcases", "rcases", "drcases"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { - cols: [ - { - type: "align", - align: "l" - }, - { - type: "align", - align: "l" - } - ], - colSeparationType: "cases" - }; - const res = parseArray(context.parser, payload, dCellStyle(context.envName)); - return { - type: "leftright", - mode: context.mode, - body: [res], - left: context.envName.indexOf("r") > -1 ? "." : "\\{", - right: context.envName.indexOf("r") > -1 ? "\\}" : ".", - rightColor: undefined - }; - }, - mathmlBuilder: mathmlBuilder$7 - }); - - // In the align environment, one uses ampersands, &, to specify number of - // columns in each row, and to locate spacing between each column. - // align gets automatic numbering. align* and aligned do not. - // The alignedat environment can be used in math mode. - // Note that we assume \nomallineskiplimit to be zero, - // so that \strut@ is the same as \strut. - defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$7 - }); - - // A gathered environment is like an array environment with one centered - // column, but where rows are considered lines so get \jot line spacing - // and contents are set in \displaystyle. - defineEnvironment({ - type: "array", - names: ["gathered", "gather", "gather*"], - props: { - numArgs: 0 - }, - handler(context) { - if (utils.contains(["gather", "gather*"], context.envName)) { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [ - { - type: "align", - align: "c" - } - ], - addJot: true, - colSeparationType: "gather", - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 - }); - - // alignat environment is like an align environment, but one must explicitly - // specify maximum number of columns in each row, and can adjust spacing between - // each columns. - defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$7 - }); - - defineEnvironment({ - type: "array", - names: ["equation", "equation*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "equation", - emptySingleRow: true, - singleRow: true, - maxNumCols: 1, - colSeparationType: "gather", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 - }); - - defineEnvironment({ - type: "array", - names: ["multline", "multline*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "multline", - maxNumCols: 1, - colSeparationType: "multline", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 - }); - - defineEnvironment({ - type: "array", - names: ["CD"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - return parseCD(context.parser); - }, - mathmlBuilder: mathmlBuilder$7 - }); - - // Catch \hline outside array environment - defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\hline", "\\hdashline"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: true - }, - handler(context, args) { - throw new ParseError(`${context.funcName} valid only within array environment`); - } - }); - - const environments = _environments; - - // Environment delimiters. HTML/MathML rendering is defined in the corresponding - // defineEnvironment definitions. - defineFunction({ - type: "environment", - names: ["\\begin", "\\end"], - props: { - numArgs: 1, - argTypes: ["text"] - }, - handler({ parser, funcName }, args) { - const nameGroup = args[0]; - if (nameGroup.type !== "ordgroup") { - throw new ParseError("Invalid environment name", nameGroup); - } - let envName = ""; - for (let i = 0; i < nameGroup.body.length; ++i) { - envName += assertNodeType(nameGroup.body[i], "textord").text; - } - - if (funcName === "\\begin") { - // begin...end is similar to left...right - if (!Object.prototype.hasOwnProperty.call(environments, envName )) { - throw new ParseError("No such environment: " + envName, nameGroup); - } - // Build the environment object. Arguments and other information will - // be made available to the begin and end methods using properties. - const env = environments[envName]; - const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env); - const context = { - mode: parser.mode, - envName, - parser - }; - const result = env.handler(context, args, optArgs); - parser.expect("\\end", false); - const endNameToken = parser.nextToken; - const end = assertNodeType(parser.parseFunction(), "environment"); - if (end.name !== envName) { - throw new ParseError( - `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, - endNameToken - ); - } - return result; - } - - return { - type: "environment", - mode: parser.mode, - name: envName, - nameGroup - }; - } - }); - - defineFunction({ - type: "envTag", - names: ["\\env@tag"], - props: { - numArgs: 1, - argTypes: ["math"] - }, - handler({ parser }, args) { - return { - type: "envTag", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } - }); - - defineFunction({ - type: "noTag", - names: ["\\env@notag"], - props: { - numArgs: 0 - }, - handler({ parser }) { - return { - type: "noTag", - mode: parser.mode - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } - }); - - const mathmlBuilder$6 = (group, style) => { - const font = group.font; - const newStyle = style.withFont(font); - const mathGroup = buildGroup$1(group.body, newStyle); - - if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{} - if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - let canConsolidate = mathGroup.children[0].type === "mo"; - for (let i = 1; i < mathGroup.children.length; i++) { - if (mathGroup.children[i].type === "mo" && font === "boldsymbol") { - mathGroup.children[i].style.fontWeight = "bold"; - } - if (mathGroup.children[i].type !== "mi") { canConsolidate = false; } - const localVariant = mathGroup.children[i].attributes && - mathGroup.children[i].attributes.mathvariant || ""; - if (localVariant !== "normal") { canConsolidate = false; } - } - if (!canConsolidate) { return mathGroup } - // Consolidate the elements. - const mi = mathGroup.children[0]; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children.push(mathGroup.children[i].children[0]); - } - if (mathGroup.attributes.mathcolor) { mi.attributes.mathcolor = mathGroup.attributes.mathcolor; } - if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") { - // Workaround for a Firefox bug that renders spurious space around - // a - // Ref: https://bugs.webkit.org/show_bug.cgi?id=129097 - // We insert a text node that contains a zero-width space and wrap in an mrow. - // TODO: Get rid of this workaround when the Firefox bug is fixed. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - return mi - }; - - const fontAliases = { - "\\Bbb": "\\mathbb", - "\\bold": "\\mathbf", - "\\frak": "\\mathfrak", - "\\bm": "\\boldsymbol" - }; - - defineFunction({ - type: "font", - names: [ - // styles - "\\mathrm", - "\\mathit", - "\\mathbf", - "\\mathnormal", - "\\up@greek", - "\\boldsymbol", - - // families - "\\mathbb", - "\\mathcal", - "\\mathfrak", - "\\mathscr", - "\\mathsf", - "\\mathtt", - "\\oldstylenums", - - // aliases - "\\Bbb", - "\\bm", - "\\bold", - "\\frak" - ], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = normalizeArgument(args[0]); - let func = funcName; - if (func in fontAliases) { - func = fontAliases[func]; - } - return { - type: "font", - mode: parser.mode, - font: func.slice(1), - body - }; - }, - mathmlBuilder: mathmlBuilder$6 - }); - - // Old font changing functions - defineFunction({ - type: "font", - names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ parser, funcName, breakOnTokenText }, args) => { - const { mode } = parser; - const body = parser.parseExpression(true, breakOnTokenText); - const fontStyle = `math${funcName.slice(1)}`; - - return { - type: "font", - mode: mode, - font: fontStyle, - body: { - type: "ordgroup", - mode: parser.mode, - body - } - }; - }, - mathmlBuilder: mathmlBuilder$6 - }); - - const stylArray = ["display", "text", "script", "scriptscript"]; - const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 }; - - const mathmlBuilder$5 = (group, style) => { - // Track the scriptLevel of the numerator and denominator. - // We may need that info for \mathchoice or for adjusting em dimensions. - const childOptions = group.scriptLevel === "auto" - ? style.incrementLevel() - : group.scriptLevel === "display" - ? style.withLevel(StyleLevel.TEXT) - : group.scriptLevel === "text" - ? style.withLevel(StyleLevel.SCRIPT) - : style.withLevel(StyleLevel.SCRIPTSCRIPT); - - let node = new mathMLTree.MathNode("mfrac", [ - buildGroup$1(group.numer, childOptions), - buildGroup$1(group.denom, childOptions) - ]); - - if (!group.hasBarLine) { - node.setAttribute("linethickness", "0px"); - } else if (group.barSize) { - const ruleWidth = calculateSize(group.barSize, style); - node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit); - } - - if (group.leftDelim != null || group.rightDelim != null) { - const withDelims = []; - - if (group.leftDelim != null) { - const leftOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.leftDelim.replace("\\", "")) - ]); - leftOp.setAttribute("fence", "true"); - withDelims.push(leftOp); - } - - withDelims.push(node); - - if (group.rightDelim != null) { - const rightOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.rightDelim.replace("\\", "")) - ]); - rightOp.setAttribute("fence", "true"); - withDelims.push(rightOp); - } - - node = makeRow(withDelims); - } - - if (group.scriptLevel !== "auto") { - node = new mathMLTree.MathNode("mstyle", [node]); - node.setAttribute("displaystyle", String(group.scriptLevel === "display")); - node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]); - } - - return node; - }; - - defineFunction({ - type: "genfrac", - names: [ - "\\dfrac", - "\\frac", - "\\tfrac", - "\\dbinom", - "\\binom", - "\\tbinom", - "\\\\atopfrac", // can’t be entered directly - "\\\\bracefrac", - "\\\\brackfrac" // ditto - ], - props: { - numArgs: 2, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - let hasBarLine = false; - let leftDelim = null; - let rightDelim = null; - let scriptLevel = "auto"; - - switch (funcName) { - case "\\dfrac": - case "\\frac": - case "\\tfrac": - hasBarLine = true; - break; - case "\\\\atopfrac": - hasBarLine = false; - break; - case "\\dbinom": - case "\\binom": - case "\\tbinom": - leftDelim = "("; - rightDelim = ")"; - break; - case "\\\\bracefrac": - leftDelim = "\\{"; - rightDelim = "\\}"; - break; - case "\\\\brackfrac": - leftDelim = "["; - rightDelim = "]"; - break; - default: - throw new Error("Unrecognized genfrac command"); - } - - switch (funcName) { - case "\\dfrac": - case "\\dbinom": - scriptLevel = "display"; - break; - case "\\tfrac": - case "\\tbinom": - scriptLevel = "text"; - break; - } - - return { - type: "genfrac", - mode: parser.mode, - continued: false, - numer, - denom, - hasBarLine, - leftDelim, - rightDelim, - scriptLevel, - barSize: null - }; - }, - mathmlBuilder: mathmlBuilder$5 - }); - - defineFunction({ - type: "genfrac", - names: ["\\cfrac"], - props: { - numArgs: 2 - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - - return { - type: "genfrac", - mode: parser.mode, - continued: true, - numer, - denom, - hasBarLine: true, - leftDelim: null, - rightDelim: null, - scriptLevel: "display", - barSize: null - }; - } - }); - - // Infix generalized fractions -- these are not rendered directly, but replaced - // immediately by one of the variants above. - defineFunction({ - type: "infix", - names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], - props: { - numArgs: 0, - infix: true - }, - handler({ parser, funcName, token }) { - let replaceWith; - switch (funcName) { - case "\\over": - replaceWith = "\\frac"; - break; - case "\\choose": - replaceWith = "\\binom"; - break; - case "\\atop": - replaceWith = "\\\\atopfrac"; - break; - case "\\brace": - replaceWith = "\\\\bracefrac"; - break; - case "\\brack": - replaceWith = "\\\\brackfrac"; - break; - default: - throw new Error("Unrecognized infix genfrac command"); - } - return { - type: "infix", - mode: parser.mode, - replaceWith, - token - }; - } - }); - - const delimFromValue = function(delimString) { - let delim = null; - if (delimString.length > 0) { - delim = delimString; - delim = delim === "." ? null : delim; - } - return delim; - }; - - defineFunction({ - type: "genfrac", - names: ["\\genfrac"], - props: { - numArgs: 6, - allowedInArgument: true, - argTypes: ["math", "math", "size", "text", "math", "math"] - }, - handler({ parser }, args) { - const numer = args[4]; - const denom = args[5]; - - // Look into the parse nodes to get the desired delimiters. - const leftNode = normalizeArgument(args[0]); - const leftDelim = leftNode.type === "atom" && leftNode.family === "open" - ? delimFromValue(leftNode.text) - : null; - const rightNode = normalizeArgument(args[1]); - const rightDelim = - rightNode.type === "atom" && rightNode.family === "close" - ? delimFromValue(rightNode.text) - : null; - - const barNode = assertNodeType(args[2], "size"); - let hasBarLine; - let barSize = null; - if (barNode.isBlank) { - // \genfrac acts differently than \above. - // \genfrac treats an empty size group as a signal to use a - // standard bar size. \above would see size = 0 and omit the bar. - hasBarLine = true; - } else { - barSize = barNode.value; - hasBarLine = barSize.number > 0; - } - - // Find out if we want displaystyle, textstyle, etc. - let scriptLevel = "auto"; - let styl = args[3]; - if (styl.type === "ordgroup") { - if (styl.body.length > 0) { - const textOrd = assertNodeType(styl.body[0], "textord"); - scriptLevel = stylArray[Number(textOrd.text)]; - } - } else { - styl = assertNodeType(styl, "textord"); - scriptLevel = stylArray[Number(styl.text)]; - } - - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim, - rightDelim, - scriptLevel - }; - }, - mathmlBuilder: mathmlBuilder$5 - }); - - // \above is an infix fraction that also defines a fraction bar size. - defineFunction({ - type: "infix", - names: ["\\above"], - props: { - numArgs: 1, - argTypes: ["size"], - infix: true - }, - handler({ parser, funcName, token }, args) { - return { - type: "infix", - mode: parser.mode, - replaceWith: "\\\\abovefrac", - barSize: assertNodeType(args[0], "size").value, - token - }; - } - }); - - defineFunction({ - type: "genfrac", - names: ["\\\\abovefrac"], - props: { - numArgs: 3, - argTypes: ["math", "size", "math"] - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const barSize = assert(assertNodeType(args[1], "infix").barSize); - const denom = args[2]; - - const hasBarLine = barSize.number > 0; - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim: null, - rightDelim: null, - scriptLevel: "auto" - }; - }, - - mathmlBuilder: mathmlBuilder$5 - }); - - const mathmlBuilder$4 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - }; - - // Horizontal stretchy braces - defineFunction({ - type: "horizBrace", - names: ["\\overbrace", "\\underbrace"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "horizBrace", - mode: parser.mode, - label: funcName, - isOver: /^\\over/.test(funcName), - base: args[0] - }; - }, - mathmlBuilder: mathmlBuilder$4 - }); - - defineFunction({ - type: "href", - names: ["\\href"], - props: { - numArgs: 2, - argTypes: ["url", "original"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const body = args[1]; - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\href", - url: href - }) - ) { - throw new ParseError(`Function "\\href" is not trusted`, token) - } - - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - let math = buildExpressionRow(group.body, style); - if (!(math instanceof MathNode)) { - math = new MathNode("mrow", [math]); - } - math.setAttribute("href", group.href); - return math; - } - }); - - defineFunction({ - type: "href", - names: ["\\url"], - props: { - numArgs: 1, - argTypes: ["url"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\url", - url: href - }) - ) { - throw new ParseError(`Function "\\url" is not trusted`, token) - } - - const chars = []; - for (let i = 0; i < href.length; i++) { - let c = href[i]; - if (c === "~") { - c = "\\textasciitilde"; - } - chars.push({ - type: "textord", - mode: "text", - text: c - }); - } - const body = { - type: "text", - mode: parser.mode, - font: "\\texttt", - body: chars - }; - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - } - }); - - defineFunction({ - type: "html", - names: ["\\class", "\\id", "\\style", "\\data"], - props: { - numArgs: 2, - argTypes: ["raw", "original"], - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - const value = assertNodeType(args[0], "raw").string; - const body = args[1]; - - if (parser.settings.strict) { - throw new ParseError(`Function "${funcName}" is disabled in strict mode`, token) - } - - let trustContext; - const attributes = {}; - - switch (funcName) { - case "\\class": - attributes.class = value; - trustContext = { - command: "\\class", - class: value - }; - break; - case "\\id": - attributes.id = value; - trustContext = { - command: "\\id", - id: value - }; - break; - case "\\style": - attributes.style = value; - trustContext = { - command: "\\style", - style: value - }; - break; - case "\\data": { - const data = value.split(","); - for (let i = 0; i < data.length; i++) { - const keyVal = data[i].split("="); - if (keyVal.length !== 2) { - throw new ParseError("Error parsing key-value for \\data"); - } - attributes["data-" + keyVal[0].trim()] = keyVal[1].trim(); - } - - trustContext = { - command: "\\data", - attributes - }; - break; - } - default: - throw new Error("Unrecognized html command"); - } - - if (!parser.settings.isTrusted(trustContext)) { - throw new ParseError(`Function "${funcName}" is not trusted`, token) - } - return { - type: "html", - mode: parser.mode, - attributes, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const element = buildExpressionRow(group.body, style); - - const classes = []; - if (group.attributes.class) { - classes.push(...group.attributes.class.trim().split(/\s+/)); - } - element.classes = classes; - - for (const attr in group.attributes) { - if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) { - element.setAttribute(attr, group.attributes[attr]); - } - } - - return element; - } - }); - - const sizeData = function(str) { - if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { - // str is a number with no unit specified. - // default unit is bp, per graphix package. - return { number: +str, unit: "bp" } - } else { - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); - if (!match) { - throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); - } - return data - } - }; - - defineFunction({ - type: "includegraphics", - names: ["\\includegraphics"], - props: { - numArgs: 1, - numOptionalArgs: 1, - argTypes: ["raw", "url"], - allowedInText: false - }, - handler: ({ parser, token }, args, optArgs) => { - let width = { number: 0, unit: "em" }; - let height = { number: 0.9, unit: "em" }; // sorta character sized. - let totalheight = { number: 0, unit: "em" }; - let alt = ""; - - if (optArgs[0]) { - const attributeStr = assertNodeType(optArgs[0], "raw").string; - - // Parser.js does not parse key/value pairs. We get a string. - const attributes = attributeStr.split(","); - for (let i = 0; i < attributes.length; i++) { - const keyVal = attributes[i].split("="); - if (keyVal.length === 2) { - const str = keyVal[1].trim(); - switch (keyVal[0].trim()) { - case "alt": - alt = str; - break - case "width": - width = sizeData(str); - break - case "height": - height = sizeData(str); - break - case "totalheight": - totalheight = sizeData(str); - break - default: - throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics.") - } - } - } - } - - const src = assertNodeType(args[0], "url").url; - - if (alt === "") { - // No alt given. Use the file name. Strip away the path. - alt = src; - alt = alt.replace(/^.*[\\/]/, ""); - alt = alt.substring(0, alt.lastIndexOf(".")); - } - - if ( - !parser.settings.isTrusted({ - command: "\\includegraphics", - url: src - }) - ) { - throw new ParseError(`Function "\\includegraphics" is not trusted`, token) - } - - return { - type: "includegraphics", - mode: parser.mode, - alt: alt, - width: width, - height: height, - totalheight: totalheight, - src: src - } - }, - mathmlBuilder: (group, style) => { - const height = calculateSize(group.height, style); - const depth = { number: 0, unit: "em" }; - - if (group.totalheight.number > 0) { - if (group.totalheight.unit === height.unit && - group.totalheight.number > height.number) { - depth.number = group.totalheight.number - height.number; - depth.unit = height.unit; - } - } - - let width = 0; - if (group.width.number > 0) { - width = calculateSize(group.width, style); - } - - const graphicStyle = { height: height.number + depth.number + "em" }; - if (width.number > 0) { - graphicStyle.width = width.number + width.unit; - } - if (depth.number > 0) { - graphicStyle.verticalAlign = -depth.number + depth.unit; - } - - const node = new Img(group.src, group.alt, graphicStyle); - node.height = height; - node.depth = depth; - return new mathMLTree.MathNode("mtext", [node]) - } - }); - - // Horizontal spacing commands - - // TODO: \hskip and \mskip should support plus and minus in lengths - - defineFunction({ - type: "kern", - names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], - props: { - numArgs: 1, - argTypes: ["size"], - primitive: true, - allowedInText: true - }, - handler({ parser, funcName, token }, args) { - const size = assertNodeType(args[0], "size"); - if (parser.settings.strict) { - const mathFunction = funcName[1] === "m"; // \mkern, \mskip - const muUnit = size.value.unit === "mu"; - if (mathFunction) { - if (!muUnit) { - throw new ParseError(`LaTeX's ${funcName} supports only mu units, ` + - `not ${size.value.unit} units`, token) - } - if (parser.mode !== "math") { - throw new ParseError(`LaTeX's ${funcName} works only in math mode`, token) - } - } else { - // !mathFunction - if (muUnit) { - throw new ParseError(`LaTeX's ${funcName} doesn't support mu units`, token) - } - } - } - return { - type: "kern", - mode: parser.mode, - dimension: size.value - }; - }, - mathmlBuilder(group, style) { - const dimension = calculateSize(group.dimension, style); - const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : ""; - if (group.mode === "text" && ch.length > 0) { - const character = new mathMLTree.TextNode(ch); - return new mathMLTree.MathNode("mtext", [character]); - } else { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", dimension.number + dimension.unit); - return node; - } - } - }); - - const spaceCharacter = function(width) { - if (width >= 0.05555 && width <= 0.05556) { - return "\u200a"; //   - } else if (width >= 0.1666 && width <= 0.1667) { - return "\u2009"; //   - } else if (width >= 0.2222 && width <= 0.2223) { - return "\u2005"; //   - } else if (width >= 0.2777 && width <= 0.2778) { - return "\u2005\u200a"; //    - } else { - return ""; - } - }; - - // Limit valid characters to a small set, for safety. - const invalidIdRegEx = /[^A-Za-z_0-9-]/g; - - defineFunction({ - type: "label", - names: ["\\label"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser }, args) { - return { - type: "label", - mode: parser.mode, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Return a no-width, no-ink element with an HTML id. - const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]); - if (group.string.length > 0) { - node.setAttribute("id", group.string); - } - return node - } - }); - - // Horizontal overlap functions - - const textModeLap = ["\\clap", "\\llap", "\\rlap"]; - - defineFunction({ - type: "lap", - names: ["\\mathllap", "\\mathrlap", "\\mathclap", "\\clap", "\\llap", "\\rlap"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - if (textModeLap.includes(funcName)) { - if (parser.settings.strict && parser.mode !== "text") { - throw new ParseError(`{${funcName}} can be used only in text mode. - Try \\math${funcName.slice(1)}`, token) - } - funcName = funcName.slice(1); - } else { - funcName = funcName.slice(5); - } - const body = args[0]; - return { - type: "lap", - mode: parser.mode, - alignment: funcName, - body - } - }, - mathmlBuilder: (group, style) => { - // mathllap, mathrlap, mathclap - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, style)]); - - if (group.alignment === "rlap") { - if (group.body.body.length > 0 && group.body.body[0].type === "genfrac") { - // In Firefox, a squashes the 3/18em padding of a child \frac. Put it back. - node.setAttribute("lspace", "0.16667em"); - } - } else { - const offset = group.alignment === "llap" ? "-1" : "-0.5"; - node.setAttribute("lspace", offset + "width"); - } - node.setAttribute("width", "0px"); - return node - } - }); - - // Switching from text mode back to math mode - defineFunction({ - type: "ordgroup", - names: ["\\(", "$"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler({ funcName, parser }, args) { - const outerMode = parser.mode; - parser.switchMode("math"); - const close = funcName === "\\(" ? "\\)" : "$"; - const body = parser.parseExpression(false, close); - parser.expect(close); - parser.switchMode(outerMode); - return { - type: "ordgroup", - mode: parser.mode, - body - }; - } - }); - - // Check for extra closing math delimiters - defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\)", "\\]"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler(context, token) { - throw new ParseError(`Mismatched ${context.funcName}`, token); - } - }); - - const chooseStyle = (group, style) => { - switch (style.level) { - case StyleLevel.DISPLAY: // 0 - return group.display; - case StyleLevel.TEXT: // 1 - return group.text; - case StyleLevel.SCRIPT: // 2 - return group.script; - case StyleLevel.SCRIPTSCRIPT: // 3 - return group.scriptscript; - default: - return group.text; - } - }; - - defineFunction({ - type: "mathchoice", - names: ["\\mathchoice"], - props: { - numArgs: 4, - primitive: true - }, - handler: ({ parser }, args) => { - return { - type: "mathchoice", - mode: parser.mode, - display: ordargument(args[0]), - text: ordargument(args[1]), - script: ordargument(args[2]), - scriptscript: ordargument(args[3]) - }; - }, - mathmlBuilder: (group, style) => { - const body = chooseStyle(group, style); - return buildExpressionRow(body, style); - } - }); - - const textAtomTypes = ["text", "textord", "mathord", "atom"]; - - function mathmlBuilder$3(group, style) { - let node; - const inner = buildExpression(group.body, style); - - if (group.mclass === "minner") { - node = new mathMLTree.MathNode("mpadded", inner); - } else if (group.mclass === "mord") { - if (group.isCharacterBox || inner[0].type === "mathord") { - node = inner[0]; - node.type = "mi"; - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - if (group.mustPromote) { - node = inner[0]; - node.type = "mo"; - if (group.isCharacterBox && group.body[0].text && /[A-Za-z]/.test(group.body[0].text)) { - node.setAttribute("mathvariant", "italic"); - } - } else { - node = new mathMLTree.MathNode("mo", inner); - } - - // Set spacing based on what is the most likely adjacent atom type. - // See TeXbook p170. - const doSpacing = style.level < 2; // Operator spacing is zero inside a (sub|super)script. - if (group.mclass === "mbin") { - // medium space - node.attributes.lspace = (doSpacing ? "0.2222em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2222em" : "0"); - } else if (group.mclass === "mrel") { - // thickspace - node.attributes.lspace = (doSpacing ? "0.2778em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2778em" : "0"); - } else if (group.mclass === "mpunct") { - node.attributes.lspace = "0em"; - node.attributes.rspace = (doSpacing ? "0.1667em" : "0"); - } else if (group.mclass === "mopen" || group.mclass === "mclose") { - node.attributes.lspace = "0em"; - node.attributes.rspace = "0em"; - } else if (group.mclass === "minner" && doSpacing) { - node.attributes.lspace = "0.0556em"; // 1 mu is the most likely option - node.attributes.width = "+0.1111em"; - } - if (!(group.mclass === "mopen" || group.mclass === "mclose")) { - delete node.attributes.stretchy; - delete node.attributes.form; - } - } - return node; - } - - // Math class commands except \mathop - defineFunction({ - type: "mclass", - names: [ - "\\mathord", - "\\mathbin", - "\\mathrel", - "\\mathopen", - "\\mathclose", - "\\mathpunct", - "\\mathinner" - ], - props: { - numArgs: 1, - primitive: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - const isCharacterBox = utils.isCharacterBox(body); - // We should not wrap a around a or . That would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - let mustPromote = true; - const mord = { type: "mathord", text: "", mode: parser.mode }; - const arr = (body.body) ? body.body : [body]; - for (const arg of arr) { - if (textAtomTypes.includes(arg.type)) { - if (arg.text) { - mord.text += arg.text; - } else if (arg.body) { - arg.body.map(e => { mord.text += e.text; }); - } - } else { - mustPromote = false; - break - } - } - return { - type: "mclass", - mode: parser.mode, - mclass: "m" + funcName.slice(5), - body: ordargument(mustPromote ? mord : body), - isCharacterBox, - mustPromote - }; - }, - mathmlBuilder: mathmlBuilder$3 - }); - - const binrelClass = (arg) => { - // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. - // (by rendering separately and with {}s before and after, and measuring - // the change in spacing). We'll do roughly the same by detecting the - // atom type directly. - const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; - if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { - return "m" + atom.family; - } else { - return "mord"; - } - }; - - // \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. - // This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. - defineFunction({ - type: "mclass", - names: ["\\@binrel"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "mclass", - mode: parser.mode, - mclass: binrelClass(args[0]), - body: ordargument(args[1]), - isCharacterBox: utils.isCharacterBox(args[1]) - }; - } - }); - - // Build a relation or stacked op by placing one symbol on top of another - defineFunction({ - type: "mclass", - names: ["\\stackrel", "\\overset", "\\underset"], - props: { - numArgs: 2 - }, - handler({ parser, funcName }, args) { - const baseArg = args[1]; - const shiftedArg = args[0]; - - const baseOp = { - type: "op", - mode: baseArg.mode, - limits: true, - alwaysHandleSupSub: true, - parentIsSupSub: false, - symbol: false, - stack: true, - suppressBaseShift: funcName !== "\\stackrel", - body: ordargument(baseArg) - }; - - return { - type: "supsub", - mode: shiftedArg.mode, - base: baseOp, - sup: funcName === "\\underset" ? null : shiftedArg, - sub: funcName === "\\underset" ? shiftedArg : null - }; - }, - mathmlBuilder: mathmlBuilder$3 - }); - - // Helper function - const buildGroup = (el, style, noneNode) => { - if (!el) { return noneNode } - const node = buildGroup$1(el, style); - if (node.type === "mrow" && node.children.length === 0) { return noneNode } - return node - }; - - defineFunction({ - type: "multiscript", - names: ["\\sideset", "\\pres@cript"], // See macros.js for \prescript - props: { - numArgs: 3 - }, - handler({ parser, funcName, token }, args) { - if (args[2].body.length === 0) { - throw new ParseError(funcName + `cannot parse an empty base.`) - } - const base = args[2].body[0]; - if (parser.settings.strict && funcName === "\\sideset" && !base.symbol) { - throw new ParseError(`The base of \\sideset must be a big operator. Try \\prescript.`) - } - - if ((args[0].body.length > 0 && args[0].body[0].type !== "supsub") || - (args[1].body.length > 0 && args[1].body[0].type !== "supsub")) { - throw new ParseError("\\sideset can parse only subscripts and " + - "superscripts in its first two arguments", token) - } - - // The prescripts and postscripts come wrapped in a supsub. - const prescripts = args[0].body.length > 0 ? args[0].body[0] : null; - const postscripts = args[1].body.length > 0 ? args[1].body[0] : null; - - if (!prescripts && !postscripts) { - return base - } else if (!prescripts) { - // It's not a multi-script. Get a \textstyle supsub. - return { - type: "styling", - mode: parser.mode, - scriptLevel: "text", - body: [{ - type: "supsub", - mode: parser.mode, - base, - sup: postscripts.sup, - sub: postscripts.sub - }] - } - } else { - return { - type: "multiscript", - mode: parser.mode, - isSideset: funcName === "\\sideset", - prescripts, - postscripts, - base - } - } - }, - mathmlBuilder(group, style) { - const base = buildGroup$1(group.base, style); - - const prescriptsNode = new mathMLTree.MathNode("mprescripts"); - const noneNode = new mathMLTree.MathNode("none"); - let children = []; - - const preSub = buildGroup(group.prescripts.sub, style, noneNode); - const preSup = buildGroup(group.prescripts.sup, style, noneNode); - if (group.isSideset) { - // This seems silly, but LaTeX does this. Firefox ignores it, which does not make me sad. - preSub.setAttribute("style", "text-align: left;"); - preSup.setAttribute("style", "text-align: left;"); - } - - if (group.postscripts) { - const postSub = buildGroup(group.postscripts.sub, style, noneNode); - const postSup = buildGroup(group.postscripts.sup, style, noneNode); - children = [base, postSub, postSup, prescriptsNode, preSub, preSup]; - } else { - children = [base, prescriptsNode, preSub, preSup]; - } - - return new mathMLTree.MathNode("mmultiscripts", children); - } - }); - - defineFunction({ - type: "not", - names: ["\\not"], - props: { - numArgs: 1, - primitive: true, - allowedInText: false - }, - handler({ parser }, args) { - const isCharacterBox = utils.isCharacterBox(args[0]); - let body; - if (isCharacterBox) { - body = ordargument(args[0]); - if (body[0].text.charAt(0) === "\\") { - body[0].text = symbols.math[body[0].text].replace; - } - // \u0338 is the Unicode Combining Long Solidus Overlay - body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1); - } else { - // When the argument is not a character box, TeX does an awkward, poorly placed overlay. - // We'll do the same. - const notNode = { type: "textord", mode: "math", text: "\u0338" }; - const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } }; - body = [notNode, kernNode, args[0]]; - } - return { - type: "not", - mode: parser.mode, - body, - isCharacterBox - }; - }, - mathmlBuilder(group, style) { - if (group.isCharacterBox) { - const inner = buildExpression(group.body, style); - return inner[0] - } else { - return buildExpressionRow(group.body, style, true) - } - } - }); - - // Limits, symbols - - // Some helpers - - const ordAtomTypes = ["textord", "mathord", "atom"]; - - // Most operators have a large successor symbol, but these don't. - const noSuccessor = ["\\smallint"]; - - // Math operators (e.g. \sin) need a space between these types and themselves: - const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"]; - - const dels = ["}", "\\left", "\\middle", "\\right"]; - const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)); - - // NOTE: Unlike most `builders`s, this one handles not only "op", but also - // "supsub" since some of them (like \int) can affect super/subscripting. - - const mathmlBuilder$2 = (group, style) => { - let node; - - if (group.symbol) { - // This is a symbol. Just add the symbol. - node = new MathNode("mo", [makeText(group.name, group.mode)]); - if (utils.contains(noSuccessor, group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - } else { - // This is a text operator. Add all of the characters from the operator's name. - node = new MathNode("mi", [new TextNode(group.name.slice(1))]); - - if (!group.parentIsSupSub) { - // Append an invisible . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new MathNode("mo", [makeText("\u2061", "text")]); - node = new MathNode("mpadded", [node, operator]); - const lSpace = group.needsLeadingSpace ? 0.1667 : 0; - const rSpace = group.isFollowedByDelimiter ? 0 : 0.1666; - if (group.needsLeadingSpace) { - node.setAttribute("lspace", "0.1667em"); // thin space. - } - if ((lSpace + rSpace) > 0) { - node.setAttribute("width", `+${lSpace + rSpace}em`); - } - } - } - - return node; - }; - - const singleCharBigOps = { - "\u220F": "\\prod", - "\u2210": "\\coprod", - "\u2211": "\\sum", - "\u22c0": "\\bigwedge", - "\u22c1": "\\bigvee", - "\u22c2": "\\bigcap", - "\u22c3": "\\bigcup", - "\u2a00": "\\bigodot", - "\u2a01": "\\bigoplus", - "\u2a02": "\\bigotimes", - "\u2a04": "\\biguplus", - "\u2a05": "\\bigsqcap", - "\u2a06": "\\bigsqcup" - }; - - defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\smallint", - "\u220F", - "\u2210", - "\u2211", - "\u22c0", - "\u22c1", - "\u22c2", - "\u22c3", - "\u2a00", - "\u2a01", - "\u2a02", - "\u2a04", - "\u2a06" - ], - props: { - numArgs: 0 - }, - handler: ({ parser, funcName }, args) => { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharBigOps[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: true, - stack: false, // This is true for \stackrel{}, not here. - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$2 - }); - - // Note: calling defineFunction with a type that's already been defined only - // works because the same mathmlBuilder is being used. - defineFunction({ - type: "op", - names: ["\\mathop"], - props: { - numArgs: 1, - primitive: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - // It would be convienient to just wrap a around the argument. - // But if the argument is a or , that would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - const arr = (body.body) ? body.body : [body]; - const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type); - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: isSymbol, - stack: false, - name: isSymbol ? arr[0].text : null, - body: isSymbol ? null : ordargument(body) - }; - }, - mathmlBuilder: mathmlBuilder$2 - }); - - // There are 2 flags for operators; whether they produce limits in - // displaystyle, and whether they are symbols and should grow in - // displaystyle. These four groups cover the four possible choices. - - const singleCharIntegrals = { - "\u222b": "\\int", - "\u222c": "\\iint", - "\u222d": "\\iiint", - "\u222e": "\\oint", - "\u222f": "\\oiint", - "\u2230": "\\oiiint", - "\u2231": "\\intclockwise", - "\u2232": "\\varointclockwise", - "\u2a0c": "\\iiiint", - "\u2a0d": "\\intbar", - "\u2a0e": "\\intBar", - "\u2a0f": "\\fint", - "\u2a12": "\\rppolint", - "\u2a13": "\\scpolint", - "\u2a15": "\\pointint", - "\u2a16": "\\sqint", - "\u2a17": "\\intlarhk", - "\u2a18": "\\intx", - "\u2a19": "\\intcap", - "\u2a1a": "\\intcup" - }; - - // No limits, not symbols - defineFunction({ - type: "op", - names: [ - "\\arcsin", - "\\arccos", - "\\arctan", - "\\arctg", - "\\arcctg", - "\\arg", - "\\ch", - "\\cos", - "\\cosec", - "\\cosh", - "\\cot", - "\\cotg", - "\\coth", - "\\csc", - "\\ctg", - "\\cth", - "\\deg", - "\\dim", - "\\exp", - "\\hom", - "\\ker", - "\\lg", - "\\ln", - "\\log", - "\\sec", - "\\sin", - "\\sinh", - "\\sh", - "\\sgn", - "\\tan", - "\\tanh", - "\\tg", - "\\th" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - const next = parser.gullet.future().text; - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$2 - }); - - // Limits, not symbols - defineFunction({ - type: "op", - names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - const next = parser.gullet.future().text; - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$2 - }); - - // No limits, symbols - defineFunction({ - type: "op", - names: [ - "\\int", - "\\iint", - "\\iiint", - "\\iiiint", - "\\oint", - "\\oiint", - "\\oiiint", - "\\intclockwise", - "\\varointclockwise", - "\\intbar", - "\\intBar", - "\\fint", - "\\rppolint", - "\\scpolint", - "\\pointint", - "\\sqint", - "\\intlarhk", - "\\intx", - "\\intcap", - "\\intcup", - "\u222b", - "\u222c", - "\u222d", - "\u222e", - "\u222f", - "\u2230", - "\u2231", - "\u2232", - "\u2a0c", - "\u2a0d", - "\u2a0e", - "\u2a0f", - "\u2a12", - "\u2a13", - "\u2a15", - "\u2a16", - "\u2a17", - "\u2a18", - "\u2a19", - "\u2a1a" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharIntegrals[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: true, - stack: false, - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$2 - }); - - /** - * All registered global/built-in macros. - * `macros.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `macros.js`. - */ - const _macros = {}; - - // This function might one day accept an additional argument and do more things. - function defineMacro(name, body) { - _macros[name] = body; - } - - // NOTE: Unlike most builders, this one handles not only - // "operatorname", but also "supsub" since \operatorname* can - // affect super/subscripting. - - const mathmlBuilder$1 = (group, style) => { - let expression = buildExpression(group.body, style.withFont("mathrm")); - - // Is expression a string or has it something like a fraction? - let isAllString = true; // default - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - switch (node.type) { - case "mi": - case "mn": - case "ms": - case "mtext": - break; // Do nothing yet. - case "mspace": - { - if (node.attributes.width) { - const width = node.attributes.width.replace("em", ""); - const ch = spaceCharacter(Number(width)); - if (ch === "") { - isAllString = false; - } else { - expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)]); - } - } - } - break - case "mo": { - const child = node.children[0]; - if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { - child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); - } else { - isAllString = false; - } - break - } - default: - isAllString = false; - } - } else { - isAllString = false; - } - } - - if (isAllString) { - // Write a single TextNode instead of multiple nested tags. - const word = expression.map((node) => node.toText()).join(""); - expression = [new mathMLTree.TextNode(word)]; - } else if ( - expression.length === 1 - && utils.contains(["mover", "munder"], expression[0].type) && - (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext") - ) { - expression[0].children[0].type = "mi"; - if (group.parentIsSupSub) { - return new mathMLTree.MathNode("mrow", expression) - } else { - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - return mathMLTree.newDocumentFragment([expression[0], operator]) - } - } - - let wrapper; - if (isAllString) { - wrapper = new mathMLTree.MathNode("mi", expression); - wrapper.setAttribute("mathvariant", "normal"); - } else { - wrapper = new mathMLTree.MathNode("mrow", expression); - } - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (group.needsLeadingSpace) { - // LaTeX gives operator spacing, but a gets ord spacing. - // So add a leading space. - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - return mathMLTree.newDocumentFragment([space, wrapper, operator]) - } else { - return mathMLTree.newDocumentFragment([wrapper, operator]) - } - } - - return wrapper - }; - - // \operatorname - // amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ - defineFunction({ - type: "operatorname", - names: ["\\operatorname@", "\\operatornamewithlimits"], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = args[0]; - const prevAtomType = parser.prevAtomType; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$1 - }); - - defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - - defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, true); - } - }); - - defineFunction({ - type: "overline", - names: ["\\overline"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - const body = args[0]; - return { - type: "overline", - mode: parser.mode, - body - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005F")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode( - "mover", - [buildGroup$1(group.body, style), operator] - ); - node.setAttribute("accent", "true"); - - return node; - } - }); - - defineFunction({ - type: "phantom", - names: ["\\phantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "phantom", - mode: parser.mode, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(group.body, style); - return new mathMLTree.MathNode("mphantom", inner); - } - }); - - defineFunction({ - type: "hphantom", - names: ["\\hphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "hphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("height", "0px"); - node.setAttribute("depth", "0px"); - return node; - } - }); - - defineFunction({ - type: "vphantom", - names: ["\\vphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "vphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("width", "0px"); - return node; - } - }); - - // \pmb is a simulation of bold font. - // The version of \pmb in ambsy.sty works by typesetting three copies of the argument - // with small offsets. We use CSS text-shadow. - // It's a hack. Not as good as a real bold font. Better than nothing. - - defineFunction({ - type: "pmb", - names: ["\\pmb"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "pmb", - mode: parser.mode, - body: ordargument(args[0]) - } - }, - mathmlBuilder(group, style) { - const inner = buildExpression(group.body, style); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px"); - return node - } - }); - - const sign = num => num >= 0 ? "+" : "-"; - - // \raise, \lower, and \raisebox - - const mathmlBuilder = (group, style) => { - const newStyle = style.withLevel(StyleLevel.TEXT); - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, newStyle)]); - const dy = calculateSize(group.dy, style); - node.setAttribute("voffset", dy.number + dy.unit); - const dyAbs = Math.abs(dy.number); - node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit); - node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit); - return node - }; - - defineFunction({ - type: "raise", - names: ["\\raise", "\\lower"], - props: { - numArgs: 2, - argTypes: ["size", "primitive"], - primitive: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - if (funcName === "\\lower") { amount.number *= -1; } - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder - }); - - - defineFunction({ - type: "raise", - names: ["\\raisebox"], - props: { - numArgs: 2, - argTypes: ["size", "hbox"], - allowedInText: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder - }); - - defineFunction({ - type: "ref", - names: ["\\ref", "\\eqref"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser, funcName }, args) { - return { - type: "ref", - mode: parser.mode, - funcName, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Create an empty text node. Set a class and an href. - // The post-processor will populate with the target's tag or equation number. - const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"]; - const node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("")], classes); - node.setAttribute("href", "#" + group.string); - return node - } - }); - - defineFunction({ - type: "internal", - names: ["\\relax"], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser }) { - return { - type: "internal", - mode: parser.mode - }; - } - }); - - defineFunction({ - type: "rule", - names: ["\\rule"], - props: { - numArgs: 2, - numOptionalArgs: 1, - argTypes: ["size", "size", "size"] - }, - handler({ parser }, args, optArgs) { - const shift = optArgs[0]; - const width = assertNodeType(args[0], "size"); - const height = assertNodeType(args[1], "size"); - return { - type: "rule", - mode: parser.mode, - shift: shift && assertNodeType(shift, "size").value, - width: width.value, - height: height.value - }; - }, - mathmlBuilder(group, style) { - const width = calculateSize(group.width, style); - const height = calculateSize(group.height, style); - const shift = group.shift - ? calculateSize(group.shift, style) - : { number: 0, unit: "em" }; - const color = (style.color && style.getColor()) || "black"; - - const rule = new mathMLTree.MathNode("mspace"); - if (width.number > 0 && height.number > 0) { - rule.setAttribute("mathbackground", color); - } - rule.setAttribute("width", width.number + width.unit); - rule.setAttribute("height", height.number + height.unit); - if (shift.number === 0) { return rule } - - const wrapper = new mathMLTree.MathNode("mpadded", [rule]); - if (shift.number >= 0) { - wrapper.setAttribute("height", "+" + shift.number + shift.unit); - } else { - wrapper.setAttribute("height", shift.number + shift.unit); - wrapper.setAttribute("depth", "+" + -shift.number + shift.unit); - } - wrapper.setAttribute("voffset", shift.number + shift.unit); - return wrapper; - } - }); - - // The size mappings are taken from TeX with \normalsize=10pt. - // We don't have to track script level. MathML does that. - const sizeMap = { - "\\tiny": 0.5, - "\\sixptsize": 0.6, - "\\Tiny": 0.6, - "\\scriptsize": 0.7, - "\\footnotesize": 0.8, - "\\small": 0.9, - "\\normalsize": 1.0, - "\\large": 1.2, - "\\Large": 1.44, - "\\LARGE": 1.728, - "\\huge": 2.074, - "\\Huge": 2.488 - }; - - defineFunction({ - type: "sizing", - names: [ - "\\tiny", - "\\sixptsize", - "\\Tiny", - "\\scriptsize", - "\\footnotesize", - "\\small", - "\\normalsize", - "\\large", - "\\Large", - "\\LARGE", - "\\huge", - "\\Huge" - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ breakOnTokenText, funcName, parser }, args) => { - if (parser.settings.strict && parser.mode === "math") { - // eslint-disable-next-line no-console - console.log(`Temml strict-mode warning: Command ${funcName} is invalid in math mode.`); - } - const body = parser.parseExpression(false, breakOnTokenText); - return { - type: "sizing", - mode: parser.mode, - funcName, - body - }; - }, - mathmlBuilder: (group, style) => { - const newStyle = style.withFontSize(sizeMap[group.funcName]); - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - const factor = (sizeMap[group.funcName] / style.fontSize).toFixed(4); - node.setAttribute("mathsize", factor + "em"); - return node; - } - }); - - // smash, with optional [tb], as in AMS - - defineFunction({ - type: "smash", - names: ["\\smash"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args, optArgs) => { - let smashHeight = false; - let smashDepth = false; - const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); - if (tbArg) { - // Optional [tb] argument is engaged. - // ref: amsmath: \renewcommand{\smash}[1][tb]{% - // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% - let letter = ""; - for (let i = 0; i < tbArg.body.length; ++i) { - const node = tbArg.body[i]; - // TODO: Write an AssertSymbolNode - letter = node.text; - if (letter === "t") { - smashHeight = true; - } else if (letter === "b") { - smashDepth = true; - } else { - smashHeight = false; - smashDepth = false; - break; - } - } - } else { - smashHeight = true; - smashDepth = true; - } - - const body = args[0]; - return { - type: "smash", - mode: parser.mode, - body, - smashHeight, - smashDepth - }; - }, - mathmlBuilder: (group, style) => { - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, style)]); - - if (group.smashHeight) { - node.setAttribute("height", "0px"); - } - - if (group.smashDepth) { - node.setAttribute("depth", "0px"); - } - - return node; - } - }); - - defineFunction({ - type: "sqrt", - names: ["\\sqrt"], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser }, args, optArgs) { - const index = optArgs[0]; - const body = args[0]; - return { - type: "sqrt", - mode: parser.mode, - body, - index - }; - }, - mathmlBuilder(group, style) { - const { body, index } = group; - return index - ? new mathMLTree.MathNode("mroot", [ - buildGroup$1(body, style), - buildGroup$1(index, style.incrementLevel()) - ]) - : new mathMLTree.MathNode("msqrt", [buildGroup$1(body, style)]); - } - }); - - const styleMap = { - display: 0, - text: 1, - script: 2, - scriptscript: 3 - }; - - const styleAttributes = { - display: ["0", "true"], - text: ["0", "false"], - script: ["1", "false"], - scriptscript: ["2", "false"] - }; - - defineFunction({ - type: "styling", - names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ breakOnTokenText, funcName, parser }, args) { - // parse out the implicit body - const body = parser.parseExpression(true, breakOnTokenText); - - const scriptLevel = funcName.slice(1, funcName.length - 5); - return { - type: "styling", - mode: parser.mode, - // Figure out what scriptLevel to use by pulling out the scriptLevel from - // the function name - scriptLevel, - body - }; - }, - mathmlBuilder(group, style) { - // Figure out what scriptLevel we're changing to. - const newStyle = style.withLevel(styleMap[group.scriptLevel]); - // The style argument in the next line does NOT directly set a MathML script level. - // It just tracks the style level, in case we need to know it for supsub or mathchoice. - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - - const attr = styleAttributes[group.scriptLevel]; - - // Here is where we set the MathML script level. - node.setAttribute("scriptlevel", attr[0]); - node.setAttribute("displaystyle", attr[1]); - - return node; - } - }); - - /** - * Sometimes, groups perform special rules when they have superscripts or - * subscripts attached to them. This function lets the `supsub` group know that - * Sometimes, groups perform special rules when they have superscripts or - * its inner element should handle the superscripts and subscripts instead of - * handling them itself. - */ - - // Helpers - const symbolRegEx = /^m(over|under|underover)$/; - - // Super scripts and subscripts, whose precise placement can depend on other - // functions that precede them. - defineFunctionBuilders({ - type: "supsub", - mathmlBuilder(group, style) { - // Is the inner group a relevant horizonal brace? - let isBrace = false; - let isOver; - let isSup; - let appendApplyFunction = false; - let needsLeadingSpace = false; - - if (group.base && group.base.type === "horizBrace") { - isSup = !!group.sup; - if (isSup === group.base.isOver) { - isBrace = true; - isOver = group.base.isOver; - } - } - - if (group.base && !group.base.stack && - (group.base.type === "op" || group.base.type === "operatorname")) { - group.base.parentIsSupSub = true; - appendApplyFunction = !group.base.symbol; - needsLeadingSpace = group.base.needsLeadingSpace; - } - - const children = group.base && group.base.stack - ? [buildGroup$1(group.base.body[0], style)] - : [buildGroup$1(group.base, style)]; - - const childStyle = style.inSubOrSup(); - if (group.sub) { - children.push(buildGroup$1(group.sub, childStyle)); - } - - if (group.sup) { - children.push(buildGroup$1(group.sup, childStyle)); - } - - let nodeType; - if (isBrace) { - nodeType = isOver ? "mover" : "munder"; - } else if (!group.sub) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "mover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "mover"; - } else { - nodeType = "msup"; - } - } else if (!group.sup) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munder"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "munder"; - } else { - nodeType = "msub"; - } - } else { - const base = group.base; - if (base && ((base.type === "op" && base.limits) || base.type === "multiscript") && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munderover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (style.level === StyleLevel.DISPLAY || base.limits) - ) { - nodeType = "munderover"; - } else { - nodeType = "msubsup"; - } - } - - let node = new mathMLTree.MathNode(nodeType, children); - if (appendApplyFunction) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (needsLeadingSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node = mathMLTree.newDocumentFragment([space, node, operator]); - } else { - node = mathMLTree.newDocumentFragment([node, operator]); - } - } else if (symbolRegEx.test(nodeType)) { - // Wrap in a . Otherwise Firefox stretchy parens will not stretch to include limits. - node = new mathMLTree.MathNode("mrow", [node]); - } - - return node - } - }); - - // Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js. - - const short = ["\\shortmid", "\\nshortmid", "\\shortparallel", - "\\nshortparallel", "\\smallsetminus"]; - - defineFunctionBuilders({ - type: "atom", - mathmlBuilder(group, style) { - const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]); - if (group.family === "punct") { - node.setAttribute("separator", "true"); - } else if (group.family === "open" || group.family === "close") { - // Delims built here should not stretch vertically. - // See delimsizing.js for stretchy delims. - if (group.family === "open") { - node.setAttribute("form", "prefix"); - // Set an explicit attribute for stretch. Otherwise Firefox may do it wrong. - node.setAttribute("stretchy", "false"); - } else if (group.family === "close") { - node.setAttribute("form", "postfix"); - node.setAttribute("stretchy", "false"); - } - } else if (group.text === "\\mid") { - // Firefox messes up this spacing if at the end of an . See it explicitly. - node.setAttribute("lspace", "0.22em"); // medium space - node.setAttribute("rspace", "0.22em"); - node.setAttribute("stretchy", "false"); - } else if (short.includes(group.text)) { - node.setAttribute("mathsize", "70%"); - } else if (group.text === ":") { - // ":" is not in the MathML operator dictionary. Give it BIN spacing. - node.attributes.lspace = "0.2222em"; - node.attributes.rspace = "0.2222em"; - } - return node; - } - }); - - /** - * Maps TeX font commands to "mathvariant" attribute in buildMathML.js - */ - const fontMap = { - // styles - mathbf: "bold", - mathrm: "normal", - textit: "italic", - mathit: "italic", - mathnormal: "italic", - - // families - mathbb: "double-struck", - mathcal: "script", - mathfrak: "fraktur", - mathscr: "script", - mathsf: "sans-serif", - mathtt: "monospace", - oldstylenums: "oldstylenums" - }; - - /** - * Returns the math variant as a string or null if none is required. - */ - const getVariant = function(group, style) { - // Handle font specifiers as best we can. - // Chromium does not support the MathML mathvariant attribute. - // So we'll use Unicode replacement characters instead. - // But first, determine the math variant. - - // Deal with the \textit, \textbf, etc., functions. - if (style.fontFamily === "texttt") { - return "monospace" - } else if (style.fontFamily === "textsc") { - return "normal"; // handled via character substitution in symbolsOrd.js. - } else if (style.fontFamily === "textsf") { - if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "sans-serif-bold-italic" - } else if (style.fontShape === "textit") { - return "sans-serif-italic" - } else if (style.fontWeight === "textbf") { - return "sans-serif-bold" - } else { - return "sans-serif" - } - } else if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "bold-italic" - } else if (style.fontShape === "textit") { - return "italic" - } else if (style.fontWeight === "textbf") { - return "bold" - } - - // Deal with the \mathit, mathbf, etc, functions. - const font = style.font; - if (!font || font === "mathnormal") { - return null - } - - const mode = group.mode; - switch (font) { - case "mathit": - return "italic" - case "mathrm": { - const codePoint = group.text.codePointAt(0); - // LaTeX \mathrm returns italic for Greek characters. - return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal" - } - case "greekItalic": - return "italic" - case "up@greek": - return "normal" - case "boldsymbol": - case "mathboldsymbol": - return "bold-italic" - case "mathbf": - return "bold" - case "mathbb": - return "double-struck" - case "mathfrak": - return "fraktur" - case "mathscr": - case "mathcal": - return "script" - case "mathsf": - return "sans-serif" - case "mathtt": - return "monospace" - case "oldstylenums": - return "oldstylenums" - } - - let text = group.text; - if (symbols[mode][text] && symbols[mode][text].replace) { - text = symbols[mode][text].replace; - } - - return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null - }; - - // Chromium does not support the MathML `mathvariant` attribute. - // Instead, we replace ASCII characters with Unicode characters that - // are defined in the font as bold, italic, double-struck, etc. - // This module identifies those Unicode code points. - - // First, a few helpers. - const script = Object.freeze({ - B: 0x20EA, // Offset from ASCII B to Unicode script B - E: 0x20EB, - F: 0x20EB, - H: 0x20C3, - I: 0x20C7, - L: 0x20C6, - M: 0x20E6, - R: 0x20C9, - e: 0x20CA, - g: 0x20A3, - o: 0x20C5 - }); - - const frak = Object.freeze({ - C: 0x20EA, - H: 0x20C4, - I: 0x20C8, - R: 0x20CA, - Z: 0x20CE - }); - - const bbb = Object.freeze({ - C: 0x20BF, // blackboard bold - H: 0x20C5, - N: 0x20C7, - P: 0x20C9, - Q: 0x20C9, - R: 0x20CB, - Z: 0x20CA - }); - - const bold = Object.freeze({ - "\u03f5": 0x1D2E7, // lunate epsilon - "\u03d1": 0x1D30C, // vartheta - "\u03f0": 0x1D2EE, // varkappa - "\u03c6": 0x1D319, // varphi - "\u03f1": 0x1D2EF, // varrho - "\u03d6": 0x1D30B // varpi - }); - - const boldItalic = Object.freeze({ - "\u03f5": 0x1D35B, // lunate epsilon - "\u03d1": 0x1D380, // vartheta - "\u03f0": 0x1D362, // varkappa - "\u03c6": 0x1D38D, // varphi - "\u03f1": 0x1D363, // varrho - "\u03d6": 0x1D37F // varpi - }); - - const boldsf = Object.freeze({ - "\u03f5": 0x1D395, // lunate epsilon - "\u03d1": 0x1D3BA, // vartheta - "\u03f0": 0x1D39C, // varkappa - "\u03c6": 0x1D3C7, // varphi - "\u03f1": 0x1D39D, // varrho - "\u03d6": 0x1D3B9 // varpi - }); - - const bisf = Object.freeze({ - "\u03f5": 0x1D3CF, // lunate epsilon - "\u03d1": 0x1D3F4, // vartheta - "\u03f0": 0x1D3D6, // varkappa - "\u03c6": 0x1D401, // varphi - "\u03f1": 0x1D3D7, // varrho - "\u03d6": 0x1D3F3 // varpi - }); - - // Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf - const offset = Object.freeze({ - upperCaseLatin: { // A-Z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3BF }, - "italic": ch => { return 0x1D3F3 }, - "bold-italic": ch => { return 0x1D427 }, - "script": ch => { return script[ch] || 0x1D45B }, - "script-bold": ch => { return 0x1D48F }, - "fraktur": ch => { return frak[ch] || 0x1D4C3 }, - "fraktur-bold": ch => { return 0x1D52B }, - "double-struck": ch => { return bbb[ch] || 0x1D4F7 }, - "sans-serif": ch => { return 0x1D55F }, - "sans-serif-bold": ch => { return 0x1D593 }, - "sans-serif-italic": ch => { return 0x1D5C7 }, - "sans-serif-bold-italic": ch => { return 0x1D63C }, - "monospace": ch => { return 0x1D62F } - }, - lowerCaseLatin: { // a-z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3B9 }, - "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED }, - "bold-italic": ch => { return 0x1D421 }, - "script": ch => { return script[ch] || 0x1D455 }, - "script-bold": ch => { return 0x1D489 }, - "fraktur": ch => { return 0x1D4BD }, - "fraktur-bold": ch => { return 0x1D525 }, - "double-struck": ch => { return 0x1D4F1 }, - "sans-serif": ch => { return 0x1D559 }, - "sans-serif-bold": ch => { return 0x1D58D }, - "sans-serif-italic": ch => { return 0x1D5C1 }, - "sans-serif-bold-italic": ch => { return 0x1D5F5 }, - "monospace": ch => { return 0x1D629 } - }, - upperCaseGreek: { // A-Ω ∇ - "normal": ch => { return 0 }, - "bold": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "italic": ch => { return ch === "∇" ? 0x1B4F4 : 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-bold": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return ch === "∇" ? 0x1B5A2 : 0x1D3FF }, - "monospace": ch => { return 0 } - }, - lowerCaseGreek: { // α-ω - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D311 }, - "italic": ch => { return 0x1D34B }, - "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return 0x1D3BF }, - "sans-serif-bold": ch => { return 0x1D3BF }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0x1D3F9 }, - "monospace": ch => { return 0 } - }, - varGreek: { // \varGamma, etc - "normal": ch => { return 0 }, - "bold": ch => { return bold[ch] || -51 }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return boldItalic[ch] || 0x3A }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - "sans-serif": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-bold": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE }, - "monospace": ch => { return 0 } - }, - numeral: { // 0-9 - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D79E }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return 0 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0x1D7A8 }, - "sans-serif": ch => { return 0x1D7B2 }, - "sans-serif-bold": ch => { return 0x1D7BC }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0 }, - "monospace": ch => { return 0x1D7C6 } - } - }); - - const variantChar = (ch, variant) => { - const codePoint = ch.codePointAt(0); - const block = 0x40 < codePoint && codePoint < 0x5b - ? "upperCaseLatin" - : 0x60 < codePoint && codePoint < 0x7b - ? "lowerCaseLatin" - : (0x390 < codePoint && codePoint < 0x3AA) || ch === "∇" - ? "upperCaseGreek" - : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5" - ? "lowerCaseGreek" - : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch] - ? "varGreek" - : (0x2F < codePoint && codePoint < 0x3A) - ? "numeral" - : "other"; - return block === "other" - ? ch - : String.fromCodePoint(codePoint + offset[block][variant](ch)) - }; - - const smallCaps = Object.freeze({ - a: "ᴀ", - b: "ʙ", - c: "ᴄ", - d: "ᴅ", - e: "ᴇ", - f: "ꜰ", - g: "ɢ", - h: "ʜ", - i: "ɪ", - j: "ᴊ", - k: "ᴋ", - l: "ʟ", - m: "ᴍ", - n: "ɴ", - o: "ᴏ", - p: "ᴘ", - q: "ǫ", - r: "ʀ", - s: "s", - t: "ᴛ", - u: "ᴜ", - v: "ᴠ", - w: "ᴡ", - x: "x", - y: "ʏ", - z: "ᴢ" - }); - - // "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in - // src/symbols.js. - - const numberRegEx$1 = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in Parser.js - - const latinRegEx = /[A-Ba-z]/; - - const italicNumber = (text, variant) => { - const mn = new mathMLTree.MathNode("mn", [text]); - const wrapper = new mathMLTree.MathNode("mstyle", [mn]); - wrapper.style["font-style"] = "italic"; - wrapper.style["font-family"] = "Cambria, 'Times New Roman', serif"; - if (variant === "bold-italic") { wrapper.style["font-weight"] = "bold"; } - return wrapper - }; - - defineFunctionBuilders({ - type: "mathord", - mathmlBuilder(group, style) { - const text = makeText(group.text, group.mode, style); - const codePoint = text.text.codePointAt(0); - // Test for upper-case Greek - const defaultVariant = (0x0390 < codePoint && codePoint < 0x03aa) ? "normal" : "italic"; - const variant = getVariant(group, style) || defaultVariant; - if (variant === "script") { - text.text = variantChar(text.text, variant); - return new mathMLTree.MathNode("mi", [text], [style.font]) - } else if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - let node = new mathMLTree.MathNode("mi", [text]); - // TODO: Handle U+1D49C - U+1D4CF per https://www.unicode.org/charts/PDF/U1D400.pdf - if (variant === "normal") { - node.setAttribute("mathvariant", "normal"); - if (text.text.length === 1) { - // A Firefox bug will apply spacing here, but there should be none. Fix it. - node = new mathMLTree.MathNode("mpadded", [node]); - node.setAttribute("lspace", "0"); - node.setAttribute("width", "+0em"); - } - } - return node - } - }); - - defineFunctionBuilders({ - type: "textord", - mathmlBuilder(group, style) { - let ch = group.text; - const codePoint = ch.codePointAt(0); - if (style.fontFamily === "textsc") { - // Convert small latin letters to small caps. - if (96 < codePoint && codePoint < 123) { - ch = smallCaps[ch]; - } - } - const text = makeText(ch, group.mode, style); - const variant = getVariant(group, style) || "normal"; - - let node; - if (group.mode === "text") { - if (variant === "italic" || variant === "bold-italic") { - if (numberRegEx$1.test(group.text)) { - return italicNumber(text, variant) - } - } - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (numberRegEx$1.test(group.text)) { - if (variant === "oldstylenums") { - const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]); - node = new mathMLTree.MathNode("mn", [ms]); - } else if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode("mn", [text]); - } - } else if (group.text === "\\prime") { - node = new mathMLTree.MathNode("mo", [text]); - } else { - const origText = text.text; - if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mi", [text]); - if (text.text === origText && latinRegEx.test(origText)) { - node.setAttribute("mathvariant", "italic"); - } - } - return node - } - }); - - // A map of CSS-based spacing functions to their CSS class. - const cssSpace = { - "\\nobreak": "nobreak", - "\\allowbreak": "allowbreak" - }; - - // A lookup table to determine whether a spacing function/symbol should be - // treated like a regular space character. If a symbol or command is a key - // in this table, then it should be a regular space character. Furthermore, - // the associated value may have a `className` specifying an extra CSS class - // to add to the created `span`. - const regularSpace = { - " ": {}, - "\\ ": {}, - "~": { - className: "nobreak" - }, - "\\space": {}, - "\\nobreakspace": { - className: "nobreak" - } - }; - - // ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in - // src/symbols.js. - defineFunctionBuilders({ - type: "spacing", - mathmlBuilder(group, style) { - let node; - - if (Object.prototype.hasOwnProperty.call(regularSpace, group.text)) { - // Firefox does not render a space in a . So write a no-break space. - // TODO: If Firefox fixes that bug, uncomment the next line and write ch into the node. - //const ch = (regularSpace[group.text].className === "nobreak") ? "\u00a0" : " " - node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]); - } else if (Object.prototype.hasOwnProperty.call(cssSpace, group.text)) { - // MathML 3.0 calls for nobreak to occur in an , not an - // Ref: https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs - node = new mathMLTree.MathNode("mo"); - if (group.text === "\\nobreak") { - node.setAttribute("linebreak", "nobreak"); - } - } else { - throw new ParseError(`Unknown type of space "${group.text}"`) - } - - return node - } - }); - - defineFunctionBuilders({ - type: "tag" - }); - - // For a \tag, the work usually done in a mathmlBuilder is instead done in buildMathML.js. - // That way, a \tag can be pulled out of the parse tree and wrapped around the outer node. - - // Non-mathy text, possibly in a font - const textFontFamilies = { - "\\text": undefined, - "\\textrm": "textrm", - "\\textsf": "textsf", - "\\texttt": "texttt", - "\\textnormal": "textrm", - "\\textsc": "textsc" // small caps - }; - - const textFontWeights = { - "\\textbf": "textbf", - "\\textmd": "textmd" - }; - - const textFontShapes = { - "\\textit": "textit", - "\\textup": "textup" - }; - - const styleWithFont = (group, style) => { - const font = group.font; - // Checks if the argument is a font family or a font style. - if (!font) { - return style; - } else if (textFontFamilies[font]) { - return style.withTextFontFamily(textFontFamilies[font]); - } else if (textFontWeights[font]) { - return style.withTextFontWeight(textFontWeights[font]); - } else { - return style.withTextFontShape(textFontShapes[font]); - } - }; - - defineFunction({ - type: "text", - names: [ - // Font families - "\\text", - "\\textrm", - "\\textsf", - "\\texttt", - "\\textnormal", - "\\textsc", - // Font weights - "\\textbf", - "\\textmd", - // Font Shapes - "\\textit", - "\\textup" - ], - props: { - numArgs: 1, - argTypes: ["text"], - allowedInArgument: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "text", - mode: parser.mode, - body: ordargument(body), - font: funcName - }; - }, - mathmlBuilder(group, style) { - const newStyle = styleWithFont(group, style); - const mrow = buildExpressionRow(group.body, newStyle); - return utils.consolidateText(mrow) - } - }); - - // Two functions included to enable migration from Mathjax. - - defineFunction({ - type: "tip", - names: ["\\mathtip"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup$1(group.body, style); - const tip = buildGroup$1(group.tip, style); - // Browsers don't support the tooltip actiontype. - // TODO: Come back and fix \mathtip when it can be done via CSS w/o a JS event. - const node = new mathMLTree.MathNode("maction", [math, tip], ["tml-tip"]); - node.setAttribute("actiontype", "tooltip"); - return node - } - }); - - defineFunction({ - type: "tip", - names: ["\\texttip"], - props: { - numArgs: 2, - argTypes: ["math", "text"] - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup$1(group.body, style); - const tip = buildGroup$1(group.tip, style); - // args[1] only accepted text, so tip is a element or a of them. - let str = ""; - if (tip.type === "mtext") { - str = tip.children[0].text; - } else { - for (const child of tip.children) { - str += child.children[0].text; - } - } - // Implement \texttip via a title attribute. - math.setAttribute("title", str); - return math - } - }); - - defineFunctionBuilders({ - type: "toggle", - mathmlBuilder(group, style) { - const expression = buildExpression(group.body, style); - const node = new mathMLTree.MathNode("maction", expression, [], { cursor: "default" }); - node.setAttribute("actiontype", "toggle"); - return node - } - }); - - defineFunction({ - type: "underline", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "underline", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005f")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode("munder", - [buildGroup$1(group.body, style), operator] - ); - node.setAttribute("accentunder", "true"); - - return node; - } - }); - - defineFunction({ - type: "verb", - names: ["\\verb"], - props: { - numArgs: 0, - allowedInText: true - }, - handler(context, args, optArgs) { - // \verb and \verb* are dealt with directly in Parser.js. - // If we end up here, it's because of a failure to match the two delimiters - // in the regex in Lexer.js. LaTeX raises the following error when \verb is - // terminated by end of line (or file). - throw new ParseError("\\verb ended by end of line instead of matching delimiter"); - }, - mathmlBuilder(group, style) { - const text = new mathMLTree.TextNode(makeVerb(group)); - const node = new mathMLTree.MathNode("mtext", [text]); - node.setAttribute("mathvariant", "monospace"); - return node; - } - }); - - /** - * Converts verb group into body string. - * - * \verb* replaces each space with an open box \u2423 - * \verb replaces each space with a no-break space \xA0 - */ - const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0"); - - /** Include this to ensure that all functions are defined. */ - - const functions = _functions; - - /** - * Lexing or parsing positional information for error reporting. - * This object is immutable. - */ - class SourceLocation { - constructor(lexer, start, end) { - this.lexer = lexer; // Lexer holding the input string. - this.start = start; // Start offset, zero-based inclusive. - this.end = end; // End offset, zero-based exclusive. - } - - /** - * Merges two `SourceLocation`s from location providers, given they are - * provided in order of appearance. - * - Returns the first one's location if only the first is provided. - * - Returns a merged range of the first and the last if both are provided - * and their lexers match. - * - Otherwise, returns null. - */ - static range(first, second) { - if (!second) { - return first && first.loc; - } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { - return null; - } else { - return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); - } - } - } - - /** - * Interface required to break circular dependency between Token, Lexer, and - * ParseError. - */ - - /** - * The resulting token returned from `lex`. - * - * It consists of the token text plus some position information. - * The position information is essentially a range in an input string, - * but instead of referencing the bare input string, we refer to the lexer. - * That way it is possible to attach extra metadata to the input string, - * like for example a file name or similar. - * - * The position information is optional, so it is OK to construct synthetic - * tokens if appropriate. Not providing available position information may - * lead to degraded error reporting, though. - */ - class Token { - constructor( - text, // the text of this token - loc - ) { - this.text = text; - this.loc = loc; - } - - /** - * Given a pair of tokens (this and endToken), compute a `Token` encompassing - * the whole input range enclosed by these two. - */ - range( - endToken, // last token of the range, inclusive - text // the text of the newly constructed token - ) { - return new Token(text, SourceLocation.range(this, endToken)); - } - } - - /** - * The Lexer class handles tokenizing the input in various ways. Since our - * parser expects us to be able to backtrack, the lexer allows lexing from any - * given starting point. - * - * Its main exposed function is the `lex` function, which takes a position to - * lex from and a type of token to lex. It defers to the appropriate `_innerLex` - * function. - * - * The various `_innerLex` functions perform the actual lexing of different - * kinds. - */ - - /* The following tokenRegex - * - matches typical whitespace (but not NBSP etc.) using its first two groups - * - does not match any control character \x00-\x1f except whitespace - * - does not match a bare backslash - * - matches any ASCII character except those just mentioned - * - does not match the BMP private use area \uE000-\uF8FF - * - does not match bare surrogate code units - * - matches any BMP character except for those just described - * - matches any valid Unicode surrogate pair - * - mathches numerals - * - matches a backslash followed by one or more whitespace characters - * - matches a backslash followed by one or more letters then whitespace - * - matches a backslash followed by any BMP character - * Capturing groups: - * [1] regular whitespace - * [2] backslash followed by whitespace - * [3] anything else, which may include: - * [4] left character of \verb* - * [5] left character of \verb - * [6] backslash followed by word, excluding any trailing whitespace - * Just because the Lexer matches something doesn't mean it's valid input: - * If there is no matching function or symbol definition, the Parser will - * still reject the input. - */ - const spaceRegexString = "[ \r\n\t]"; - const controlWordRegexString = "\\\\[a-zA-Z@]+"; - const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; - const controlWordWhitespaceRegexString = `(${controlWordRegexString})${spaceRegexString}*`; - const controlSpaceRegexString = "\\\\(\n|[ \r\t]+\n?)[ \r\t]*"; - const combiningDiacriticalMarkString = "[\u0300-\u036f]"; - const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); - const tokenRegexString = - `(${spaceRegexString}+)|` + // whitespace - `${controlSpaceRegexString}|` + // whitespace - "(number" + // numbers (in non-strict mode) - "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|\\\\verb\\*([^]).*?\\4" + // \verb* - "|\\\\verb([^*a-zA-Z]).*?\\5" + // \verb unstarred - `|${controlWordWhitespaceRegexString}` + // \macroName + spaces - `|${controlSymbolRegexString})`; // \\, \', etc. - - /** Main Lexer class */ - class Lexer { - constructor(input, settings) { - // Separate accents from characters - this.input = input; - this.settings = settings; - this.tokenRegex = new RegExp( - // Strict Temml, like TeX, lexes one numeral at a time. - // Default Temml lexes contiguous numerals into a single element. - tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"), - "g" - ); - // Category codes. The lexer only supports comment characters (14) for now. - // MacroExpander additionally distinguishes active (13). - this.catcodes = { - "%": 14, // comment character - "~": 13 // active character - }; - } - - setCatcode(char, code) { - this.catcodes[char] = code; - } - - /** - * This function lexes a single token. - */ - lex() { - const input = this.input; - const pos = this.tokenRegex.lastIndex; - if (pos === input.length) { - return new Token("EOF", new SourceLocation(this, pos, pos)); - } - const match = this.tokenRegex.exec(input); - if (match === null || match.index !== pos) { - throw new ParseError( - `Unexpected character: '${input[pos]}'`, - new Token(input[pos], new SourceLocation(this, pos, pos + 1)) - ); - } - const text = match[6] || match[3] || (match[2] ? "\\ " : " "); - - if (this.catcodes[text] === 14) { - // comment character - const nlIndex = input.indexOf("\n", this.tokenRegex.lastIndex); - if (nlIndex === -1) { - this.tokenRegex.lastIndex = input.length; // EOF - if (this.settings.strict) { - throw new ParseError("% comment has no terminating newline; LaTeX would " + - "fail because of commenting the end of math mode") - } - } else { - this.tokenRegex.lastIndex = nlIndex + 1; - } - return this.lex(); - } - - return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); - } - } - - /** - * A `Namespace` refers to a space of nameable things like macros or lengths, - * which can be `set` either globally or local to a nested group, using an - * undo stack similar to how TeX implements this functionality. - * Performance-wise, `get` and `set` take constant time. - */ - - class Namespace { - /** - * Both arguments are optional. The first argument is an object of - * built-in mappings which never change. The second argument is an object - * of initial (global-level) mappings, which will constantly change - * according to any global/top-level `set`s done. - */ - constructor(builtins = {}, globalMacros = {}) { - this.current = globalMacros; - this.builtins = builtins; - this.undefStack = []; - } - - /** - * Start a new nested group, affecting future local `set`s. - */ - beginGroup() { - this.undefStack.push({}); - } - - /** - * End current nested group, restoring values before the group began. - */ - endGroup() { - if (this.undefStack.length === 0) { - throw new ParseError( - "Unbalanced namespace destruction: attempt " + - "to pop global namespace; please report this as a bug" - ); - } - const undefs = this.undefStack.pop(); - for (const undef in undefs) { - if (Object.prototype.hasOwnProperty.call(undefs, undef )) { - if (undefs[undef] === undefined) { - delete this.current[undef]; - } else { - this.current[undef] = undefs[undef]; - } - } - } - } - - /** - * Detect whether `name` has a definition. Equivalent to - * `get(name) != null`. - */ - has(name) { - return Object.prototype.hasOwnProperty.call(this.current, name ) || - Object.prototype.hasOwnProperty.call(this.builtins, name ); - } - - /** - * Get the current value of a name, or `undefined` if there is no value. - * - * Note: Do not use `if (namespace.get(...))` to detect whether a macro - * is defined, as the definition may be the empty string which evaluates - * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or - * `if (namespace.has(...))`. - */ - get(name) { - if (Object.prototype.hasOwnProperty.call(this.current, name )) { - return this.current[name]; - } else { - return this.builtins[name]; - } - } - - /** - * Set the current value of a name, and adds an undo - * operation to the undo stack. - */ - set(name, value) { - // Undo this set at end of this group (possibly to `undefined`), - // unless an undo is already in place, in which case that older - // value is the correct one. - const top = this.undefStack[this.undefStack.length - 1]; - if (top && !Object.prototype.hasOwnProperty.call(top, name )) { - top[name] = this.current[name]; - } - this.current[name] = value; - } - } - - /** - * Predefined macros for Temml. - * This can be used to define some commands in terms of others. - */ - const macros = _macros; - - ////////////////////////////////////////////////////////////////////// - // macro tools - - defineMacro("\\noexpand", function(context) { - // The expansion is the token itself; but that token is interpreted - // as if its meaning were ‘\relax’ if it is a control sequence that - // would ordinarily be expanded by TeX’s expansion rules. - const t = context.popToken(); - if (context.isExpandable(t.text)) { - t.noexpand = true; - t.treatAsRelax = true; - } - return { tokens: [t], numArgs: 0 }; - }); - - defineMacro("\\expandafter", function(context) { - // TeX first reads the token that comes immediately after \expandafter, - // without expanding it; let’s call this token t. Then TeX reads the - // token that comes after t (and possibly more tokens, if that token - // has an argument), replacing it by its expansion. Finally TeX puts - // t back in front of that expansion. - const t = context.popToken(); - context.expandOnce(true); // expand only an expandable token - return { tokens: [t], numArgs: 0 }; - }); - - // LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 - // TeX source: \long\def\@firstoftwo#1#2{#1} - defineMacro("\\@firstoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[0], numArgs: 0 }; - }); - - // LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 - // TeX source: \long\def\@secondoftwo#1#2{#2} - defineMacro("\\@secondoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[1], numArgs: 0 }; - }); - - // LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) - // symbol that isn't a space, consuming any spaces but not consuming the - // first nonspace character. If that nonspace character matches #1, then - // the macro expands to #2; otherwise, it expands to #3. - defineMacro("\\@ifnextchar", function(context) { - const args = context.consumeArgs(3); // symbol, if, else - context.consumeSpaces(); - const nextToken = context.future(); - if (args[0].length === 1 && args[0][0].text === nextToken.text) { - return { tokens: args[1], numArgs: 0 }; - } else { - return { tokens: args[2], numArgs: 0 }; - } - }); - - // LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. - // If it is `*`, then it consumes the symbol, and the macro expands to #1; - // otherwise, the macro expands to #2 (without consuming the symbol). - // TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} - defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); - - // LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode - defineMacro("\\TextOrMath", function(context) { - const args = context.consumeArgs(2); - if (context.mode === "text") { - return { tokens: args[0], numArgs: 0 }; - } else { - return { tokens: args[1], numArgs: 0 }; - } - }); - - const stringFromArg = arg => { - // Reverse the order of the arg and return a string. - let str = ""; - for (let i = arg.length - 1; i > -1; i--) { - str += arg[i].text; - } - return str - }; - - // Lookup table for parsing numbers in base 8 through 16 - const digitToNumber = { - 0: 0, - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - a: 10, - A: 10, - b: 11, - B: 11, - c: 12, - C: 12, - d: 13, - D: 13, - e: 14, - E: 14, - f: 15, - F: 15 - }; - - const nextCharNumber = context => { - const numStr = context.future().text; - if (numStr === "EOF") { return [null, ""] } - return [digitToNumber[numStr.charAt(0)], numStr] - }; - - const appendCharNumbers = (number, numStr, base) => { - for (let i = 1; i < numStr.length; i++) { - const digit = digitToNumber[numStr.charAt(i)]; - number *= base; - number += digit; - } - return number - }; - - // TeX \char makes a literal character (catcode 12) using the following forms: - // (see The TeXBook, p. 43) - // \char123 -- decimal - // \char'123 -- octal - // \char"123 -- hex - // \char`x -- character that can be written (i.e. isn't active) - // \char`\x -- character that cannot be written (e.g. %) - // These all refer to characters from the font, so we turn them into special - // calls to a function \@char dealt with in the Parser. - defineMacro("\\char", function(context) { - let token = context.popToken(); - let base; - let number = ""; - if (token.text === "'") { - base = 8; - token = context.popToken(); - } else if (token.text === '"') { - base = 16; - token = context.popToken(); - } else if (token.text === "`") { - token = context.popToken(); - if (token.text[0] === "\\") { - number = token.text.charCodeAt(1); - } else if (token.text === "EOF") { - throw new ParseError("\\char` missing argument"); - } else { - number = token.text.charCodeAt(0); - } - } else { - base = 10; - } - if (base) { - // Parse a number in the given base, starting with first `token`. - let numStr = token.text; - number = digitToNumber[numStr.charAt(0)]; - if (number == null || number >= base) { - throw new ParseError(`Invalid base-${base} digit ${token.text}`); - } - number = appendCharNumbers(number, numStr, base); - let digit; - [digit, numStr] = nextCharNumber(context); - while (digit != null && digit < base) { - number *= base; - number += digit; - number = appendCharNumbers(number, numStr, base); - context.popToken(); - [digit, numStr] = nextCharNumber(context); - } - } - return `\\@char{${number}}`; - }); - - // The Latin Modern font renders at the wrong vertical alignment. - // This macro provides a better rendering. - defineMacro("\\surd", "\\sqrt{}"); - - defineMacro("\\hbox", "\\text{#1}"); - - // Per TeXbook p.122, "/" gets zero operator spacing. - // And MDN recommends using U+2044 instead of / for inline - defineMacro("/", "{\u2044}"); - - // Since Temml has no \par, ignore \long. - defineMacro("\\long", ""); - - ////////////////////////////////////////////////////////////////////// - // Grouping - // \let\bgroup={ \let\egroup=} - defineMacro("\\bgroup", "{"); - defineMacro("\\egroup", "}"); - - // Symbols from latex.ltx: - // \def~{\nobreakspace{}} - // \def\lq{`} - // \def\rq{'} - // \def \aa {\r a} - defineMacro("~", "\\nobreakspace"); - defineMacro("\\lq", "`"); - defineMacro("\\rq", "'"); - defineMacro("\\aa", "\\r a"); - - defineMacro("\\Bbbk", "\\Bbb{k}"); - - // \mathstrut from the TeXbook, p 360 - defineMacro("\\mathstrut", "\\vphantom{(}"); - - // \underbar from TeXbook p 353 - defineMacro("\\underbar", "\\underline{\\text{#1}}"); - - ////////////////////////////////////////////////////////////////////// - // LaTeX_2ε - - // \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ - // \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} - // We'll call \varvdots, which gets a glyph from symbols.js. - // The zero-width rule gets us an equivalent to the vertical 6pt kern. - defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); - defineMacro("\u22ee", "\\vdots"); - - ////////////////////////////////////////////////////////////////////// - // amsmath.sty - // http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf - - //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} - defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); - - // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} - defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); - - // \def\iff{\DOTSB\;\Longleftrightarrow\;} - // \def\implies{\DOTSB\;\Longrightarrow\;} - // \def\impliedby{\DOTSB\;\Longleftarrow\;} - defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); - defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); - defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); - - // AMSMath's automatic \dots, based on \mdots@@ macro. - const dotsByToken = { - ",": "\\dotsc", - "\\not": "\\dotsb", - // \keybin@ checks for the following: - "+": "\\dotsb", - "=": "\\dotsb", - "<": "\\dotsb", - ">": "\\dotsb", - "-": "\\dotsb", - "*": "\\dotsb", - ":": "\\dotsb", - // Symbols whose definition starts with \DOTSB: - "\\DOTSB": "\\dotsb", - "\\coprod": "\\dotsb", - "\\bigvee": "\\dotsb", - "\\bigwedge": "\\dotsb", - "\\biguplus": "\\dotsb", - "\\bigcap": "\\dotsb", - "\\bigcup": "\\dotsb", - "\\prod": "\\dotsb", - "\\sum": "\\dotsb", - "\\bigotimes": "\\dotsb", - "\\bigoplus": "\\dotsb", - "\\bigodot": "\\dotsb", - "\\bigsqcap": "\\dotsb", - "\\bigsqcup": "\\dotsb", - "\\And": "\\dotsb", - "\\longrightarrow": "\\dotsb", - "\\Longrightarrow": "\\dotsb", - "\\longleftarrow": "\\dotsb", - "\\Longleftarrow": "\\dotsb", - "\\longleftrightarrow": "\\dotsb", - "\\Longleftrightarrow": "\\dotsb", - "\\mapsto": "\\dotsb", - "\\longmapsto": "\\dotsb", - "\\hookrightarrow": "\\dotsb", - "\\doteq": "\\dotsb", - // Symbols whose definition starts with \mathbin: - "\\mathbin": "\\dotsb", - // Symbols whose definition starts with \mathrel: - "\\mathrel": "\\dotsb", - "\\relbar": "\\dotsb", - "\\Relbar": "\\dotsb", - "\\xrightarrow": "\\dotsb", - "\\xleftarrow": "\\dotsb", - // Symbols whose definition starts with \DOTSI: - "\\DOTSI": "\\dotsi", - "\\int": "\\dotsi", - "\\oint": "\\dotsi", - "\\iint": "\\dotsi", - "\\iiint": "\\dotsi", - "\\iiiint": "\\dotsi", - "\\idotsint": "\\dotsi", - // Symbols whose definition starts with \DOTSX: - "\\DOTSX": "\\dotsx" - }; - - defineMacro("\\dots", function(context) { - // TODO: If used in text mode, should expand to \textellipsis. - // However, in Temml, \textellipsis and \ldots behave the same - // (in text mode), and it's unlikely we'd see any of the math commands - // that affect the behavior of \dots when in text mode. So fine for now - // (until we support \ifmmode ... \else ... \fi). - let thedots = "\\dotso"; - const next = context.expandAfterFuture().text; - if (next in dotsByToken) { - thedots = dotsByToken[next]; - } else if (next.slice(0, 4) === "\\not") { - thedots = "\\dotsb"; - } else if (next in symbols.math) { - if (utils.contains(["bin", "rel"], symbols.math[next].group)) { - thedots = "\\dotsb"; - } - } - return thedots; - }); - - const spaceAfterDots = { - // \rightdelim@ checks for the following: - ")": true, - "]": true, - "\\rbrack": true, - "\\}": true, - "\\rbrace": true, - "\\rangle": true, - "\\rceil": true, - "\\rfloor": true, - "\\rgroup": true, - "\\rmoustache": true, - "\\right": true, - "\\bigr": true, - "\\biggr": true, - "\\Bigr": true, - "\\Biggr": true, - // \extra@ also tests for the following: - $: true, - // \extrap@ checks for the following: - ";": true, - ".": true, - ",": true - }; - - defineMacro("\\dotso", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } - }); - - defineMacro("\\dotsc", function(context) { - const next = context.future().text; - // \dotsc uses \extra@ but not \extrap@, instead specially checking for - // ';' and '.', but doesn't check for ','. - if (next in spaceAfterDots && next !== ",") { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } - }); - - defineMacro("\\cdots", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\@cdots\\,"; - } else { - return "\\@cdots"; - } - }); - - defineMacro("\\dotsb", "\\cdots"); - defineMacro("\\dotsm", "\\cdots"); - defineMacro("\\dotsi", "\\!\\cdots"); - defineMacro("\\idotsint", "\\dotsi"); - // amsmath doesn't actually define \dotsx, but \dots followed by a macro - // starting with \DOTSX implies \dotso, and then \extra@ detects this case - // and forces the added `\,`. - defineMacro("\\dotsx", "\\ldots\\,"); - - // \let\DOTSI\relax - // \let\DOTSB\relax - // \let\DOTSX\relax - defineMacro("\\DOTSI", "\\relax"); - defineMacro("\\DOTSB", "\\relax"); - defineMacro("\\DOTSX", "\\relax"); - - // Spacing, based on amsmath.sty's override of LaTeX defaults - // \DeclareRobustCommand{\tmspace}[3]{% - // \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} - defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); - // \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} - // TODO: math mode should use \thinmuskip - defineMacro("\\,", "{\\tmspace+{3mu}{.1667em}}"); - // \let\thinspace\, - defineMacro("\\thinspace", "\\,"); - // \def\>{\mskip\medmuskip} - // \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} - // TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu - defineMacro("\\>", "\\mskip{4mu}"); - defineMacro("\\:", "{\\tmspace+{4mu}{.2222em}}"); - // \let\medspace\: - defineMacro("\\medspace", "\\:"); - // \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} - // TODO: math mode should use \thickmuskip = 5mu plus 5mu - defineMacro("\\;", "{\\tmspace+{5mu}{.2777em}}"); - // \let\thickspace\; - defineMacro("\\thickspace", "\\;"); - // \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} - // TODO: math mode should use \thinmuskip - defineMacro("\\!", "{\\tmspace-{3mu}{.1667em}}"); - // \let\negthinspace\! - defineMacro("\\negthinspace", "\\!"); - // \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} - // TODO: math mode should use \medmuskip - defineMacro("\\negmedspace", "{\\tmspace-{4mu}{.2222em}}"); - // \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} - // TODO: math mode should use \thickmuskip - defineMacro("\\negthickspace", "{\\tmspace-{5mu}{.277em}}"); - // \def\enspace{\kern.5em } - defineMacro("\\enspace", "\\kern.5em "); - // \def\enskip{\hskip.5em\relax} - defineMacro("\\enskip", "\\hskip.5em\\relax"); - // \def\quad{\hskip1em\relax} - defineMacro("\\quad", "\\hskip1em\\relax"); - // \def\qquad{\hskip2em\relax} - defineMacro("\\qquad", "\\hskip2em\\relax"); - - // \tag@in@display form of \tag - defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); - defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); - defineMacro("\\tag@literal", (context) => { - if (context.macros.get("\\df@tag")) { - throw new ParseError("Multiple \\tag"); - } - return "\\def\\df@tag{\\text{#1}}"; - }); - - // \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin - // {\operator@font mod}\penalty900 - // \mkern5mu\nonscript\mskip-\medmuskip} - // \newcommand{\pod}[1]{\allowbreak - // \if@display\mkern18mu\else\mkern8mu\fi(#1)} - // \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} - // \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu - // \else\mkern12mu\fi{\operator@font mod}\,\,#1} - // TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu - defineMacro("\\bmod", "\\mathbin{\\text{mod}}"); - defineMacro( - "\\pod", - "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)" - ); - defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); - defineMacro( - "\\mod", - "\\allowbreak" + - "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + - "{\\rm mod}\\,\\,#1" - ); - - ////////////////////////////////////////////////////////////////////// - // LaTeX source2e - - // \expandafter\let\expandafter\@normalcr - // \csname\expandafter\@gobble\string\\ \endcsname - // \DeclareRobustCommand\newline{\@normalcr\relax} - defineMacro("\\newline", "\\\\\\relax"); - - // \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} - // TODO: Doesn't normally work in math mode because \@ fails. - defineMacro("\\TeX", "\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"); - - defineMacro( - "\\LaTeX", - "\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX" - ); - - defineMacro( - "\\Temml", - // eslint-disable-next-line max-len - "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}" - ); - - // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} - // \def\@hspace#1{\hskip #1\relax} - // \def\@hspacer#1{\vrule \@width\z@\nobreak - // \hskip #1\hskip \z@skip} - defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); - defineMacro("\\@hspace", "\\hskip #1\\relax"); - defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); - - defineMacro("\\colon", `\\mathpunct{\\char"3a}`); - - ////////////////////////////////////////////////////////////////////// - // mathtools.sty - - defineMacro("\\prescript", "\\pres@cript{_{#1}^{#2}}{}{#3}"); - - //\providecommand\ordinarycolon{:} - defineMacro("\\ordinarycolon", `\\char"3a`); - // Raise to center on the math axis, as closely as possible. - defineMacro("\\vcentcolon", "\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}}"); - // \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} - defineMacro("\\coloneq", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2212}'); - // \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} - defineMacro("\\Coloneq", '\\mathrel{\\char"2237\\char"2212}'); - // \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} - defineMacro("\\Eqqcolon", '\\mathrel{\\char"3d\\char"2237}'); - // \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} - defineMacro("\\Eqcolon", '\\mathrel{\\char"2212\\char"2237}'); - // \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} - defineMacro("\\colonapprox", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2248}'); - // \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} - defineMacro("\\Colonapprox", '\\mathrel{\\char"2237\\char"2248}'); - // \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} - defineMacro("\\colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); - // \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} - defineMacro("\\Colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); - - ////////////////////////////////////////////////////////////////////// - // colonequals.sty - - // Alternate names for mathtools's macros: - defineMacro("\\ratio", "\\vcentcolon"); - defineMacro("\\coloncolon", "\\dblcolon"); - defineMacro("\\colonequals", "\\coloneqq"); - defineMacro("\\coloncolonequals", "\\Coloneqq"); - defineMacro("\\equalscolon", "\\eqqcolon"); - defineMacro("\\equalscoloncolon", "\\Eqqcolon"); - defineMacro("\\colonminus", "\\coloneq"); - defineMacro("\\coloncolonminus", "\\Coloneq"); - defineMacro("\\minuscolon", "\\eqcolon"); - defineMacro("\\minuscoloncolon", "\\Eqcolon"); - // \colonapprox name is same in mathtools and colonequals. - defineMacro("\\coloncolonapprox", "\\Colonapprox"); - // \colonsim name is same in mathtools and colonequals. - defineMacro("\\coloncolonsim", "\\Colonsim"); - - // Present in newtxmath, pxfonts and txfonts - defineMacro("\\notni", "\\mathrel{\\char`\u220C}"); - defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); - defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); - - ////////////////////////////////////////////////////////////////////// - // From amsopn.sty - defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}"); - defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}"); - defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"); - defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"); - defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"); - defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"); - - defineMacro("\\centerdot", "{\\medspace\\rule{0.167em}{0.189em}\\medspace}"); - - ////////////////////////////////////////////////////////////////////// - // statmath.sty - // https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf - - defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); - defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); - defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}"); - - ////////////////////////////////////////////////////////////////////// - // braket.sty - // http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf - - defineMacro("\\bra", "\\mathinner{\\langle{#1}|}"); - defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}"); - defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}"); - defineMacro("\\Bra", "\\left\\langle#1\\right|"); - defineMacro("\\Ket", "\\left|#1\\right\\rangle"); - const braketHelper = (one) => (context) => { - const left = context.consumeArg().tokens; - const middle = context.consumeArg().tokens; - const middleDouble = context.consumeArg().tokens; - const right = context.consumeArg().tokens; - const oldMiddle = context.macros.get("|"); - const oldMiddleDouble = context.macros.get("\\|"); - context.macros.beginGroup(); - const midMacro = (double) => (context) => { - if (one) { - // Only modify the first instance of | or \| - context.macros.set("|", oldMiddle); - if (middleDouble.length) { - context.macros.set("\\|", oldMiddleDouble); - } - } - let doubled = double; - if (!double && middleDouble.length) { - // Mimic \@ifnextchar - const nextToken = context.future(); - if (nextToken.text === "|") { - context.popToken(); - doubled = true; - } - } - return { - tokens: doubled ? middleDouble : middle, - numArgs: 0 - }; - }; - context.macros.set("|", midMacro(false)); - if (middleDouble.length) { - context.macros.set("\\|", midMacro(true)); - } - const arg = context.consumeArg().tokens; - const expanded = context.expandTokens([...right, ...arg, ...left]); // reversed - context.macros.endGroup(); - return { - tokens: expanded.reverse(), - numArgs: 0 - }; - }; - defineMacro("\\bra@ket", braketHelper(false)); - defineMacro("\\bra@set", braketHelper(true)); - defineMacro("\\Braket", "\\bra@ket{\\left\\langle}" + - "{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"); - defineMacro("\\Set", "\\bra@set{\\left\\{\\:}" + - "{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"); - defineMacro("\\set", "\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"); - // has no support for special || or \| - - ////////////////////////////////////////////////////////////////////// - // actuarialangle.dtx - defineMacro("\\angln", "{\\angl n}"); - - ////////////////////////////////////////////////////////////////////// - // derivative.sty - defineMacro("\\odv", "\\@ifstar\\odv@next\\odv@numerator"); - defineMacro("\\odv@numerator", "\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}"); - defineMacro("\\odv@next", "\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1"); - defineMacro("\\pdv", "\\@ifstar\\pdv@next\\pdv@numerator"); - - const pdvHelper = args => { - const numerator = args[0][0].text; - const denoms = stringFromArg(args[1]).split(","); - const power = String(denoms.length); - const numOp = power === "1" ? "\\partial" : `\\partial^${power}`; - let denominator = ""; - denoms.map(e => { denominator += "\\partial " + e.trim() + "\\,";}); - return [numerator, numOp, denominator.replace(/\\,$/, "")] - }; - defineMacro("\\pdv@numerator", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp} ${numerator}}{${denominator}}` - }); - defineMacro("\\pdv@next", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp}}{${denominator}} ${numerator}` - }); - - ////////////////////////////////////////////////////////////////////// - // upgreek.dtx - defineMacro("\\upalpha", "\\up@greek{\\alpha}"); - defineMacro("\\upbeta", "\\up@greek{\\beta}"); - defineMacro("\\upgamma", "\\up@greek{\\gamma}"); - defineMacro("\\updelta", "\\up@greek{\\delta}"); - defineMacro("\\upepsilon", "\\up@greek{\\epsilon}"); - defineMacro("\\upzeta", "\\up@greek{\\zeta}"); - defineMacro("\\upeta", "\\up@greek{\\eta}"); - defineMacro("\\uptheta", "\\up@greek{\\theta}"); - defineMacro("\\upiota", "\\up@greek{\\iota}"); - defineMacro("\\upkappa", "\\up@greek{\\kappa}"); - defineMacro("\\uplambda", "\\up@greek{\\lambda}"); - defineMacro("\\upmu", "\\up@greek{\\mu}"); - defineMacro("\\upnu", "\\up@greek{\\nu}"); - defineMacro("\\upxi", "\\up@greek{\\xi}"); - defineMacro("\\upomicron", "\\up@greek{\\omicron}"); - defineMacro("\\uppi", "\\up@greek{\\pi}"); - defineMacro("\\upalpha", "\\up@greek{\\alpha}"); - defineMacro("\\uprho", "\\up@greek{\\rho}"); - defineMacro("\\upsigma", "\\up@greek{\\sigma}"); - defineMacro("\\uptau", "\\up@greek{\\tau}"); - defineMacro("\\upupsilon", "\\up@greek{\\upsilon}"); - defineMacro("\\upphi", "\\up@greek{\\phi}"); - defineMacro("\\upchi", "\\up@greek{\\chi}"); - defineMacro("\\uppsi", "\\up@greek{\\psi}"); - defineMacro("\\upomega", "\\up@greek{\\omega}"); - - ////////////////////////////////////////////////////////////////////// - // cmll package - defineMacro("\\invamp", '\\mathbin{\\char"214b}'); - defineMacro("\\parr", '\\mathbin{\\char"214b}'); - defineMacro("\\with", '\\mathbin{\\char"26}'); - defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}'); - defineMacro("\\multimapboth", '\\mathrel{\\char"29df}'); - defineMacro("\\scoh", '{\\mkern5mu\\char"2322\\mkern5mu}'); - defineMacro("\\sincoh", '{\\mkern5mu\\char"2323\\mkern5mu}'); - defineMacro("\\coh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2322}}} -{\\smash{\\lower4mu{\\char"2323}}}\\mkern5mu}`); - defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2323}}} -{\\smash{\\lower4mu{\\char"2322}}}\\mkern5mu}`); - - - ////////////////////////////////////////////////////////////////////// - // chemstyle package - defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}"); - - /** - * This file contains the “gullet” where macros are expanded - * until only non-macro tokens remain. - */ - - // List of commands that act like macros but aren't defined as a macro, - // function, or symbol. Used in `isDefined`. - const implicitCommands = { - "^": true, // Parser.js - _: true, // Parser.js - "\\limits": true, // Parser.js - "\\nolimits": true // Parser.js - }; - - class MacroExpander { - constructor(input, settings, mode) { - this.settings = settings; - this.expansionCount = 0; - this.feed(input); - // Make new global namespace - this.macros = new Namespace(macros, settings.macros); - this.mode = mode; - this.stack = []; // contains tokens in REVERSE order - } - - /** - * Feed a new input string to the same MacroExpander - * (with existing macros etc.). - */ - feed(input) { - this.lexer = new Lexer(input, this.settings); - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - } - - /** - * Start a new group nesting within all namespaces. - */ - beginGroup() { - this.macros.beginGroup(); - } - - /** - * End current group nesting within all namespaces. - */ - endGroup() { - this.macros.endGroup(); - } - - /** - * Returns the topmost token on the stack, without expanding it. - * Similar in behavior to TeX's `\futurelet`. - */ - future() { - if (this.stack.length === 0) { - this.pushToken(this.lexer.lex()); - } - return this.stack[this.stack.length - 1] - } - - /** - * Remove and return the next unexpanded token. - */ - popToken() { - this.future(); // ensure non-empty stack - return this.stack.pop(); - } - - /** - * Add a given token to the token stack. In particular, this get be used - * to put back a token returned from one of the other methods. - */ - pushToken(token) { - this.stack.push(token); - } - - /** - * Append an array of tokens to the token stack. - */ - pushTokens(tokens) { - this.stack.push(...tokens); - } - - /** - * Find an macro argument without expanding tokens and append the array of - * tokens to the token stack. Uses Token as a container for the result. - */ - scanArgument(isOptional) { - let start; - let end; - let tokens; - if (isOptional) { - this.consumeSpaces(); // \@ifnextchar gobbles any space following it - if (this.future().text !== "[") { - return null; - } - start = this.popToken(); // don't include [ in tokens - ({ tokens, end } = this.consumeArg(["]"])); - } else { - ({ tokens, start, end } = this.consumeArg()); - } - - // indicate the end of an argument - this.pushToken(new Token("EOF", end.loc)); - - this.pushTokens(tokens); - return start.range(end, ""); - } - - /** - * Consume all following space tokens, without expansion. - */ - consumeSpaces() { - for (;;) { - const token = this.future(); - if (token.text === " ") { - this.stack.pop(); - } else { - break; - } - } - } - - /** - * Consume an argument from the token stream, and return the resulting array - * of tokens and start/end token. - */ - consumeArg(delims) { - // The argument for a delimited parameter is the shortest (possibly - // empty) sequence of tokens with properly nested {...} groups that is - // followed ... by this particular list of non-parameter tokens. - // The argument for an undelimited parameter is the next nonblank - // token, unless that token is ‘{’, when the argument will be the - // entire {...} group that follows. - const tokens = []; - const isDelimited = delims && delims.length > 0; - if (!isDelimited) { - // Ignore spaces between arguments. As the TeXbook says: - // "After you have said ‘\def\row#1#2{...}’, you are allowed to - // put spaces between the arguments (e.g., ‘\row x n’), because - // TeX doesn’t use single spaces as undelimited arguments." - this.consumeSpaces(); - } - const start = this.future(); - let tok; - let depth = 0; - let match = 0; - do { - tok = this.popToken(); - tokens.push(tok); - if (tok.text === "{") { - ++depth; - } else if (tok.text === "}") { - --depth; - if (depth === -1) { - throw new ParseError("Extra }", tok); - } - } else if (tok.text === "EOF") { - throw new ParseError( - "Unexpected end of input in a macro argument" + - ", expected '" + - (delims && isDelimited ? delims[match] : "}") + - "'", - tok - ); - } - if (delims && isDelimited) { - if ((depth === 0 || (depth === 1 && delims[match] === "{")) && tok.text === delims[match]) { - ++match; - if (match === delims.length) { - // don't include delims in tokens - tokens.splice(-match, match); - break; - } - } else { - match = 0; - } - } - } while (depth !== 0 || isDelimited); - // If the argument found ... has the form ‘{}’, - // ... the outermost braces enclosing the argument are removed - if (start.text === "{" && tokens[tokens.length - 1].text === "}") { - tokens.pop(); - tokens.shift(); - } - tokens.reverse(); // to fit in with stack order - return { tokens, start, end: tok }; - } - - /** - * Consume the specified number of (delimited) arguments from the token - * stream and return the resulting array of arguments. - */ - consumeArgs(numArgs, delimiters) { - if (delimiters) { - if (delimiters.length !== numArgs + 1) { - throw new ParseError("The length of delimiters doesn't match the number of args!"); - } - const delims = delimiters[0]; - for (let i = 0; i < delims.length; i++) { - const tok = this.popToken(); - if (delims[i] !== tok.text) { - throw new ParseError("Use of the macro doesn't match its definition", tok); - } - } - } - - const args = []; - for (let i = 0; i < numArgs; i++) { - args.push(this.consumeArg(delimiters && delimiters[i + 1]).tokens); - } - return args; - } - - /** - * Expand the next token only once if possible. - * - * If the token is expanded, the resulting tokens will be pushed onto - * the stack in reverse order and will be returned as an array, - * also in reverse order. - * - * If not, the next token will be returned without removing it - * from the stack. This case can be detected by a `Token` return value - * instead of an `Array` return value. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty. - * - * Used to implement `expandAfterFuture` and `expandNextToken`. - * - * If expandableOnly, only expandable tokens are expanded and - * an undefined control sequence results in an error. - */ - expandOnce(expandableOnly) { - const topToken = this.popToken(); - const name = topToken.text; - const expansion = !topToken.noexpand ? this._getExpansion(name) : null; - if (expansion == null || (expandableOnly && expansion.unexpandable)) { - if (expandableOnly && expansion == null && name[0] === "\\" && !this.isDefined(name)) { - throw new ParseError("Undefined control sequence: " + name); - } - this.pushToken(topToken); - return topToken; - } - this.expansionCount++; - if (this.expansionCount > this.settings.maxExpand) { - throw new ParseError( - "Too many expansions: infinite loop or " + "need to increase maxExpand setting" - ); - } - let tokens = expansion.tokens; - const args = this.consumeArgs(expansion.numArgs, expansion.delimiters); - if (expansion.numArgs) { - // paste arguments in place of the placeholders - tokens = tokens.slice(); // make a shallow copy - for (let i = tokens.length - 1; i >= 0; --i) { - let tok = tokens[i]; - if (tok.text === "#") { - if (i === 0) { - throw new ParseError("Incomplete placeholder at end of macro body", tok); - } - tok = tokens[--i]; // next token on stack - if (tok.text === "#") { - // ## → # - tokens.splice(i + 1, 1); // drop first # - } else if (/^[1-9]$/.test(tok.text)) { - // replace the placeholder with the indicated argument - tokens.splice(i, 2, ...args[+tok.text - 1]); - } else { - throw new ParseError("Not a valid argument number", tok); - } - } - } - } - // Concatenate expansion onto top of stack. - this.pushTokens(tokens); - return tokens; - } - - /** - * Expand the next token only once (if possible), and return the resulting - * top token on the stack (without removing anything from the stack). - * Similar in behavior to TeX's `\expandafter\futurelet`. - * Equivalent to expandOnce() followed by future(). - */ - expandAfterFuture() { - this.expandOnce(); - return this.future(); - } - - /** - * Recursively expand first token, then return first non-expandable token. - */ - expandNextToken() { - for (;;) { - const expanded = this.expandOnce(); - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (expanded.treatAsRelax) { - expanded.text = "\\relax"; - } - return this.stack.pop(); // === expanded - } - } - - // This pathway is impossible. - throw new Error(); // eslint-disable-line no-unreachable - } - - /** - * Fully expand the given macro name and return the resulting list of - * tokens, or return `undefined` if no such macro is defined. - */ - expandMacro(name) { - return this.macros.has(name) ? this.expandTokens([new Token(name)]) : undefined; - } - - /** - * Fully expand the given token stream and return the resulting list of - * tokens. Note that the input tokens are in reverse order, but the - * output tokens are in forward order. - */ - expandTokens(tokens) { - const output = []; - const oldStackLength = this.stack.length; - this.pushTokens(tokens); - while (this.stack.length > oldStackLength) { - const expanded = this.expandOnce(true); // expand only expandable tokens - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - if (expanded.treatAsRelax) { - // the expansion of \noexpand is the token itself - expanded.noexpand = false; - expanded.treatAsRelax = false; - } - output.push(this.stack.pop()); - } - } - return output; - } - - /** - * Fully expand the given macro name and return the result as a string, - * or return `undefined` if no such macro is defined. - */ - expandMacroAsText(name) { - const tokens = this.expandMacro(name); - if (tokens) { - return tokens.map((token) => token.text).join(""); - } else { - return tokens; - } - } - - /** - * Returns the expanded macro as a reversed array of tokens and a macro - * argument count. Or returns `null` if no such macro. - */ - _getExpansion(name) { - const definition = this.macros.get(name); - if (definition == null) { - // mainly checking for undefined here - return definition; - } - // If a single character has an associated catcode other than 13 - // (active character), then don't expand it. - if (name.length === 1) { - const catcode = this.lexer.catcodes[name]; - if (catcode != null && catcode !== 13) { - return - } - } - const expansion = typeof definition === "function" ? definition(this) : definition; - if (typeof expansion === "string") { - let numArgs = 0; - if (expansion.indexOf("#") !== -1) { - const stripped = expansion.replace(/##/g, ""); - while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { - ++numArgs; - } - } - const bodyLexer = new Lexer(expansion, this.settings); - const tokens = []; - let tok = bodyLexer.lex(); - while (tok.text !== "EOF") { - tokens.push(tok); - tok = bodyLexer.lex(); - } - tokens.reverse(); // to fit in with stack using push and pop - const expanded = { tokens, numArgs }; - return expanded; - } - - return expansion; - } - - /** - * Determine whether a command is currently "defined" (has some - * functionality), meaning that it's a macro (in the current group), - * a function, a symbol, or one of the special commands listed in - * `implicitCommands`. - */ - isDefined(name) { - return ( - this.macros.has(name) || - Object.prototype.hasOwnProperty.call(functions, name ) || - Object.prototype.hasOwnProperty.call(symbols.math, name ) || - Object.prototype.hasOwnProperty.call(symbols.text, name ) || - Object.prototype.hasOwnProperty.call(implicitCommands, name ) - ); - } - - /** - * Determine whether a command is expandable. - */ - isExpandable(name) { - const macro = this.macros.get(name); - return macro != null - ? typeof macro === "string" || typeof macro === "function" || !macro.unexpandable - : Object.prototype.hasOwnProperty.call(functions, name ) && !functions[name].primitive; - } - } - - /* - * This file defines the Unicode scripts and script families that we - * support. To add new scripts or families, just add a new entry to the - * scriptData array below. Adding scripts to the scriptData array allows - * characters from that script to appear in \text{} environments. - */ - - /** - * Each script or script family has a name and an array of blocks. - * Each block is an array of two numbers which specify the start and - * end points (inclusive) of a block of Unicode codepoints. - - /** - * Unicode block data for the families of scripts we support in \text{}. - * Scripts only need to appear here if they do not have font metrics. - */ - const scriptData = [ - { - // Latin characters beyond the Latin-1 characters we have metrics for. - // Needed for Czech, Hungarian and Turkish text, for example. - name: "latin", - blocks: [ - [0x0100, 0x024f], // Latin Extended-A and Latin Extended-B - [0x0300, 0x036f] // Combining Diacritical marks - ] - }, - { - // The Cyrillic script used by Russian and related languages. - // A Cyrillic subset used to be supported as explicitly defined - // symbols in symbols.js - name: "cyrillic", - blocks: [[0x0400, 0x04ff]] - }, - { - // Armenian - name: "armenian", - blocks: [[0x0530, 0x058f]] - }, - { - // The Brahmic scripts of South and Southeast Asia - // Devanagari (0900–097F) - // Bengali (0980–09FF) - // Gurmukhi (0A00–0A7F) - // Gujarati (0A80–0AFF) - // Oriya (0B00–0B7F) - // Tamil (0B80–0BFF) - // Telugu (0C00–0C7F) - // Kannada (0C80–0CFF) - // Malayalam (0D00–0D7F) - // Sinhala (0D80–0DFF) - // Thai (0E00–0E7F) - // Lao (0E80–0EFF) - // Tibetan (0F00–0FFF) - // Myanmar (1000–109F) - name: "brahmic", - blocks: [[0x0900, 0x109f]] - }, - { - name: "georgian", - blocks: [[0x10a0, 0x10ff]] - }, - { - // Chinese and Japanese. - // The "k" in cjk is for Korean, but we've separated Korean out - name: "cjk", - blocks: [ - [0x3000, 0x30ff], // CJK symbols and punctuation, Hiragana, Katakana - [0x4e00, 0x9faf], // CJK ideograms - [0xff00, 0xff60] // Fullwidth punctuation - // TODO: add halfwidth Katakana and Romanji glyphs - ] - }, - { - // Korean - name: "hangul", - blocks: [[0xac00, 0xd7af]] - } - ]; - - /** - * A flattened version of all the supported blocks in a single array. - * This is an optimization to make supportedCodepoint() fast. - */ - const allBlocks = []; - scriptData.forEach((s) => s.blocks.forEach((b) => allBlocks.push(...b))); - - /** - * Given a codepoint, return true if it falls within one of the - * scripts or script families defined above and false otherwise. - * - * Micro benchmarks shows that this is faster than - * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() - * in Firefox, Chrome and Node. - */ - function supportedCodepoint(codepoint) { - for (let i = 0; i < allBlocks.length; i += 2) { - if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { - return true; - } - } - return false; - } - - // Helpers for Parser.js handling of Unicode (sub|super)script characters. - - const unicodeSubRegEx = /^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/; - - const uSubsAndSups = Object.freeze({ - '₊': '+', - '₋': '-', - '₌': '=', - '₍': '(', - '₎': ')', - '₀': '0', - '₁': '1', - '₂': '2', - '₃': '3', - '₄': '4', - '₅': '5', - '₆': '6', - '₇': '7', - '₈': '8', - '₉': '9', - '\u2090': 'a', - '\u2091': 'e', - '\u2095': 'h', - '\u1D62': 'i', - '\u2C7C': 'j', - '\u2096': 'k', - '\u2097': 'l', - '\u2098': 'm', - '\u2099': 'n', - '\u2092': 'o', - '\u209A': 'p', - '\u1D63': 'r', - '\u209B': 's', - '\u209C': 't', - '\u1D64': 'u', - '\u1D65': 'v', - '\u2093': 'x', - '\u1D66': 'β', - '\u1D67': 'γ', - '\u1D68': 'ρ', - '\u1D69': '\u03d5', - '\u1D6A': 'χ', - '⁺': '+', - '⁻': '-', - '⁼': '=', - '⁽': '(', - '⁾': ')', - '⁰': '0', - '¹': '1', - '²': '2', - '³': '3', - '⁴': '4', - '⁵': '5', - '⁶': '6', - '⁷': '7', - '⁸': '8', - '⁹': '9', - '\u1D2C': 'A', - '\u1D2E': 'B', - '\u1D30': 'D', - '\u1D31': 'E', - '\u1D33': 'G', - '\u1D34': 'H', - '\u1D35': 'I', - '\u1D36': 'J', - '\u1D37': 'K', - '\u1D38': 'L', - '\u1D39': 'M', - '\u1D3A': 'N', - '\u1D3C': 'O', - '\u1D3E': 'P', - '\u1D3F': 'R', - '\u1D40': 'T', - '\u1D41': 'U', - '\u2C7D': 'V', - '\u1D42': 'W', - '\u1D43': 'a', - '\u1D47': 'b', - '\u1D9C': 'c', - '\u1D48': 'd', - '\u1D49': 'e', - '\u1DA0': 'f', - '\u1D4D': 'g', - '\u02B0': 'h', - '\u2071': 'i', - '\u02B2': 'j', - '\u1D4F': 'k', - '\u02E1': 'l', - '\u1D50': 'm', - '\u207F': 'n', - '\u1D52': 'o', - '\u1D56': 'p', - '\u02B3': 'r', - '\u02E2': 's', - '\u1D57': 't', - '\u1D58': 'u', - '\u1D5B': 'v', - '\u02B7': 'w', - '\u02E3': 'x', - '\u02B8': 'y', - '\u1DBB': 'z', - '\u1D5D': 'β', - '\u1D5E': 'γ', - '\u1D5F': 'δ', - '\u1D60': '\u03d5', - '\u1D61': 'χ', - '\u1DBF': 'θ' - }); - - // Mapping of Unicode accent characters to their LaTeX equivalent in text and - // math mode (when they exist). - var unicodeAccents = { - "\u0301": { text: "\\'", math: "\\acute" }, - "\u0300": { text: "\\`", math: "\\grave" }, - "\u0308": { text: '\\"', math: "\\ddot" }, - "\u0303": { text: "\\~", math: "\\tilde" }, - "\u0304": { text: "\\=", math: "\\bar" }, - "\u0306": { text: "\\u", math: "\\breve" }, - "\u030c": { text: "\\v", math: "\\check" }, - "\u0302": { text: "\\^", math: "\\hat" }, - "\u0307": { text: "\\.", math: "\\dot" }, - "\u030a": { text: "\\r", math: "\\mathring" }, - "\u030b": { text: "\\H" }, - '\u0327': { text: '\\c' } - }; - - var unicodeSymbols = { - "á": "á", - "à": "à", - "ä": "ä", - "ǟ": "ǟ", - "ã": "ã", - "ā": "ā", - "ă": "ă", - "ắ": "ắ", - "ằ": "ằ", - "ẵ": "ẵ", - "ǎ": "ǎ", - "â": "â", - "ấ": "ấ", - "ầ": "ầ", - "ẫ": "ẫ", - "ȧ": "ȧ", - "ǡ": "ǡ", - "å": "å", - "ǻ": "ǻ", - "ḃ": "ḃ", - "ć": "ć", - "č": "č", - "ĉ": "ĉ", - "ċ": "ċ", - "ď": "ď", - "ḋ": "ḋ", - "é": "é", - "è": "è", - "ë": "ë", - "ẽ": "ẽ", - "ē": "ē", - "ḗ": "ḗ", - "ḕ": "ḕ", - "ĕ": "ĕ", - "ě": "ě", - "ê": "ê", - "ế": "ế", - "ề": "ề", - "ễ": "ễ", - "ė": "ė", - "ḟ": "ḟ", - "ǵ": "ǵ", - "ḡ": "ḡ", - "ğ": "ğ", - "ǧ": "ǧ", - "ĝ": "ĝ", - "ġ": "ġ", - "ḧ": "ḧ", - "ȟ": "ȟ", - "ĥ": "ĥ", - "ḣ": "ḣ", - "í": "í", - "ì": "ì", - "ï": "ï", - "ḯ": "ḯ", - "ĩ": "ĩ", - "ī": "ī", - "ĭ": "ĭ", - "ǐ": "ǐ", - "î": "î", - "ǰ": "ǰ", - "ĵ": "ĵ", - "ḱ": "ḱ", - "ǩ": "ǩ", - "ĺ": "ĺ", - "ľ": "ľ", - "ḿ": "ḿ", - "ṁ": "ṁ", - "ń": "ń", - "ǹ": "ǹ", - "ñ": "ñ", - "ň": "ň", - "ṅ": "ṅ", - "ó": "ó", - "ò": "ò", - "ö": "ö", - "ȫ": "ȫ", - "õ": "õ", - "ṍ": "ṍ", - "ṏ": "ṏ", - "ȭ": "ȭ", - "ō": "ō", - "ṓ": "ṓ", - "ṑ": "ṑ", - "ŏ": "ŏ", - "ǒ": "ǒ", - "ô": "ô", - "ố": "ố", - "ồ": "ồ", - "ỗ": "ỗ", - "ȯ": "ȯ", - "ȱ": "ȱ", - "ő": "ő", - "ṕ": "ṕ", - "ṗ": "ṗ", - "ŕ": "ŕ", - "ř": "ř", - "ṙ": "ṙ", - "ś": "ś", - "ṥ": "ṥ", - "š": "š", - "ṧ": "ṧ", - "ŝ": "ŝ", - "ṡ": "ṡ", - "ẗ": "ẗ", - "ť": "ť", - "ṫ": "ṫ", - "ú": "ú", - "ù": "ù", - "ü": "ü", - "ǘ": "ǘ", - "ǜ": "ǜ", - "ǖ": "ǖ", - "ǚ": "ǚ", - "ũ": "ũ", - "ṹ": "ṹ", - "ū": "ū", - "ṻ": "ṻ", - "ŭ": "ŭ", - "ǔ": "ǔ", - "û": "û", - "ů": "ů", - "ű": "ű", - "ṽ": "ṽ", - "ẃ": "ẃ", - "ẁ": "ẁ", - "ẅ": "ẅ", - "ŵ": "ŵ", - "ẇ": "ẇ", - "ẘ": "ẘ", - "ẍ": "ẍ", - "ẋ": "ẋ", - "ý": "ý", - "ỳ": "ỳ", - "ÿ": "ÿ", - "ỹ": "ỹ", - "ȳ": "ȳ", - "ŷ": "ŷ", - "ẏ": "ẏ", - "ẙ": "ẙ", - "ź": "ź", - "ž": "ž", - "ẑ": "ẑ", - "ż": "ż", - "Á": "Á", - "À": "À", - "Ä": "Ä", - "Ǟ": "Ǟ", - "Ã": "Ã", - "Ā": "Ā", - "Ă": "Ă", - "Ắ": "Ắ", - "Ằ": "Ằ", - "Ẵ": "Ẵ", - "Ǎ": "Ǎ", - "Â": "Â", - "Ấ": "Ấ", - "Ầ": "Ầ", - "Ẫ": "Ẫ", - "Ȧ": "Ȧ", - "Ǡ": "Ǡ", - "Å": "Å", - "Ǻ": "Ǻ", - "Ḃ": "Ḃ", - "Ć": "Ć", - "Č": "Č", - "Ĉ": "Ĉ", - "Ċ": "Ċ", - "Ď": "Ď", - "Ḋ": "Ḋ", - "É": "É", - "È": "È", - "Ë": "Ë", - "Ẽ": "Ẽ", - "Ē": "Ē", - "Ḗ": "Ḗ", - "Ḕ": "Ḕ", - "Ĕ": "Ĕ", - "Ě": "Ě", - "Ê": "Ê", - "Ế": "Ế", - "Ề": "Ề", - "Ễ": "Ễ", - "Ė": "Ė", - "Ḟ": "Ḟ", - "Ǵ": "Ǵ", - "Ḡ": "Ḡ", - "Ğ": "Ğ", - "Ǧ": "Ǧ", - "Ĝ": "Ĝ", - "Ġ": "Ġ", - "Ḧ": "Ḧ", - "Ȟ": "Ȟ", - "Ĥ": "Ĥ", - "Ḣ": "Ḣ", - "Í": "Í", - "Ì": "Ì", - "Ï": "Ï", - "Ḯ": "Ḯ", - "Ĩ": "Ĩ", - "Ī": "Ī", - "Ĭ": "Ĭ", - "Ǐ": "Ǐ", - "Î": "Î", - "İ": "İ", - "Ĵ": "Ĵ", - "Ḱ": "Ḱ", - "Ǩ": "Ǩ", - "Ĺ": "Ĺ", - "Ľ": "Ľ", - "Ḿ": "Ḿ", - "Ṁ": "Ṁ", - "Ń": "Ń", - "Ǹ": "Ǹ", - "Ñ": "Ñ", - "Ň": "Ň", - "Ṅ": "Ṅ", - "Ó": "Ó", - "Ò": "Ò", - "Ö": "Ö", - "Ȫ": "Ȫ", - "Õ": "Õ", - "Ṍ": "Ṍ", - "Ṏ": "Ṏ", - "Ȭ": "Ȭ", - "Ō": "Ō", - "Ṓ": "Ṓ", - "Ṑ": "Ṑ", - "Ŏ": "Ŏ", - "Ǒ": "Ǒ", - "Ô": "Ô", - "Ố": "Ố", - "Ồ": "Ồ", - "Ỗ": "Ỗ", - "Ȯ": "Ȯ", - "Ȱ": "Ȱ", - "Ő": "Ő", - "Ṕ": "Ṕ", - "Ṗ": "Ṗ", - "Ŕ": "Ŕ", - "Ř": "Ř", - "Ṙ": "Ṙ", - "Ś": "Ś", - "Ṥ": "Ṥ", - "Š": "Š", - "Ṧ": "Ṧ", - "Ŝ": "Ŝ", - "Ṡ": "Ṡ", - "Ť": "Ť", - "Ṫ": "Ṫ", - "Ú": "Ú", - "Ù": "Ù", - "Ü": "Ü", - "Ǘ": "Ǘ", - "Ǜ": "Ǜ", - "Ǖ": "Ǖ", - "Ǚ": "Ǚ", - "Ũ": "Ũ", - "Ṹ": "Ṹ", - "Ū": "Ū", - "Ṻ": "Ṻ", - "Ŭ": "Ŭ", - "Ǔ": "Ǔ", - "Û": "Û", - "Ů": "Ů", - "Ű": "Ű", - "Ṽ": "Ṽ", - "Ẃ": "Ẃ", - "Ẁ": "Ẁ", - "Ẅ": "Ẅ", - "Ŵ": "Ŵ", - "Ẇ": "Ẇ", - "Ẍ": "Ẍ", - "Ẋ": "Ẋ", - "Ý": "Ý", - "Ỳ": "Ỳ", - "Ÿ": "Ÿ", - "Ỹ": "Ỹ", - "Ȳ": "Ȳ", - "Ŷ": "Ŷ", - "Ẏ": "Ẏ", - "Ź": "Ź", - "Ž": "Ž", - "Ẑ": "Ẑ", - "Ż": "Ż", - "ά": "ά", - "ὰ": "ὰ", - "ᾱ": "ᾱ", - "ᾰ": "ᾰ", - "έ": "έ", - "ὲ": "ὲ", - "ή": "ή", - "ὴ": "ὴ", - "ί": "ί", - "ὶ": "ὶ", - "ϊ": "ϊ", - "ΐ": "ΐ", - "ῒ": "ῒ", - "ῑ": "ῑ", - "ῐ": "ῐ", - "ό": "ό", - "ὸ": "ὸ", - "ύ": "ύ", - "ὺ": "ὺ", - "ϋ": "ϋ", - "ΰ": "ΰ", - "ῢ": "ῢ", - "ῡ": "ῡ", - "ῠ": "ῠ", - "ώ": "ώ", - "ὼ": "ὼ", - "Ύ": "Ύ", - "Ὺ": "Ὺ", - "Ϋ": "Ϋ", - "Ῡ": "Ῡ", - "Ῠ": "Ῠ", - "Ώ": "Ώ", - "Ὼ": "Ὼ" - }; - - /* eslint no-constant-condition:0 */ - - const numberRegEx = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in symbolsOrd.js - - /** - * This file contains the parser used to parse out a TeX expression from the - * input. Since TeX isn't context-free, standard parsers don't work particularly - * well. - * - * The strategy of this parser is as such: - * - * The main functions (the `.parse...` ones) take a position in the current - * parse string to parse tokens from. The lexer (found in Lexer.js, stored at - * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When - * individual tokens are needed at a position, the lexer is called to pull out a - * token, which is then used. - * - * The parser has a property called "mode" indicating the mode that - * the parser is currently in. Currently it has to be one of "math" or - * "text", which denotes whether the current environment is a math-y - * one or a text-y one (e.g. inside \text). Currently, this serves to - * limit the functions which can be used in text mode. - * - * The main functions then return an object which contains the useful data that - * was parsed at its given point, and a new position at the end of the parsed - * data. The main functions can call each other and continue the parsing by - * using the returned position as a new starting point. - * - * There are also extra `.handle...` functions, which pull out some reused - * functionality into self-contained functions. - * - * The functions return ParseNodes. - */ - - class Parser { - constructor(input, settings, isPreamble = false) { - // Start in math mode - this.mode = "math"; - // Create a new macro expander (gullet) and (indirectly via that) also a - // new lexer (mouth) for this parser (stomach, in the language of TeX) - this.gullet = new MacroExpander(input, settings, this.mode); - // Store the settings for use in parsing - this.settings = settings; - // Are we defining a preamble? - this.isPreamble = isPreamble; - // Count leftright depth (for \middle errors) - this.leftrightDepth = 0; - this.prevAtomType = ""; - } - - /** - * Checks a result to make sure it has the right type, and throws an - * appropriate error otherwise. - */ - expect(text, consume = true) { - if (this.fetch().text !== text) { - throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); - } - if (consume) { - this.consume(); - } - } - - /** - * Discards the current lookahead token, considering it consumed. - */ - consume() { - this.nextToken = null; - } - - /** - * Return the current lookahead token, or if there isn't one (at the - * beginning, or if the previous lookahead token was consume()d), - * fetch the next token as the new lookahead token and return it. - */ - fetch() { - if (this.nextToken == null) { - this.nextToken = this.gullet.expandNextToken(); - } - return this.nextToken; - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - this.gullet.switchMode(newMode); - } - - /** - * Main parsing function, which parses an entire input. - */ - parse() { - // Create a group namespace for every $...$, $$...$$, \[...\].) - // A \def is then valid only within that pair of delimiters. - this.gullet.beginGroup(); - - if (this.settings.colorIsTextColor) { - // Use old \color behavior (same as LaTeX's \textcolor) if requested. - // We do this within the group for the math expression, so it doesn't - // pollute settings.macros. - this.gullet.macros.set("\\color", "\\textcolor"); - } - - // Try to parse the input - const parse = this.parseExpression(false); - - // If we succeeded, make sure there's an EOF at the end - this.expect("EOF"); - - if (this.isPreamble) { - const macros = Object.create(null); - Object.entries(this.gullet.macros.current).forEach(([key, value]) => { - macros[key] = value; - }); - this.gullet.endGroup(); - return macros - } - - // The only local macro that we want to save is from \tag. - const tag = this.gullet.macros.get("\\df@tag"); - - // End the group namespace for the expression - this.gullet.endGroup(); - - if (tag) { this.gullet.macros.current["\\df@tag"] = tag; } - - return parse; - } - - static get endOfExpression() { - return ["}", "\\endgroup", "\\end", "\\right", "\\endtoggle", "&"]; - } - - /** - * Parses an "expression", which is a list of atoms. - * - * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This - * happens when functions have higher precendence han infix - * nodes in implicit parses. - * - * `breakOnTokenText`: The text of the token that the expression should end - * with, or `null` if something else should end the - * expression. - */ - parseExpression(breakOnInfix, breakOnTokenText) { - const body = []; - // Keep adding atoms to the body until we can't parse any more atoms (either - // we reached the end, a }, or a \right) - while (true) { - // Ignore spaces in math mode - if (this.mode === "math") { - this.consumeSpaces(); - } - const lex = this.fetch(); - if (Parser.endOfExpression.indexOf(lex.text) !== -1) { - break; - } - if (breakOnTokenText && lex.text === breakOnTokenText) { - break; - } - if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { - break; - } - const atom = this.parseAtom(breakOnTokenText); - if (!atom) { - break; - } else if (atom.type === "internal") { - continue; - } - body.push(atom); - // Keep a record of the atom type, so that op.js can set correct spacing. - this.prevAtomType = atom.type === "atom" ? atom.family : atom.type; - } - if (this.mode === "text") { - this.formLigatures(body); - } - return this.handleInfixNodes(body); - } - - /** - * Rewrites infix operators such as \over with corresponding commands such - * as \frac. - * - * There can only be one infix operator per group. If there's more than one - * then the expression is ambiguous. This can be resolved by adding {}. - */ - handleInfixNodes(body) { - let overIndex = -1; - let funcName; - - for (let i = 0; i < body.length; i++) { - if (body[i].type === "infix") { - if (overIndex !== -1) { - throw new ParseError("only one infix operator per group", body[i].token); - } - overIndex = i; - funcName = body[i].replaceWith; - } - } - - if (overIndex !== -1 && funcName) { - let numerNode; - let denomNode; - - const numerBody = body.slice(0, overIndex); - const denomBody = body.slice(overIndex + 1); - - if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { - numerNode = numerBody[0]; - } else { - numerNode = { type: "ordgroup", mode: this.mode, body: numerBody }; - } - - if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { - denomNode = denomBody[0]; - } else { - denomNode = { type: "ordgroup", mode: this.mode, body: denomBody }; - } - - let node; - if (funcName === "\\\\abovefrac") { - node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); - } else { - node = this.callFunction(funcName, [numerNode, denomNode], []); - } - return [node]; - } else { - return body; - } - } - - /** - * Handle a subscript or superscript with nice errors. - */ - handleSupSubscript( - name // For error reporting. - ) { - const symbolToken = this.fetch(); - const symbol = symbolToken.text; - this.consume(); - this.consumeSpaces(); // ignore spaces before sup/subscript argument - const group = this.parseGroup(name); - - if (!group) { - throw new ParseError("Expected group after '" + symbol + "'", symbolToken); - } - - return group; - } - - /** - * Converts the textual input of an unsupported command into a text node - * contained within a color node whose color is determined by errorColor - */ - formatUnsupportedCmd(text) { - const textordArray = []; - - for (let i = 0; i < text.length; i++) { - textordArray.push({ type: "textord", mode: "text", text: text[i] }); - } - - const textNode = { - type: "text", - mode: this.mode, - body: textordArray - }; - - const colorNode = { - type: "color", - mode: this.mode, - color: this.settings.errorColor, - body: [textNode] - }; - - return colorNode; - } - - /** - * Parses a group with optional super/subscripts. - */ - parseAtom(breakOnTokenText) { - // The body of an atom is an implicit group, so that things like - // \left(x\right)^2 work correctly. - const base = this.parseGroup("atom", breakOnTokenText); - - // In text mode, we don't have superscripts or subscripts - if (this.mode === "text") { - return base; - } - - // Note that base may be empty (i.e. null) at this point. - - let superscript; - let subscript; - while (true) { - // Guaranteed in math mode, so eat any spaces first. - this.consumeSpaces(); - - // Lex the first token - const lex = this.fetch(); - - if (lex.text === "\\limits" || lex.text === "\\nolimits") { - // We got a limit control - if (base && base.type === "op") { - const limits = lex.text === "\\limits"; - base.limits = limits; - base.alwaysHandleSupSub = true; - } else if (base && base.type === "operatorname") { - if (base.alwaysHandleSupSub) { - base.limits = lex.text === "\\limits"; - } - } else { - throw new ParseError("Limit controls must follow a math operator", lex); - } - this.consume(); - } else if (lex.text === "^") { - // We got a superscript start - if (superscript) { - throw new ParseError("Double superscript", lex); - } - superscript = this.handleSupSubscript("superscript"); - } else if (lex.text === "_") { - // We got a subscript start - if (subscript) { - throw new ParseError("Double subscript", lex); - } - subscript = this.handleSupSubscript("subscript"); - } else if (lex.text === "'") { - // We got a prime - if (superscript) { - throw new ParseError("Double superscript", lex); - } - const prime = { type: "textord", mode: this.mode, text: "\\prime" }; - - // Many primes can be grouped together, so we handle this here - const primes = [prime]; - this.consume(); - // Keep lexing tokens until we get something that's not a prime - while (this.fetch().text === "'") { - // For each one, add another prime to the list - primes.push(prime); - this.consume(); - } - // If there's a superscript following the primes, combine that - // superscript in with the primes. - if (this.fetch().text === "^") { - primes.push(this.handleSupSubscript("superscript")); - } - // Put everything into an ordgroup as the superscript - superscript = { type: "ordgroup", mode: this.mode, body: primes }; - } else if (uSubsAndSups[lex.text]) { - // A Unicode subscript or superscript character. - // We treat these similarly to the unicode-math package. - // So we render a string of Unicode (sub|super)scripts the - // same as a (sub|super)script of regular characters. - let str = uSubsAndSups[lex.text]; - const isSub = unicodeSubRegEx.test(lex.text); - this.consume(); - // Continue fetching tokens to fill out the string. - while (true) { - const token = this.fetch().text; - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - this.consume(); - str += uSubsAndSups[token]; - } - // Now create a (sub|super)script. - const body = (new Parser(str, this.settings)).parse(); - if (isSub) { - subscript = { type: "ordgroup", mode: "math", body }; - } else { - superscript = { type: "ordgroup", mode: "math", body }; - } - } else { - // If it wasn't ^, _, a Unicode (sub|super)script, or ', stop parsing super/subscripts - break; - } - } - - if (superscript || subscript) { - if (base && base.type === "multiscript" && !base.postscripts) { - // base is the result of a \prescript function. - // Write the sub- & superscripts into the multiscript element. - base.postscripts = { sup: superscript, sub: subscript }; - return base - } else { - // We got either a superscript or subscript, create a supsub - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript - } - } - } else { - // Otherwise return the original body - return base; - } - } - - /** - * Parses an entire function, including its base and all of its arguments. - */ - parseFunction( - breakOnTokenText, - name // For determining its context - ) { - const token = this.fetch(); - const func = token.text; - const funcData = functions[func]; - if (!funcData) { - return null; - } - this.consume(); // consume command token - - if (name && name !== "atom" && !funcData.allowedInArgument) { - throw new ParseError( - "Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), - token - ); - } else if (this.mode === "text" && !funcData.allowedInText) { - throw new ParseError("Can't use function '" + func + "' in text mode", token); - } else if (this.mode === "math" && funcData.allowedInMath === false) { - throw new ParseError("Can't use function '" + func + "' in math mode", token); - } - - const prevAtomType = this.prevAtomType; - const { args, optArgs } = this.parseArguments(func, funcData); - this.prevAtomType = prevAtomType; - return this.callFunction(func, args, optArgs, token, breakOnTokenText); - } - - /** - * Call a function handler with a suitable context and arguments. - */ - callFunction(name, args, optArgs, token, breakOnTokenText) { - const context = { - funcName: name, - parser: this, - token, - breakOnTokenText - }; - const func = functions[name]; - if (func && func.handler) { - return func.handler(context, args, optArgs); - } else { - throw new ParseError(`No function handler for ${name}`); - } - } - - /** - * Parses the arguments of a function or environment - */ - parseArguments( - func, // Should look like "\name" or "\begin{name}". - funcData - ) { - const totalArgs = funcData.numArgs + funcData.numOptionalArgs; - if (totalArgs === 0) { - return { args: [], optArgs: [] }; - } - - const args = []; - const optArgs = []; - - for (let i = 0; i < totalArgs; i++) { - let argType = funcData.argTypes && funcData.argTypes[i]; - const isOptional = i < funcData.numOptionalArgs; - - if ( - (funcData.primitive && argType == null) || - // \sqrt expands into primitive if optional argument doesn't exist - (funcData.type === "sqrt" && i === 1 && optArgs[0] == null) - ) { - argType = "primitive"; - } - - const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional); - if (isOptional) { - optArgs.push(arg); - } else if (arg != null) { - args.push(arg); - } else { - // should be unreachable - throw new ParseError("Null argument, please report this as a bug"); - } - } - - return { args, optArgs }; - } - - /** - * Parses a group when the mode is changing. - */ - parseGroupOfType(name, type, optional) { - switch (type) { - case "size": - return this.parseSizeGroup(optional); - case "url": - return this.parseUrlGroup(optional); - case "math": - case "text": - return this.parseArgumentGroup(optional, type); - case "hbox": { - // hbox argument type wraps the argument in the equivalent of - // \hbox, which is like \text but switching to \textstyle size. - const group = this.parseArgumentGroup(optional, "text"); - return group != null - ? { - type: "styling", - mode: group.mode, - body: [group], - scriptLevel: "text" // simulate \textstyle - } - : null; - } - case "raw": { - const token = this.parseStringGroup("raw", optional); - return token != null - ? { - type: "raw", - mode: "text", - string: token.text - } - : null; - } - case "primitive": { - if (optional) { - throw new ParseError("A primitive argument cannot be optional"); - } - const group = this.parseGroup(name); - if (group == null) { - throw new ParseError("Expected group as " + name, this.fetch()); - } - return group; - } - case "original": - case null: - case undefined: - return this.parseArgumentGroup(optional); - default: - throw new ParseError("Unknown group type as " + name, this.fetch()); - } - } - - /** - * Discard any space tokens, fetching the next non-space token. - */ - consumeSpaces() { - while (this.fetch().text === " ") { - this.consume(); - } - } - - /** - * Parses a group, essentially returning the string formed by the - * brace-enclosed tokens plus some position information. - */ - parseStringGroup( - modeName, // Used to describe the mode in error messages. - optional - ) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF") { - str += nextToken.text; - this.consume(); - } - this.consume(); // consume the end of the argument - argToken.text = str; - return argToken; - } - - /** - * Parses a regex-delimited group: the largest sequence of tokens - * whose concatenated strings match `regex`. Returns the string - * formed by the tokens plus some position information. - */ - parseRegexGroup( - regex, - modeName // Used to describe the mode in error messages. - ) { - const firstToken = this.fetch(); - let lastToken = firstToken; - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { - lastToken = nextToken; - str += lastToken.text; - this.consume(); - } - if (str === "") { - throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); - } - return firstToken.range(lastToken, str); - } - - /** - * Parses a size specification, consisting of magnitude and unit. - */ - parseSizeGroup(optional) { - let res; - let isBlank = false; - // don't expand before parseStringGroup - this.gullet.consumeSpaces(); - if (!optional && this.gullet.future().text !== "{") { - res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); - } else { - res = this.parseStringGroup("size", optional); - } - if (!res) { - return null; - } - if (!optional && res.text.length === 0) { - // Because we've tested for what is !optional, this block won't - // affect \kern, \hspace, etc. It will capture the mandatory arguments - // to \genfrac and \above. - res.text = "0pt"; // Enable \above{} - isBlank = true; // This is here specifically for \genfrac - } - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); - if (!match) { - throw new ParseError("Invalid size: '" + res.text + "'", res); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "'", res); - } - return { - type: "size", - mode: this.mode, - value: data, - isBlank - }; - } - - /** - * Parses an URL, checking escaped letters and allowed protocols, - * and setting the catcode of % as an active character (as in \hyperref). - */ - parseUrlGroup(optional) { - this.gullet.lexer.setCatcode("%", 13); // active character - this.gullet.lexer.setCatcode("~", 12); // other character - const res = this.parseStringGroup("url", optional); - this.gullet.lexer.setCatcode("%", 14); // comment character - this.gullet.lexer.setCatcode("~", 13); // active character - if (res == null) { - return null; - } - // hyperref package allows backslashes alone in href, but doesn't - // generate valid links in such cases; we interpret this as - // "undefined" behaviour, and keep them as-is. Some browser will - // replace backslashes with forward slashes. - let url = res.text.replace(/\\([#$%&~_^{}])/g, "$1"); - url = res.text.replace(/{\u2044}/g, "/"); - return { - type: "url", - mode: this.mode, - url - }; - } - - /** - * Parses an argument with the mode specified. - */ - parseArgumentGroup(optional, mode) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - const outerMode = this.mode; - if (mode) { - // Switch to specified mode - this.switchMode(mode); - } - - this.gullet.beginGroup(); - const expression = this.parseExpression(false, "EOF"); - // TODO: find an alternative way to denote the end - this.expect("EOF"); // expect the end of the argument - this.gullet.endGroup(); - const result = { - type: "ordgroup", - mode: this.mode, - loc: argToken.loc, - body: expression - }; - - if (mode) { - // Switch mode back - this.switchMode(outerMode); - } - return result; - } - - /** - * Parses an ordinary group, which is either a single nucleus (like "x") - * or an expression in braces (like "{x+y}") or an implicit group, a group - * that starts at the current position, and ends right before a higher explicit - * group ends, or at EOF. - */ - parseGroup( - name, // For error reporting. - breakOnTokenText - ) { - const firstToken = this.fetch(); - const text = firstToken.text; - - let result; - // Try to parse an open brace or \begingroup - if (text === "{" || text === "\\begingroup" || text === "\\toggle") { - this.consume(); - const groupEnd = text === "{" - ? "}" - : text === "\\begingroup" - ? "\\endgroup" - : "\\endtoggle"; - - this.gullet.beginGroup(); - // If we get a brace, parse an expression - const expression = this.parseExpression(false, groupEnd); - const lastToken = this.fetch(); - this.expect(groupEnd); // Check that we got a matching closing brace - this.gullet.endGroup(); - result = { - type: (lastToken.text === "\\endtoggle" ? "toggle" : "ordgroup"), - mode: this.mode, - loc: SourceLocation.range(firstToken, lastToken), - body: expression, - // A group formed by \begingroup...\endgroup is a semi-simple group - // which doesn't affect spacing in math mode, i.e., is transparent. - // https://tex.stackexchange.com/questions/1930/when-should-one- - // use-begingroup-instead-of-bgroup - semisimple: text === "\\begingroup" || undefined - }; - } else { - // If there exists a function with this name, parse the function. - // Otherwise, just return a nucleus - result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol(); - if (result == null && text[0] === "\\" && - !Object.prototype.hasOwnProperty.call(implicitCommands, text )) { - result = this.formatUnsupportedCmd(text); - this.consume(); - } - } - return result; - } - - /** - * Form ligature-like combinations of characters for text mode. - * This includes inputs like "--", "---", "``" and "''". - * The result will simply replace multiple textord nodes with a single - * character in each value by a single textord node having multiple - * characters in its value. The representation is still ASCII source. - * The group will be modified in place. - */ - formLigatures(group) { - let n = group.length - 1; - for (let i = 0; i < n; ++i) { - const a = group[i]; - const v = a.text; - if (v === "-" && group[i + 1].text === "-") { - if (i + 1 < n && group[i + 2].text === "-") { - group.splice(i, 3, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 2]), - text: "---" - }); - n -= 2; - } else { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: "--" - }); - n -= 1; - } - } - if ((v === "'" || v === "`") && group[i + 1].text === v) { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: v + v - }); - n -= 1; - } - } - } - - /** - * Parse a single symbol out of the string. Here, we handle single character - * symbols and special functions like \verb. - */ - parseSymbol() { - const nucleus = this.fetch(); - let text = nucleus.text; - - if (/^\\verb[^a-zA-Z]/.test(text)) { - this.consume(); - let arg = text.slice(5); - const star = arg.charAt(0) === "*"; - if (star) { - arg = arg.slice(1); - } - // Lexer's tokenRegex is constructed to always have matching - // first/last characters. - if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { - throw new ParseError(`\\verb assertion failed -- - please report what input caused this bug`); - } - arg = arg.slice(1, -1); // remove first and last char - return { - type: "verb", - mode: "text", - body: arg, - star - }; - } - // At this point, we should have a symbol, possibly with accents. - // First expand any accented base symbol according to unicodeSymbols. - if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0]) && - !symbols[this.mode][text[0]]) { - // This behavior is not strict (XeTeX-compatible) in math mode. - if (this.settings.strict && this.mode === "math") { - throw new ParseError(`Accented Unicode text character "${text[0]}" used in ` + `math mode`, - nucleus - ); - } - text = unicodeSymbols[text[0]] + text.slice(1); - } - // Strip off any combining characters - const match = combiningDiacriticalMarksEndRegex.exec(text); - if (match) { - text = text.substring(0, match.index); - if (text === "i") { - text = "\u0131"; // dotless i, in math and text mode - } else if (text === "j") { - text = "\u0237"; // dotless j, in math and text mode - } - } - // Recognize base symbol - let symbol; - if (symbols[this.mode][text]) { - const group = symbols[this.mode][text].group; - const loc = SourceLocation.range(nucleus); - let s; - if (Object.prototype.hasOwnProperty.call(ATOMS, group )) { - const family = group; - s = { - type: "atom", - mode: this.mode, - family, - loc, - text - }; - } else { - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (!this.strict && numberRegEx.test(text)) { - // A number. Wrap in a if in math mode; otherwise. - this.consume(); - return { - type: "textord", - mode: this.mode, - loc: SourceLocation.range(nucleus), - text - } - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict) { - if (!supportedCodepoint(text.charCodeAt(0))) { - throw new ParseError(`Unrecognized Unicode character "${text[0]}"` + - ` (${text.charCodeAt(0)})`, nucleus); - } else if (this.mode === "math") { - throw new ParseError(`Unicode text character "${text[0]}" used in math mode`, nucleus) - } - } - // All nonmathematical Unicode characters are rendered as if they - // are in text mode (wrapped in \text) because that's what it - // takes to render them in LaTeX. - symbol = { - type: "textord", - mode: "text", - loc: SourceLocation.range(nucleus), - text - }; - } else { - return null; // EOF, ^, _, {, }, etc. - } - this.consume(); - // Transform combining characters into accents - if (match) { - for (let i = 0; i < match[0].length; i++) { - const accent = match[0][i]; - if (!unicodeAccents[accent]) { - throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); - } - const command = unicodeAccents[accent][this.mode] || - unicodeAccents[accent].text; - if (!command) { - throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); - } - symbol = { - type: "accent", - mode: this.mode, - loc: SourceLocation.range(nucleus), - label: command, - isStretchy: false, - isShifty: true, - base: symbol - }; - } - } - return symbol; - } - } - - /** - * Parses an expression using a Parser, then returns the parsed result. - */ - const parseTree = function(toParse, settings) { - if (!(typeof toParse === "string" || toParse instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(toParse, settings); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - - let tree = parser.parse(); - - // LaTeX ignores a \tag placed outside an AMS environment. - if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) { - // If the input used \tag, it will set the \df@tag macro to the tag. - // In this case, we separately parse the tag and wrap the tree. - if (parser.gullet.macros.get("\\df@tag")) { - if (!settings.displayMode) { - throw new ParseError("\\tag works only in display mode") - } - parser.gullet.feed("\\df@tag"); - tree = [ - { - type: "tag", - mode: "text", - body: tree, - tag: parser.parse() - } - ]; - } - } - - return tree - }; - - /** - * This file contains information about the style that the mathmlBuilder carries - * around with it. Data is held in an `Style` object, and when - * recursing, a new `Style` object can be created with the `.with*` functions. - */ - - const subOrSupLevel = [2, 2, 3, 3]; - - /** - * This is the main Style class. It contains the current style.level, color, and font. - * - * Style objects should not be modified. To create a new Style with - * different properties, call a `.with*` method. - */ - class Style { - constructor(data) { - // Style.level can be 0 | 1 | 2 | 3, which correspond to - // displaystyle, textstyle, scriptstyle, and scriptscriptstyle. - // style.level does not directly set MathML's script level. MathML does that itself. - // We use style.level to track, not set, math style so that we can get the - // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em. - this.level = data.level; - this.color = data.color; // string | void - // A font family applies to a group of fonts (i.e. SansSerif), while a font - // represents a specific font (i.e. SansSerif Bold). - // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm - this.font = data.font || ""; // string - this.fontFamily = data.fontFamily || ""; // string - this.fontSize = data.fontSize || 1.0; // number - this.fontWeight = data.fontWeight || ""; - this.fontShape = data.fontShape || ""; - this.maxSize = data.maxSize; // [number, number] - } - - /** - * Returns a new style object with the same properties as "this". Properties - * from "extension" will be copied to the new style object. - */ - extend(extension) { - const data = { - level: this.level, - color: this.color, - font: this.font, - fontFamily: this.fontFamily, - fontSize: this.fontSize, - fontWeight: this.fontWeight, - fontShape: this.fontShape, - maxSize: this.maxSize - }; - - for (const key in extension) { - if (Object.prototype.hasOwnProperty.call(extension, key)) { - data[key] = extension[key]; - } - } - - return new Style(data); - } - - withLevel(n) { - return this.extend({ - level: n - }); - } - - incrementLevel() { - return this.extend({ - level: Math.min(this.level + 1, 3) - }); - } - - inSubOrSup() { - return this.extend({ - level: subOrSupLevel[this.level] - }) - } - - /** - * Create a new style object with the given color. - */ - withColor(color) { - return this.extend({ - color: color - }); - } - - /** - * Creates a new style object with the given math font or old text font. - * @type {[type]} - */ - withFont(font) { - return this.extend({ - font - }); - } - - /** - * Create a new style objects with the given fontFamily. - */ - withTextFontFamily(fontFamily) { - return this.extend({ - fontFamily, - font: "" - }); - } - - /** - * Creates a new style object with the given font size - */ - withFontSize(num) { - return this.extend({ - fontSize: num - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontWeight(fontWeight) { - return this.extend({ - fontWeight, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontShape(fontShape) { - return this.extend({ - fontShape, - font: "" - }); - } - - /** - * Gets the CSS color of the current style object - */ - getColor() { - return this.color; - } - } - - /* Temml Post Process - * Perform two tasks not done by Temml when it created each individual Temml element. - * Given a block of block, - * 1. At each AMS auto-numbered environment, assign an id. - * 2. Populate the text contents of each \ref & \eqref - * - * As with other Temml code, this file is released under terms of the MIT license. - * https://mit-license.org/ - */ - - const version = "0.6.9"; - - function postProcess(block) { - const labelMap = {}; - let i = 0; - - // Get a collection of the parents of each \tag & auto-numbered equation - const parents = block.getElementsByClassName("tml-tageqn"); - for (const parent of parents) { - const eqns = parent.getElementsByClassName("tml-eqn"); - if (eqns. length > 0 ) { - // AMS automatically numbered equation. - // Assign an id. - i += 1; - eqns[0].id = "tml-eqn-" + i; - // No need to write a number into the text content of the element. - // A CSS counter does that even if this postProcess() function is not used. - } - // If there is a \label, add it to labelMap - const labels = parent.getElementsByClassName("tml-label"); - if (labels.length === 0) { continue } - if (eqns.length > 0) { - labelMap[labels[0].id] = String(i); - } else { - const tags = parent.getElementsByClassName("tml-tag"); - if (tags.length > 0) { - labelMap[labels[0].id] = tags[0].textContent; - } - } - } - - // Populate \ref & \eqref text content - const refs = block.getElementsByClassName("tml-ref"); - [...refs].forEach(ref => { - let str = labelMap[ref.getAttribute("href").slice(1)]; - if (ref.className.indexOf("tml-eqref") === -1) { - // \ref. Omit parens. - str = str.replace(/^\(/, ""); - str = str.replace(/\($/, ""); - } { - // \eqref. Include parens - if (str.charAt(0) !== "(") { str = "(" + str; } - if (str.slice(-1) !== ")") { str = str + ")"; } - } - ref.textContent = str; - }); - } - - /* eslint no-console:0 */ - - /** - * Parse and build an expression, and place that expression in the DOM node - * given. - */ - let render = function(expression, baseNode, options) { - baseNode.textContent = ""; - const math = renderToMathMLTree(expression, options); - if (options.elementIsMath) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else { - baseNode.appendChild(math.toNode()); - } - }; - - // Temml's styles don't work properly in quirks mode. Print out an error, and - // disable rendering. - if (typeof document !== "undefined") { - if (document.compatMode !== "CSS1Compat") { - typeof console !== "undefined" && - console.warn( - "Warning: Temml doesn't work in quirks mode. Make sure your " + - "website has a suitable doctype." - ); - - render = function() { - throw new ParseError("Temml doesn't work in quirks mode."); - }; - } - } - - /** - * Parse and build an expression, and return the markup for that. - */ - const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; - }; - - /** - * Parse an expression and return the parse tree. - */ - const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); - }; - - /** - * Take an expression which contains a preamble. - * Parse it and return the macros. - */ - const definePreamble = function(expression, options) { - const settings = new Settings(options); - settings.macros = {}; - if (!(typeof expression === "string" || expression instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(expression, settings, true); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - const macros = parser.parse(); - return macros - }; - - /** - * If the given error is a Temml ParseError, - * renders the invalid LaTeX as a span with hover title giving the Temml - * error message. Otherwise, simply throws the error. - */ - const renderError = function(error, expression, options) { - if (options.throwOnError || !(error instanceof ParseError)) { - throw error; - } - const node = new Span(["temml-error"], [new TextNode$1(expression + "\n" + error.toString())]); - node.style.color = options.errorColor; - node.style.whiteSpace = "pre-line"; - return node; - }; - - /** - * Generates and returns the Temml build tree. This is used for advanced - * use cases (like rendering to custom output). - */ - const renderToMathMLTree = function(expression, options) { - const settings = new Settings(options); - try { - const tree = parseTree(expression, settings); - const style = new Style({ - level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT, - maxSize: settings.maxSize - }); - return buildMathML(tree, expression, style, settings); - } catch (error) { - return renderError(error, expression, settings); - } - }; - - var temml = { - /** - * Current Temml version - */ - version: version, - /** - * Renders the given LaTeX into MathML, and adds - * it as a child to the specified DOM node. - */ - render, - /** - * Renders the given LaTeX into MathML string, - * for sending to the client. - */ - renderToString, - /** - * Post-process an entire HTML block. - * Writes AMS auto-numbers and implements \ref{}. - * Typcally called once, after a loop has rendered many individual spans. - */ - postProcess, - /** - * Temml error, usually during parsing. - */ - ParseError, - /** - * Creates a set of macros with document-wide scope. - */ - definePreamble, - /** - * Parses the given LaTeX into Temml's internal parse tree structure, - * without rendering to HTML or MathML. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __parse: generateParseTree, - /** - * Renders the given LaTeX into a MathML internal DOM tree - * representation, without flattening that representation to a string. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __renderToMathMLTree: renderToMathMLTree, - /** - * adds a new symbol to builtin symbols table - */ - __defineSymbol: defineSymbol, - /** - * adds a new macro to builtin macro list - */ - __defineMacro: defineMacro - }; - - return temml; - -})(); diff --git a/test/temmlPostProcess.js b/test/temmlPostProcess.js deleted file mode 100644 index 51122a14..00000000 --- a/test/temmlPostProcess.js +++ /dev/null @@ -1,70 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.temml = {})); -})(this, (function (exports) { 'use strict'; - - /* Temml Post Process - * Perform two tasks not done by Temml when it created each individual Temml element. - * Given a block of block, - * 1. At each AMS auto-numbered environment, assign an id. - * 2. Populate the text contents of each \ref & \eqref - * - * As with other Temml code, this file is released under terms of the MIT license. - * https://mit-license.org/ - */ - - const version = "0.6.9"; - - function postProcess(block) { - const labelMap = {}; - let i = 0; - - // Get a collection of the parents of each \tag & auto-numbered equation - const parents = block.getElementsByClassName("tml-tageqn"); - for (const parent of parents) { - const eqns = parent.getElementsByClassName("tml-eqn"); - if (eqns. length > 0 ) { - // AMS automatically numbered equation. - // Assign an id. - i += 1; - eqns[0].id = "tml-eqn-" + i; - // No need to write a number into the text content of the element. - // A CSS counter does that even if this postProcess() function is not used. - } - // If there is a \label, add it to labelMap - const labels = parent.getElementsByClassName("tml-label"); - if (labels.length === 0) { continue } - if (eqns.length > 0) { - labelMap[labels[0].id] = String(i); - } else { - const tags = parent.getElementsByClassName("tml-tag"); - if (tags.length > 0) { - labelMap[labels[0].id] = tags[0].textContent; - } - } - } - - // Populate \ref & \eqref text content - const refs = block.getElementsByClassName("tml-ref"); - [...refs].forEach(ref => { - let str = labelMap[ref.getAttribute("href").slice(1)]; - if (ref.className.indexOf("tml-eqref") === -1) { - // \ref. Omit parens. - str = str.replace(/^\(/, ""); - str = str.replace(/\($/, ""); - } { - // \eqref. Include parens - if (str.charAt(0) !== "(") { str = "(" + str; } - if (str.slice(-1) !== ")") { str = str + ")"; } - } - ref.textContent = str; - }); - } - - exports.postProcess = postProcess; - exports.version = version; - - Object.defineProperty(exports, '__esModule', { value: true }); - -})); diff --git a/test/unit-test.js b/test/unit-test.js deleted file mode 100644 index ec7e31ff..00000000 --- a/test/unit-test.js +++ /dev/null @@ -1,2146 +0,0 @@ -import temml from "../utils/temml.cjs"; // includess mhchem & physics extensions -import ParseError from "../src/ParseError"; -import parseTree from "../src/parseTree"; -import Settings from "../src/Settings"; -//import splitAtDelimiters from "../contrib/auto-render/splitAtDelimiters.js"; -// import renderMathInElement from "../contrib/auto-render/auto-render"; - -/* - * Unit tests for Temml. - * This file contains more than 1000 tests of various Temml functions. - * - * Sidenote: - * Temml aims to minimize dependency hell by minimizing dependencies. - * When Jest is installed, it adds several thousand files, so I don't use it. - * Instead, I use this roll-your-own testing class. - * - * Many of the tests in this file have been ported from the Jest tests in KaTeX. - */ - -// First, a few helpers. -const defaultSettings = _ => new Settings(); -const strictSettings = _ => new Settings({ strict: true }); -const displayMode = _ => new Settings({ displayMode: true }); -const trustSettings = _ => new Settings({ trust: true }); -const mathTagRegEx = /<\/?math>/g; - -// tagging literal -const r = x => x != null && Object.prototype.hasOwnProperty.call(x, 'raw') ? x.raw[0] : x; - -// Strip positions from ParseNodes. -const stripPositions = expr => { - if (typeof expr !== "object" || expr === null) { return expr } - if (expr.loc && expr.loc.lexer && typeof expr.loc.start === "number") { delete expr.loc } - Object.keys(expr).forEach(function(key) { stripPositions(expr[key]) }); - return expr; -}; - -const parse = (expr, settings = defaultSettings()) => { - const tree = parseTree(expr, settings) - return stripPositions(tree) -} - -function build(expr, settings) { - const builtMathML = temml.__renderToMathMLTree(expr, settings); - if (builtMathML.classes.indexOf('temml-error') >= 0) { return builtMathML } - return builtMathML.children; -} - -// This is the main testing function. -const test = () => { - // Before we write any tests, write an Expect class that mimics Jest expect(). - // The Expect class and the say() helper function are inside this closure - // so that they will have access to the `assertion` variable. - const say = problem => { - numFailures += 1 - console.log(assertion + ", but " + problem) - console.log("") - } - - class Expect { - constructor(input) { - this.input = input; - } - - toBe(x) { - numTests += 1 - if (this.input !== x) { say(this.input + " does not equal " + x) } - } - - toNotBe(x) { - numTests += 1 - if (this.input === x) { say(this.input + " equals " + x + "!") } - } - - toMatch(regEx) { - numTests += 1 - if (!regEx.test(this.input)) { say(this.input + " does not match the RegEx!") } - } - - toMatchSnapshot(str) { - numTests += 1 - const flattened = JSON.stringify(this.input) - if (flattened !== str) { say(flattened + " is not " + str) } - } - - toBeDefined() { - numTests += 1 - if (this.input === undefined) { say(this.input + " is undefinded") } - } - - toBeUndefined() { - numTests += 1 - if (this.input !== undefined) { say(this.input + " is defined.") } - } - - toHaveLength(expectedNum) { - numTests += 1 - if (!this.input.length) { say("No length!") } - if (this.input.length !== expectedNum) { say(this.input.length + " is not " + expectedNum) } - } - - toBeTruthy() { - numTests += 1 - if (!this.input) { say(this.input + " is not truthy.") } - } - - toBeCloseTo(expected) { - numTests += 1 - if (Math.abs(expected - this.input) >= 0.005) { - say(this.input + " is not close to " + expected) - } - } - - toContain(fragment) { - numTests += 1 - if (this.input.indexOf(fragment) === -1) { - say(this.input + " does not contain " + fragment) - } - } - - toNotContain(fragment) { - numTests += 1 - if (this.input.indexOf(fragment) !== -1) { - say(this.input + " contains " + fragment + "!") - } - } - - toParse(settings = defaultSettings()) { - numTests += 1 - let result = true - try { - const tree = parse(this.input, settings) - if (tree instanceof ParseError) { result = false } - if (tree.length === 1 && tree[0].color && tree[0].color === "#b22222") { result = false } - } catch (e) { - result = false - } - if (!result) { say(this.input + " does not parse.") } - } - - toNotParse(settings = defaultSettings()) { - numTests += 1 - let result = true - try { - const tree = parse(this.input, settings) - if (tree instanceof ParseError) { result = false } - if (tree.length === 1 && tree[0].color && tree[0].color === "#b22222") { result = false } - } catch (e) { - result = false - } - if (result) { say(this.input + " parses!") } - } - - toParseLike(str, settings = defaultSettings()) { - numTests += 1 - let result = true - try { - const tree = parse(this.input, settings) - if (tree instanceof ParseError) { result = false } - const comp = parse(str, settings) - if (comp instanceof ParseError) { result = false } - result = JSON.stringify(tree) === JSON.stringify(comp) - } catch (e) { - result = false - } - if (!result) { - say(this.input + " does not parse like " + str) - } - } - - toBuild(settings = defaultSettings()) { - numTests += 1 - let result = true - try { - const tree = build(this.input, settings) - if (tree.classes && tree.classes[0] === "temml-error") { result = false } - } catch (e) { - result = false - console.log(e) - } - if (!result) { - say(this.input + " does not build.") - } - } - - toNotBuild(settings = defaultSettings()) { - numTests += 1 - let result = true - try { - const tree = build(this.input, settings) - if (tree.classes && tree.classes[0] === "temml-error") { result = false } - } catch (e) { - result = false - } - if (result) { say(this.input + " builds!") } - } - - toBuildLike(str, settings = defaultSettings()) { - numTests += 1 - let result = true - try { - const tree = build(this.input, settings) - if (tree instanceof ParseError) { result = false } - const comp = build(str, settings) - if (comp instanceof ParseError) { result = false } - result = JSON.stringify(tree) === JSON.stringify(comp) - } catch (e) { - result = false - } - if (!result) { say(this.input + " does not build like " + str) } - } - } - - // Now we have an Expect class. Here come lots of tests. - - let numTests = 0 - let numFailures = 0 - console.log("") - - let assertion = "Parser should work" - new Expect("").toParse() - new Expect("1234|/@.`abcdefgzABCDEFGZ").toParse() - - assertion = "Parser should ignore whitespace" - new Expect(` x y `).toParseLike("xy") - new Expect(` x ^ y `).toParseLike("x^y") - - assertion = "Parser should build a list of ords" - const ords = parse("1234|@.`abcdefgzABCDEFGZ"); - for (let i = 0; i < ords.length; i++) { - new Expect(ords[i].type.slice(4)).toBe("ord"); - } - - assertion = "Parser should build a list of bins" - let nodes = parse(r`+-*\cdot\pm\div`) - for (let i = 0; i < nodes.length; i++) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("bin"); - } - - assertion = "Parser should build a list of rels" - nodes = parse(r`=<>\leq\geq\neq\nleq\ngeq\cong\in`) - for (let i = 0; i < nodes.length; i++) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("rel"); - } - - assertion = "Parser should parse a \\mathinner" - new Expect(r`\mathinner{\langle{\psi}\rangle}`).toParse() - new Expect(r`\frac 1 {\mathinner{\langle{\psi}\rangle}}`).toParse() - assertion = "\\mathinner should return a group, not a fragment" - new Expect(build(r`\mathinner{\langle{\psi}\rangle}`).length).toBe(1) - - assertion = "Parse should build a list of puncts" - nodes = parse(",;") - for (let i = 0; i < nodes.length; i++) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("punct"); - } - - assertion = "Parser should build a list of opens" - nodes = parse("([") - for (let i = 0; i < nodes.length; i++) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("open"); - } - - assertion = "Parser should build a list of closes" - nodes = parse("])") - for (let i = 0; i < nodes.length; i++) { - new Expect(nodes[i].type).toBe("atom"); - new Expect(nodes[i].family).toBe("close"); - } - - assertion = "\\Temml should parse" - new Expect("\\Temml").toParse() - - assertion = "Subscripts and superscripts should parse" - new Expect(`x^2`).toParse() - new Expect(`x_3`).toParse() - new Expect(`x^2_3`).toParse() - new Expect(`x_2^3`).toParse() - new Expect(`^3`).toParse(); - new Expect(`^3+`).toParse(); - new Expect(`_2`).toParse(); - new Expect(`^3_2`).toParse(); - new Expect(`_2^3`).toParse(); - - let node = parse("x^2")[0] - new Expect(node.type).toBe("supsub"); - new Expect(node.base).toBeDefined(); - new Expect(node.sup).toBeDefined(); - new Expect(node.sub).toBeUndefined(); - - node = parse("x_3")[0] - new Expect(node.type).toBe("supsub"); - new Expect(node.base).toBeDefined(); - new Expect(node.sub).toBeDefined(); - new Expect(node.sup).toBeUndefined(); - - node = parse("x^2_3")[0] - new Expect(node.type).toBe("supsub"); - new Expect(node.base).toBeDefined(); - new Expect(node.sub).toBeDefined(); - new Expect(node.sup).toBeDefined(); - - new Expect(`x^2_3`).toParseLike(`x_3^2`) - - assertion = "Double exponents should not parse" - new Expect(`x^x^x`).toNotParse(); - new Expect(`x_x_x`).toNotParse(); - new Expect(`x_x^x_x`).toNotParse(); - new Expect(`x_x^x^x`).toNotParse(); - new Expect(`x^x_x_x`).toNotParse(); - new Expect(`x^x_x^x`).toNotParse(); - - assertion = "A subsup parser should work correctly with {}s" - new Expect(`x^{2+3}`).toParse(); - new Expect(`x_{3-2}`).toParse(); - new Expect(`x^{2+3}_3`).toParse(); - new Expect(`x^2_{3-2}`).toParse(); - new Expect(`x^{2+3}_{3-2}`).toParse(); - new Expect(`x_{3-2}^{2+3}`).toParse(); - new Expect(`x_3^{2+3}`).toParse(); - new Expect(`x_{3-2}^2`).toParse(); - - assertion = "A subsup parser should work with nested super/subscripts" - new Expect(`x^{x^x}`).toParse(); - new Expect(`x^{x_x}`).toParse(); - new Expect(`x_{x^x}`).toParse(); - new Expect(`x_{x_x}`).toParse(); - - assertion = "A subscript and superscript tree-builder should not fail when there is no nucleus" - new Expect(`^3`).toParse(); - new Expect(`_2`).toParse(); - new Expect(`^3_2`).toParse(); - new Expect(`_2^3`).toParse(); - new Expect(`^3`).toBuild(); - new Expect(`_2`).toBuild(); - new Expect(`^3_2`).toBuild(); - new Expect(`_2^3`).toBuild(); - - assertion = "A subsup parser should work with Unicode (sub|super)script characters" - new Expect(`A² + B²⁺³ + ¹²C + E₂³ + F₂₊₃`).toBuildLike("A^{2} + B^{2+3} + ^{12}C + E_{2}^{3} + F_{2+3}") - new Expect(r`\text{B²⁺³}`).toParse() - new Expect(r`\text{B²⁺³}`).toBuild() - - assertion = "A parser with limit controls should fail when the limit control is not preceded by an op node" - new Expect(r`3\nolimits_2^2`).toNotParse(); - new Expect(r`\sqrt\limits_2^2`).toNotParse(); - new Expect(r`45 +\nolimits 45`).toNotParse(); - - assertion = "A parser with limit controls should parse when the limit control directly follows an op node" - new Expect(r`\int\limits_2^2 3`).toParse(); - new Expect(r`\sum\nolimits_3^4 4`).toParse(); - - assertion = "A parser with limit controls should parse when the limit control is in the sup/sub area of an op node" - new Expect(r`\int_2^2\limits`).toParse(); - new Expect(r`\int^2\nolimits_2`).toParse(); - new Expect(r`\int_2\limits^2`).toParse(); - - assertion = "A parser with limit controls should allow multiple limit controls in the sup/sub area of an op node" - new Expect(r`\int_2\nolimits^2\limits 3`).toParse(); - new Expect(r`\int\nolimits\limits_2^2`).toParse(); - new Expect(r`\int\limits\limits\limits_2^2`).toParse(); - - assertion = "A parser with limit controls should have the rightmost limit control determine the limits property of the preceding op node" - new Expect(parse(r`\int\nolimits\limits_2^2`)[0].base.limits).toBe(true) - new Expect(parse(r`\int\limits_2\nolimits^2`)[0].base.limits).toBe(false) - - assertion = "A group parser should work" - new Expect(`{xy}`).toParse(); - nodes = parse(`{xy}`) - new Expect(nodes).toHaveLength(1); - new Expect(nodes[0].type).toBe("ordgroup"); - new Expect(nodes[0].body).toBeTruthy(); - new Expect(r`\begingroup xy \endgroup`).toParse(); - new Expect(r`\begingroup xy`).toNotParse(); - new Expect(r`\begingroup xy }`).toNotParse(); - nodes = parse(r`\begingroup xy \endgroup`) - new Expect(nodes).toHaveLength(1) - new Expect(nodes[0].type).toBe("ordgroup"); - new Expect(nodes[0].body).toBeTruthy(); - new Expect(nodes[0].semisimple).toBeTruthy(); - - assertion = "An implicit group parser should work" - new Expect(r`\Large x`).toParse(); - new Expect(r`abc {abc \Large xyz} abc`).toParse(); - nodes = parse(r`\Large abc`) - new Expect(nodes).toHaveLength(1); - new Expect(nodes[0].type).toBe("sizing"); - new Expect(nodes[0].body).toBeTruthy(); - nodes = parse(r`a \Large abc`) - new Expect(nodes).toHaveLength(2); - new Expect(nodes[1].type).toBe("sizing"); - new Expect(nodes[1].body).toHaveLength(3); - nodes = parse(r`a { b \Large c } d`) - new Expect(nodes[1].body[1].type).toBe("sizing"); - new Expect(nodes[1].body[1].body).toHaveLength(1); - - assertion = "An implicit group parser should work within optional groups" - new Expect(r`\sqrt[\small 3]{x}`).toParse(); - new Expect(r`\sqrt[\color{red} 3]{x}`).toParse() - new Expect(r`\sqrt[\textstyle 3]{x}`).toParse() - new Expect(r`\sqrt[\tt 3]{x}`).toParse() - - assertion = "A function parser should work" - new Expect(r`\div`).toParse(); - new Expect(r`\blue x`).toParse(); - new Expect(r`\frac 1 2`).toParse(); - new Expect(r`\tilde`).toNotParse(); - new Expect(r`\frac`).toNotParse(); - new Expect(r`\frac 1`).toNotParse(); - new Expect(parse(r`\tildex`)[0].color).toBe("#b22222"); - new Expect(r`\frac12`).toParse(strictSettings()); - new Expect(r`\;x`).toParse(); - - assertion = "A frac parser should work" - const expression = r`\frac{x}{y}`; - const dfracExpression = r`\dfrac{x}{y}`; - const tfracExpression = r`\tfrac{x}{y}`; - const cfracExpression = r`\cfrac{x}{y}`; - const genfrac1 = r`\genfrac ( ] {0.06em}{0}{a}{b+c}`; - const genfrac2 = r`\genfrac ( ] {0.8pt}{}{a}{b+c}`; - new Expect(expression).toParse(); - node = parse(expression)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer).toBeDefined(); - new Expect(node.denom).toBeDefined(); - new Expect(cfracExpression).toParse(); - new Expect(dfracExpression).toParse(); - new Expect(tfracExpression).toParse(); - new Expect(genfrac1).toParse(); - new Expect(genfrac2).toParse(); - const dfracParse = parse(dfracExpression)[0]; - new Expect(dfracParse.type).toBe("genfrac"); - new Expect(dfracParse.numer).toBeDefined(); - new Expect(dfracParse.denom).toBeDefined(); - const tfracParse = parse(tfracExpression)[0]; - new Expect(tfracParse.type).toBe("genfrac"); - new Expect(tfracParse.numer).toBeDefined(); - new Expect(tfracParse.denom).toBeDefined(); - const cfracParse = parse(cfracExpression)[0]; - new Expect(cfracParse.type).toBe("genfrac"); - new Expect(cfracParse.numer).toBeDefined(); - new Expect(cfracParse.denom).toBeDefined(); - const genfracParse = parse(genfrac1)[0]; - new Expect(genfracParse.type).toBe("genfrac"); - new Expect(genfracParse.numer).toBeDefined(); - new Expect(genfracParse.denom).toBeDefined(); - new Expect(genfracParse.leftDelim).toBeDefined(); - new Expect(genfracParse.rightDelim).toBeDefined(); - let badGenFrac = r`\genfrac ( ] {b+c}{0}{a}{b+c}`; - new Expect(badGenFrac).toNotParse(); - badGenFrac = r`\genfrac ( ] {0.06em}{0}{a}`; - new Expect(badGenFrac).toNotParse(); - node = parse(r`x \atop y`)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer).toBeDefined(); - new Expect(node.denom).toBeDefined(); - new Expect(node.hasBarLine).toBe(false); - - assertion = "An over/brace/brack parser should work" - const simpleOver = r`1 \over x`; - const complexOver = r`1+2i \over 3+4i`; - const braceFrac = r`a+b \brace c+d`; - const brackFrac = r`a+b \brack c+d`; - new Expect(simpleOver).toParse(); - new Expect(complexOver).toParse(); - new Expect(braceFrac).toParse(); - new Expect(brackFrac).toParse(); - - node = parse(simpleOver)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer).toBeDefined(); - new Expect(node.denom).toBeDefined(); - - node = parse(complexOver)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer).toBeDefined(); - new Expect(node.denom).toBeDefined(); - - const parseBraceFrac = parse(braceFrac)[0]; - new Expect(parseBraceFrac.type).toBe("genfrac"); - new Expect(parseBraceFrac.numer).toBeDefined(); - new Expect(parseBraceFrac.denom).toBeDefined(); - new Expect(parseBraceFrac.leftDelim).toBeDefined(); - new Expect(parseBraceFrac.rightDelim).toBeDefined(); - - const parseBrackFrac = parse(brackFrac)[0]; - new Expect(parseBrackFrac.type).toBe("genfrac"); - new Expect(parseBrackFrac.numer).toBeDefined(); - new Expect(parseBrackFrac.denom).toBeDefined(); - new Expect(parseBrackFrac.leftDelim).toBeDefined(); - new Expect(parseBrackFrac.rightDelim).toBeDefined(); - node = parse(complexOver)[0]; - - const numer = node.numer; - new Expect(numer.body).toHaveLength(4); - node = parse(complexOver)[0]; - - const denom = node.denom; - new Expect(denom.body).toHaveLength(4); - const emptyNumerator = r`\over x`; - node = parse(emptyNumerator)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer).toBeDefined(); - new Expect(node.denom).toBeDefined(); - const emptyDenominator = r`1 \over`; - node = parse(emptyDenominator)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer).toBeDefined(); - new Expect(node.denom).toBeDefined(); - const displaystyleExpression = r`\displaystyle 1 \over 2`; - node = parse(displaystyleExpression)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer.body[0].type).toBe("styling"); - new Expect(node.denom).toBeDefined(); - new Expect(r`\textstyle 1 \over 2`).toParseLike(r`\frac{\textstyle 1}{2}`); - new Expect(r`{\textstyle 1} \over 2`).toParseLike(r`\frac{\textstyle 1}{2}`); - const nestedOverExpression = r`{1 \over 2} \over 3`; - node = parse(nestedOverExpression)[0]; - new Expect(node.type).toBe("genfrac"); - new Expect(node.numer.body[0].type).toBe("genfrac"); - new Expect(node.numer.body[0].numer.body[0].text).toBe("1"); - new Expect(node.numer.body[0].denom.body[0].text).toBe("2"); - new Expect(node.denom).toBeDefined(); - new Expect(node.denom.body[0].text).toBe("3"); - const badMultipleOvers = r`1 \over 2 + 3 \over 4`; - new Expect(badMultipleOvers).toNotParse(); - const badOverChoose = r`1 \over 2 \choose 3`; - new Expect(badOverChoose).toNotParse(); - - assertion = `A genfrac builder should work` - new Expect(r`\frac{x}{y}`).toParse(); - new Expect(r`\dfrac{x}{y}`).toParse(); - new Expect(r`\tfrac{x}{y}`).toParse(); - new Expect(r`\cfrac{x}{y}`).toParse(); - new Expect(r`\genfrac ( ] {0.06em}{0}{a}{b+c}`).toParse(); - new Expect(r`\genfrac ( ] {0.8pt}{}{a}{b+c}`).toParse(); - new Expect(r`\genfrac {} {} {0.8pt}{}{a}{b+c}`).toParse(); - new Expect(r`\genfrac [ {} {0.8pt}{}{a}{b+c}`).toParse(); - new Expect(r`\frac{x}{y}`).toBuild(); - new Expect(r`\dfrac{x}{y}`).toBuild(); - new Expect(r`\tfrac{x}{y}`).toBuild(); - new Expect(r`\cfrac{x}{y}`).toBuild(); - new Expect(r`\genfrac ( ] {0.06em}{0}{a}{b+c}`).toBuild(); - new Expect(r`\genfrac ( ] {0.8pt}{}{a}{b+c}`).toBuild(); - new Expect(r`\genfrac {} {} {0.8pt}{}{a}{b+c}`).toBuild(); - new Expect(r`\genfrac [ {} {0.8pt}{}{a}{b+c}`).toBuild(); - - assertion = `A infix builder should not fail` - new Expect(r`a \over b`).toParse(); - new Expect(r`a \atop b`).toParse(); - new Expect(r`a \choose b`).toParse(); - new Expect(r`a \brace b`).toParse(); - new Expect(r`a \brack b`).toParse(); - new Expect(r`a \over b`).toBuild(); - new Expect(r`a \atop b`).toBuild(); - new Expect(r`a \choose b`).toBuild(); - new Expect(r`a \brace b`).toBuild(); - new Expect(r`a \brack b`).toBuild(); - - assertion = "A sizing parser should work" - const sizeExpression = r`\Huge{x}\small{x}`; - new Expect(sizeExpression).toParse(); - node = parse(sizeExpression)[0]; - new Expect(node.type).toBe("sizing"); - new Expect(node.body).toBeDefined(); - - assertion = "A text parser should work" - const textExpression = r`\text{a b}`; - const noBraceTextExpression = r`\text x`; - const nestedTextExpression = r`\text{a {b} \blue{c} \textcolor{#fff}{x} \llap{x}}`; - const spaceTextExpression = r`\text{ a \ }`; - const leadingSpaceTextExpression = r`\text {moo}`; - const badTextExpression = r`\text{a b%}`; - const badFunctionExpression = r`\text{\sqrt{x}}`; - const mathTokenAfterText = r`\text{sin}^2`; - new Expect(textExpression).toParse(); - node = parse(textExpression)[0]; - - new Expect(node.type).toBe("text"); - new Expect(node.body).toBeDefined(); - - new Expect(parse(textExpression)[0].body[0].type).toBe("textord"); - new Expect(badTextExpression).toNotParse(); - new Expect(badFunctionExpression).toNotParse(); - new Expect(noBraceTextExpression).toParse(); - new Expect(nestedTextExpression).toParse(); - node = parse(spaceTextExpression)[0]; - new Expect(node.body[0].type).toBe("spacing"); - new Expect(node.body[1].type).toBe("textord"); - new Expect(node.body[2].type).toBe("spacing"); - new Expect(node.body[3].type).toBe("spacing"); - new Expect(mathTokenAfterText).toParse(); - node = parse(leadingSpaceTextExpression)[0]; - // [m, o, o] - new Expect(node.body).toHaveLength(3); - new Expect(node.body.map(n => n.text).join("")).toBe("moo"); - new Expect(r`\text{graph: $y = mx + b$}`).toParse(); - new Expect(r`\text{graph: \(y = mx + b\)}`).toParse(); - new Expect(r`\text{hello $x + \text{world $y$} + z$}`).toParse(); - new Expect(r`\text{hello \(x + \text{world $y$} + z\)}`).toParse(); - new Expect(r`\text{hello $x + \text{world \(y\)} + z$}`).toParse(); - new Expect(r`\text{hello \(x + \text{world \(y\)} + z\)}`).toParse(); - new Expect(r`\(`).toNotParse(); - new Expect(r`\text{$\(x\)$}`).toNotParse(); - new Expect(r`$x$`).toNotParse(); - new Expect(r`\text{\($x$\)}`).toNotParse(); - new Expect(r`\)`).toNotParse(); - new Expect(r`\text{\)}`).toNotParse(); - new Expect(r`$`).toNotParse(); - new Expect(r`\text{$}`).toNotParse(); - new Expect(r`\text{$x\)}`).toNotParse(); - new Expect(r`\text{\(x$}`).toNotParse(); - new Expect(r`a b\, \; \! \: \> ~ \thinspace \medspace \quad \ `).toParse(); - new Expect(r`\enspace \thickspace \qquad \space \nobreakspace`).toParse(); - new Expect(r`a b\, \; \! \: \> ~ \thinspace \medspace \quad \ `).toBuild(); - new Expect(r`\enspace \thickspace \qquad \space \nobreakspace`).toBuild(); - new Expect(r`\text{\textellipsis !}`).toParseLike(r`\text{\textellipsis!}`); - new Expect(r`\:_*`).toParse(); - new Expect(r`\:_*`).toBuild(); - - assertion = `A texvc builder should not fail` - new Expect(r`\lang\N\darr\R\dArr\Z\Darr\alef\rang`).toParse(); - new Expect(r`\alefsym\uarr\Alpha\uArr\Beta\Uarr\Chi`).toParse(); - new Expect(r`\clubs\diamonds\hearts\spades\cnums\Complex`).toParse(); - new Expect(r`\Dagger\empty\harr\Epsilon\hArr\Eta\Harr\exist`).toParse(); - new Expect(r`\image\larr\infin\lArr\Iota\Larr\isin\Kappa`).toParse(); - new Expect(r`\Mu\lrarr\natnums\lrArr\Nu\Lrarr\Omicron`).toParse(); - new Expect(r`\real\rarr\plusmn\rArr\reals\Rarr\Reals\Rho`).toParse(); - new Expect(r`\text{\sect}\sdot\sub\sube\supe`).toParse(); - new Expect(r`\Tau\thetasym\weierp\Zeta`).toParse(); - new Expect(r`\lang\N\darr\R\dArr\Z\Darr\alef\rang`).toBuild(); - new Expect(r`\alefsym\uarr\Alpha\uArr\Beta\Uarr\Chi`).toBuild(); - new Expect(r`\clubs\diamonds\hearts\spades\cnums\Complex`).toBuild(); - new Expect(r`\Dagger\empty\harr\Epsilon\hArr\Eta\Harr\exist`).toBuild(); - new Expect(r`\image\larr\infin\lArr\Iota\Larr\isin\Kappa`).toBuild(); - new Expect(r`\Mu\lrarr\natnums\lrArr\Nu\Lrarr\Omicron`).toBuild(); - new Expect(r`\real\rarr\plusmn\rArr\reals\Rarr\Reals\Rho`).toBuild(); - new Expect(r`\text{\sect}\sdot\sub\sube\supe`).toBuild(); - new Expect(r`\Tau\thetasym\weierp\Zeta`).toBuild(); - - assertion = "A tie parser should work" - const mathTie = "a~b"; - const textTie = r`\text{a~ b}`; - new Expect(mathTie).toParse(); - new Expect(textTie).toParse(); - new Expect(parse(mathTie)[1].type).toBe("spacing"); - node = parse(textTie)[0]; - new Expect(node.body[1].type).toBe("spacing"); - node = parse(textTie)[0]; - new Expect(node.body[2].type).toBe("spacing"); - - assertion = "A delimiter sizing parser should work" - const normalDelim = r`\bigl |`; - const notDelim = r`\bigl x`; - const bigDelim = r`\Biggr \langle`; - new Expect(normalDelim).toParse(); - new Expect(bigDelim).toParse(); - new Expect(notDelim).toNotParse(); - node = parse(normalDelim)[0]; - new Expect(node.type).toBe("delimsizing"); - const leftParse = parse(normalDelim)[0]; - const rightParse = parse(bigDelim)[0]; - new Expect(leftParse.mclass).toBe("mopen"); - new Expect(rightParse.mclass).toBe("mclose"); - const smallParse = parse(normalDelim)[0]; - const bigParse = parse(bigDelim)[0]; - new Expect(smallParse.size).toBe(1); - new Expect(bigParse.size).toBe(4); - - assertion = "An overline parser should work" - const overline = r`\overline{x}`; - new Expect(overline).toParse(); - node = parse(overline)[0]; - new Expect(node.type).toBe("overline"); - - assertion = "A lap parser should work" - new Expect(r`\rlap{\,/}{=}`).toParse(); - new Expect(r`\mathrlap{\,/}{=}`).toParse(); - new Expect(r`{=}\llap{/\,}`).toParse(); - new Expect(r`{=}\mathllap{/\,}`).toParse(); - new Expect(r`\sum_{\clap{ABCDEFG}}`).toParse(); - new Expect(r`\sum_{\mathclap{ABCDEFG}}`).toParse(); - new Expect(r`\mathrlap{\frac{a}{b}}{=}`).toParse(); - new Expect(r`{=}\mathllap{\frac{a}{b}}`).toParse(); - new Expect(r`\sum_{\mathclap{\frac{a}{b}}}`).toParse(); - new Expect(r`\rlap{\frac{a}{b}}{=}`).toNotParse(strictSettings()); - new Expect(r`{=}\llap{\frac{a}{b}}`).toNotParse(strictSettings()); - new Expect(r`\sum_{\clap{\frac{a}{b}}}`).toNotParse(strictSettings()); - node = parse(r`\mathrlap{\,/}`)[0]; - new Expect(node.type).toBe("lap"); - - assertion = "A rule parser should work" - const emRule = r`\rule{1em}{2em}`; - const exRule = r`\rule{1ex}{2em}`; - let badUnitRule = r`\rule{1au}{2em}`; - let noNumberRule = r`\rule{1em}{em}`; - const incompleteRule = r`\rule{1em}`; - const hardNumberRule = r`\rule{ 01.24ex}{2.450 em }`; - new Expect(emRule).toParse(); - new Expect(exRule).toParse(); - new Expect(badUnitRule).toNotParse(); - new Expect(noNumberRule).toNotParse(); - new Expect(incompleteRule).toNotParse(); - node = parse(emRule)[0]; - new Expect(node.type).toBe("rule"); - let emParse = parse(emRule)[0]; - let exParse = parse(exRule)[0]; - new Expect(emParse.width.unit).toBe("em"); - new Expect(emParse.height.unit).toBe("em"); - new Expect(exParse.width.unit).toBe("ex"); - new Expect(exParse.height.unit).toBe("em"); - const hardNumberParse = parse(hardNumberRule)[0]; - new Expect(hardNumberParse.width.number).toBeCloseTo(1.24); - new Expect(hardNumberParse.height.number).toBeCloseTo(2.45); - node = parse(r`\rule{-1em}{- 0.2em}`)[0]; - new Expect(node.width.number).toBeCloseTo(-1); - new Expect(node.height.number).toBeCloseTo(-0.2); - - assertion = "A kern parser should work" - let emKern = r`\kern{1em}`; - let exKern = r`\kern{1ex}`; - let muKern = r`\mkern{1mu}`; - let abKern = r`a\kern{1em}b`; - badUnitRule = r`\kern{1au}`; - noNumberRule = r`\kern{em}`; - emParse = parse(emKern)[0]; - exParse = parse(exKern)[0]; - let muParse = parse(muKern)[0]; - let abParse = parse(abKern)[1]; - new Expect(emParse.dimension.unit).toBe("em"); - new Expect(exParse.dimension.unit).toBe("ex"); - new Expect(muParse.dimension.unit).toBe("mu"); - new Expect(abParse.dimension.unit).toBe("em"); - new Expect(badUnitRule).toNotParse(); - new Expect(noNumberRule).toNotParse(); - node = parse(r`\kern{-1em}`)[0]; - new Expect(node.dimension.number).toBeCloseTo(-1); - node = parse(r`\kern{+1em}`)[0]; - new Expect(node.dimension.number).toBeCloseTo(1); - - assertion = "A non-braced kern parser should work" - emKern = r`\kern1em`; - exKern = r`\kern 1 ex`; - muKern = r`\mkern 1mu`; - const abKern1 = r`a\mkern1mub`; - const abKern2 = r`a\mkern-1mub`; - const abKern3 = r`a\mkern-1mu b`; - badUnitRule = r`\kern1au`; - noNumberRule = r`\kern em`; - emParse = parse(emKern)[0]; - exParse = parse(exKern)[0]; - muParse = parse(muKern)[0]; - let abParse1 = parse(abKern1)[1]; - let abParse2 = parse(abKern2)[1]; - let abParse3 = parse(abKern3)[1]; - new Expect(emParse.dimension.unit).toBe("em"); - new Expect(exParse.dimension.unit).toBe("ex"); - new Expect(muParse.dimension.unit).toBe("mu"); - new Expect(abParse1.dimension.unit).toBe("mu"); - new Expect(abParse2.dimension.unit).toBe("mu"); - new Expect(abParse3.dimension.unit).toBe("mu"); - abParse1 = parse(abKern1); - abParse2 = parse(abKern2); - abParse3 = parse(abKern3); - new Expect(abParse1).toHaveLength(3); - new Expect(abParse1[0].text).toBe("a"); - new Expect(abParse1[2].text).toBe("b"); - new Expect(abParse2).toHaveLength(3); - new Expect(abParse2[0].text).toBe("a"); - new Expect(abParse2[2].text).toBe("b"); - new Expect(abParse3).toHaveLength(3); - new Expect(abParse3[0].text).toBe("a"); - new Expect(abParse3[2].text).toBe("b"); - new Expect(badUnitRule).toNotParse(); - new Expect(noNumberRule).toNotParse(); - node = parse(r`\kern-1em`)[0]; - new Expect(node.dimension.number).toBeCloseTo(-1); - node = parse(r`\kern+1em`)[0]; - new Expect(node.dimension.number).toBeCloseTo(1); - abKern = "a\\mkern\t-\r1 \n mu\nb"; - abParse = parse("a\\mkern\t-\r1 \n mu\nb"); - new Expect(abParse).toHaveLength(3); - new Expect(abParse[0].text).toBe("a"); - new Expect(abParse[1].dimension.unit).toBe("mu"); - new Expect(abParse[2].text).toBe("b"); - - assertion = "A left/right parser should work" - const normalLeftRight = r`\left( \dfrac{x}{y} \right)`; - const emptyRight = r`\left( \dfrac{x}{y} \right.`; - new Expect(normalLeftRight).toParse(); - node = parse(normalLeftRight)[0]; - new Expect(node.type).toBe("leftright"); - new Expect(node.left).toBe("("); - new Expect(node.right).toBe(")"); - const unmatchedLeft = r`\left( \dfrac{x}{y}`; - const unmatchedRight = r`\dfrac{x}{y} \right)`; - new Expect(unmatchedLeft).toNotParse(); - new Expect(unmatchedRight).toNotParse(); - const unmatched = r`{ \left( \dfrac{x}{y} } \right)`; - new Expect(unmatched).toNotParse(); - const nonDelimiter = r`\left$ \dfrac{x}{y} \right)`; - new Expect(nonDelimiter).toNotParse(); - new Expect(emptyRight).toParse(); - const normalEmpty = r`\Bigl .`; - new Expect(normalEmpty).toParse(); - const normalMiddle = r`\left( \dfrac{x}{y} \middle| \dfrac{y}{z} \right)`; - new Expect(normalMiddle).toParse(); - const multiMiddle = r`\left( \dfrac{x}{y} \middle| \dfrac{y}{z} \middle/ \dfrac{z}{q} \right)`; - new Expect(multiMiddle).toParse(); - const nestedMiddle = r`\left( a^2 \middle| \left( b \middle/ c \right) \right)`; - new Expect(nestedMiddle).toParse(); - const unmatchedMiddle = r`(\middle|\dfrac{x}{y})`; - new Expect(unmatchedMiddle).toNotParse(); - new Expect(r`\left\langle \right\rangle`).toBuildLike(r`\left< \right>`); - new Expect(r`\left\langle \right\rangle`).toBuildLike("\\left\u27e8 \\right\u27e9"); - new Expect(r`\left\lparen \right\rparen`).toBuildLike(r`\left( \right)`); - - assertion = "A begin/end parser should work" - new Expect(r`\begin{matrix}a&b\\c&d\end{matrix}`).toParse(); - new Expect(r`\begin{array}{cc}a&b\\c&d\end{array}`).toParse(); - new Expect(r`\begin{aligned}\end{aligned}`).toParse(); - new Expect(r`\begin{matrix}\hline a&b\\ \hline c&d\end{matrix}`).toParse(); - new Expect(r`\begin{matrix}\hdashline a&b\\ \hdashline c&d\end{matrix}`).toParse(); - new Expect(r`\hline`).toNotParse(); - new Expect(r`\begin{matrix}a&b\\c&d\end{pmatrix}`).toNotParse(); - new Expect(r`\begin{matrix}a&b\\c&d\right{pmatrix}`).toNotParse(); - new Expect(r`\begin{matrix}a&b\\c&d`).toNotParse(); - new Expect(r`{\begin{matrix}a&b\\c&d}\end{matrix}`).toNotParse(); - new Expect(r`\begin{matrix}0&1\over2&3\\4&5&6\end{matrix}`).toParse(); - const m1 = `\\begin{pmatrix}1&2\\\\3&4\\end{pmatrix}`; - const m2 = `\\begin{array}{rl}${m1}&0\\\\0&${m1}\\end{array}`; - new Expect(m2).toParse(); - new Expect(r`\begin{matrix}a&b\cr c&d\end{matrix}`).toParse(); - new Expect(r`\begin{matrix}a&b\\c&d\end{matrix}`).toParse(); - new Expect(r`\begin{matrix}a&b\cr[c]&d\end{matrix}`).toParse(); - const m3 = parse(r`\begin{matrix}a&b\\ c&d \\ \end{matrix}`)[0]; - new Expect(m3.body).toHaveLength(2); - new Expect(r`\begin{matrix*}[r] a & -1 \\ -1 & d \end{matrix*}`).toParse(); - new Expect(r`\begin{pmatrix*}[r] a & -1 \\ -1 & d \end{pmatrix*}`).toParse(); - new Expect(r`\begin{bmatrix*}[r] a & -1 \\ -1 & d \end{bmatrix*}`).toParse(); - new Expect(r`\begin{Bmatrix*}[r] a & -1 \\ -1 & d \end{Bmatrix*}`).toParse(); - new Expect(r`\begin{vmatrix*}[r] a & -1 \\ -1 & d \end{vmatrix*}`).toParse(); - new Expect(r`\begin{Vmatrix*}[r] a & -1 \\ -1 & d \end{Vmatrix*}`).toParse(); - new Expect(r`\begin{matrix*} a & -1 \\ -1 & d \end{matrix*}`).toParse(); - new Expect(r`\begin{matrix*}[r] a & -1 \\ -1 & d \end{matrix*}`).toBuild(); - new Expect(r`\begin{pmatrix*}[r] a & -1 \\ -1 & d \end{pmatrix*}`).toBuild(); - new Expect(r`\begin{bmatrix*}[r] a & -1 \\ -1 & d \end{bmatrix*}`).toBuild(); - new Expect(r`\begin{Bmatrix*}[r] a & -1 \\ -1 & d \end{Bmatrix*}`).toBuild(); - new Expect(r`\begin{vmatrix*}[r] a & -1 \\ -1 & d \end{vmatrix*}`).toBuild(); - new Expect(r`\begin{Vmatrix*}[r] a & -1 \\ -1 & d \end{Vmatrix*}`).toBuild(); - new Expect(r`\begin{matrix*} a & -1 \\ -1 & d \end{matrix*}`).toBuild(); - new Expect(r`\begin{matrix*}[] a & -1 \\ -1 & d \end{matrix*}`).toNotParse(); - - assertion = "A sqrt parser should work" - const sqrt = r`\sqrt{x}`; - const missingGroup = r`\sqrt`; - new Expect(sqrt).toParse(); - new Expect(missingGroup).toNotParse(); - new Expect(parse(sqrt)[0].type).toBe("sqrt"); - new Expect("\\Large\\sqrt[3]{x}").toParse(); - new Expect("\\sqrt\\foo").toParseLike("\\sqrt123", new Settings({ macros: { "\\foo": "123" } })); - new Expect("\\sqrt[2]\\foo").toParseLike("\\sqrt[2]{123}", new Settings({ macros: { "\\foo": "123" } })); - - assertion = "A TeX-compliant parser should work" - new Expect(r`\frac 2 3`).toParse(); - const missingGroups = [ - r`\frac{x}`, - r`\textcolor{#fff}`, - r`\rule{1em}`, - r`\llap`, - r`\bigl`, - r`\text` - ]; - for (let i = 0; i < missingGroups.length; i++) { - new Expect(missingGroups[i]).toNotParse(); - } - new Expect(r`x^`).toNotParse(); - new Expect(r`x_`).toNotParse(); - const badArguments = [ - r`\frac \frac x y z`, - r`\frac x \frac y z`, - r`\frac \sqrt x y`, - r`\frac x \sqrt y`, - r`\frac \mathllap x y`, - r`\frac x \mathllap y`, - // This actually doesn't work in real TeX, but it is suprisingly - // hard to get this to correctly work. So, we take hit of very small - // amounts of non-compatiblity in order for the rest of the tests to - // work - // r`\llap \frac x y`, - r`\mathllap \mathllap x`, - r`\sqrt \mathllap x` - ]; - for (let i = 0; i < badArguments.length; i++) { - new Expect(badArguments[i]).toNotParse(); - } - const goodArguments = [ - r`\frac {\frac x y} z`, - r`\frac x {\frac y z}`, - r`\frac {\sqrt x} y`, - r`\frac x {\sqrt y}`, - r`\frac {\mathllap x} y`, - r`\frac x {\mathllap y}`, - r`\mathllap {\frac x y}`, - r`\mathllap {\mathllap x}`, - r`\sqrt {\mathllap x}` - ]; - for (let i = 0; i < goodArguments.length; i++) { - new Expect(goodArguments[i]).toParse(); - } - const badSupSubscripts = [ - r`x^\sqrt x`, - r`x^\mathllap x`, - r`x_\sqrt x`, - r`x_\mathllap x` - ]; - for (let i = 0; i < badSupSubscripts.length; i++) { - new Expect(badSupSubscripts[i]).toNotParse(); - } - const goodSupSubscripts = [ - r`x^{\sqrt x}`, - r`x^{\mathllap x}`, - r`x_{\sqrt x}`, - r`x_{\mathllap x}` - ]; - for (let i = 0; i < goodSupSubscripts.length; i++) { - new Expect(goodSupSubscripts[i]).toParse(); - } - new Expect(r`x''''`).toParse(); - new Expect(r`x_2''`).toParse(); - new Expect(r`x''_2`).toParse(); - new Expect(r`\sqrt^23`).toNotParse(); - new Expect(r`\frac^234`).toNotParse(); - new Expect(r`\frac2^34`).toNotParse(); - new Expect(r`\sqrt2^3`).toParse(); - new Expect(r`\frac23^4`).toParse(strictSettings()); - new Expect(r`\sqrt \frac x y`).toParse(); - new Expect(r`\sqrt \text x`).toParse(); - new Expect(r`x^\frac x y`).toParse(); - new Expect(r`x_\text x`).toParse(); - const badLeftArguments = [ - r`\frac \left( x \right) y`, - r`\frac x \left( y \right)`, - r`\mathllap \left( x \right)`, - r`\sqrt \left( x \right)`, - r`x^\left( x \right)` - ]; - for (let i = 0; i < badLeftArguments.length; i++) { - new Expect(badLeftArguments[i]).toNotParse(); - } - const goodLeftArguments = [ - r`\frac {\left( x \right)} y`, - r`\frac x {\left( y \right)}`, - r`\mathllap {\left( x \right)}`, - r`\sqrt {\left( x \right)}`, - r`x^{\left( x \right)}` - ]; - for (let i = 0; i < goodLeftArguments.length; i++) { - new Expect(goodLeftArguments[i]).toParse(); - } - - assertion = "An op symbol builder should build" - new Expect(r`\int_i^n`).toParse(); - new Expect(r`\iint_i^n`).toParse(); - new Expect(r`\iiint_i^n`).toParse(); - new Expect(r`\int\nolimits_i^n`).toParse(); - new Expect(r`\iint\nolimits_i^n`).toParse(); - new Expect(r`\iiint\nolimits_i^n`).toParse(); - new Expect(r`\oint_i^n`).toParse(); - new Expect(r`\oiint_i^n`).toParse(); - new Expect(r`\oiiint_i^n`).toParse(); - new Expect(r`\oint\nolimits_i^n`).toParse(); - new Expect(r`\oiint\nolimits_i^n`).toParse(); - new Expect(r`\oiiint\nolimits_i^n`).toParse(); - new Expect(r`\int_i^n`).toBuild(); - new Expect(r`\iint_i^n`).toBuild(); - new Expect(r`\iiint_i^n`).toBuild(); - new Expect(r`\int\nolimits_i^n`).toBuild(); - new Expect(r`\iint\nolimits_i^n`).toBuild(); - new Expect(r`\iiint\nolimits_i^n`).toBuild(); - new Expect(r`\oint_i^n`).toBuild(); - new Expect(r`\oiint_i^n`).toBuild(); - new Expect(r`\oiiint_i^n`).toBuild(); - new Expect(r`\oint\nolimits_i^n`).toBuild(); - new Expect(r`\oiint\nolimits_i^n`).toBuild(); - new Expect(r`\oiiint\nolimits_i^n`).toBuild(); - - assertion = "A style change parser should work" - new Expect(r`\displaystyle x`).toParse(); - new Expect(r`\textstyle x`).toParse(); - new Expect(r`\scriptstyle x`).toParse(); - new Expect(r`\scriptscriptstyle x`).toParse(); - const displayParse = parse(r`\displaystyle x`)[0]; - new Expect(displayParse.scriptLevel).toBe("display"); - const scriptscriptParse = parse(r`\scriptscriptstyle x`)[0]; - new Expect(scriptscriptParse.scriptLevel).toBe("scriptscript"); - const text = r`a b { c d \displaystyle e f } g h`; - const displayNode = parse(text)[2].body[2]; - new Expect(displayNode.type).toBe("styling"); - const displayBody = displayNode.body; - new Expect(displayBody).toHaveLength(2); - new Expect(displayBody[0].text).toBe("e"); - - assertion = "A font parser should work" - new Expect(r`\mathrm x`).toParse(); - new Expect(r`\mathbb x`).toParse(); - new Expect(r`\mathit x`).toParse(); - new Expect(r`\mathnormal x`).toParse(); - new Expect(r`\mathrm {x + 1}`).toParse(); - new Expect(r`\mathbb {x + 1}`).toParse(); - new Expect(r`\mathit {x + 1}`).toParse(); - new Expect(r`\mathnormal {x + 1}`).toParse(); - new Expect(r`\mathcal{ABC123}`).toParse(); - new Expect(r`\mathfrak{abcABC123}`).toParse(); - const mathbbParse = parse(r`\mathbb x`)[0]; - new Expect(mathbbParse.font).toBe("mathbb"); - new Expect(mathbbParse.type).toBe("font"); - const mathrmParse = parse(r`\mathrm x`)[0]; - new Expect(mathrmParse.font).toBe("mathrm"); - new Expect(mathrmParse.type).toBe("font"); - const mathitParse = parse(r`\mathit x`)[0]; - new Expect(mathitParse.font).toBe("mathit"); - new Expect(mathitParse.type).toBe("font"); - const mathnormalParse = parse(r`\mathnormal x`)[0]; - new Expect(mathnormalParse.font).toBe("mathnormal"); - new Expect(mathnormalParse.type).toBe("font"); - const mathcalParse = parse(r`\mathcal C`)[0]; - new Expect(mathcalParse.font).toBe("mathcal"); - new Expect(mathcalParse.type).toBe("font"); - const mathfrakParse = parse(r`\mathfrak C`)[0]; - new Expect(mathfrakParse.font).toBe("mathfrak"); - new Expect(mathfrakParse.type).toBe("font"); - const nestedParse = parse(r`\mathbb{R \neq \mathrm{R}}`)[0]; - new Expect(nestedParse.font).toBe("mathbb"); - new Expect(nestedParse.type).toBe("font"); - const bbBody = nestedParse.body.body; - new Expect(bbBody).toHaveLength(3); - new Expect(bbBody[0].type).toBe("mathord"); - new Expect(bbBody[2].type).toBe("font"); - new Expect(bbBody[2].font).toBe("mathrm"); - new Expect(bbBody[2].type).toBe("font"); - const colorMathbbParse = parse(r`\textcolor{blue}{\mathbb R}`)[0]; - new Expect(colorMathbbParse.type).toBe("color"); - new Expect(colorMathbbParse.color).toBe("#0000FF"); - const cbody = colorMathbbParse.body; - new Expect(cbody).toHaveLength(1); - new Expect(cbody[0].type).toBe("font"); - new Expect(cbody[0].font).toBe("mathbb"); - const bf = parse(r`\mathbf{a\mathrm{b}c}`)[0]; - new Expect(bf.type).toBe("font"); - new Expect(bf.font).toBe("mathbf"); - new Expect(bf.body.body).toHaveLength(3); - new Expect(bf.body.body[0].text).toBe("a"); - new Expect(bf.body.body[1].type).toBe("font"); - new Expect(bf.body.body[1].font).toBe("mathrm"); - new Expect(bf.body.body[2].text).toBe("c"); - new Expect(r`e^\mathbf{x}`).toParse(); - new Expect(r`\rm xyz`).toParseLike(r`\mathrm{xyz}`); - new Expect(r`\sf xyz`).toParseLike(r`\mathsf{xyz}`); - new Expect(r`\tt xyz`).toParseLike(r`\mathtt{xyz}`); - new Expect(r`\bf xyz`).toParseLike(r`\mathbf{xyz}`); - new Expect(r`\it xyz`).toParseLike(r`\mathit{xyz}`); - new Expect(r`\cal xyz`).toParseLike(r`\mathcal{xyz}`); - new Expect(r`\uptheta\varDelta`).toParse(strictSettings) - new Expect(r`\uptheta\varDelta`).toBuild() - - assertion = "A \\pmb builder should work" - new Expect(r`\pmb{\mu}`).toParse(); - new Expect(r`\pmb{=}`).toParse(); - new Expect(r`\pmb{+}`).toParse(); - new Expect(r`\pmb{\frac{x^2}{x_1}}`).toParse(); - new Expect(r`\pmb{}`).toParse(); - new Expect(r`\pmb{\mu}`).toBuild(); - new Expect(r`\pmb{=}`).toBuild(); - new Expect(r`\pmb{+}`).toBuild(); - new Expect(r`\pmb{\frac{x^2}{x_1}}`).toBuild(); - new Expect(r`\pmb{}`).toBuild(); - new Expect(r`\def\x{1}\pmb{\x\def\x{2}}`).toParseLike(r`\pmb{1}`); - - assertion = `A raise parser should work` - new Expect(r`\raisebox{5pt}{text}`).toParse(strictSettings()); - new Expect(r`\raisebox{-5pt}{text}`).toParse(strictSettings()); - new Expect(r`\vcenter{\frac a b}`).toParse(); - new Expect(r`\raisebox{5pt}{text}`).toBuild(strictSettings()); - new Expect(r`\raisebox{-5pt}{text}`).toBuild(strictSettings()); - new Expect(r`\vcenter{\frac a b}`).toBuild(); - new Expect(r`\raisebox{5pt}{\frac a b}`).toNotParse(); - new Expect(r`\raisebox{-5pt}{\frac a b}`).toNotParse(); - new Expect(r`\hbox{\frac a b}`).toNotParse(); - new Expect(r`\raisebox5pt{text}`).toNotParse(); - new Expect(r`\raisebox5pt{text}`).toNotParse(); - new Expect(r`\raisebox-5pt{text}`).toNotParse(); - - assertion = "A comment parser should work" - new Expect("a^2 + b^2 = c^2 % Pythagoras' Theorem\n").toParse(); - new Expect("% comment\n").toParse(); - new Expect("% comment 1\n% comment 2\n").toParse(); - new Expect("x_3 %comment\n^2").toParseLike(`x_3^2`); - new Expect("x^ %comment\n{2}").toParseLike(`x^{2}`); - new Expect("x^ %comment\n\\frac{1}{2}").toParseLike(r`x^\frac{1}{2}`); - new Expect("\\kern{1 %kern\nem}").toParse(); - new Expect("\\kern1 %kern\nem").toParse(); - new Expect("\\color{#f00%red\n}").toParse(); - new Expect("%comment\n{2}").toParseLike(`{2}`); - new Expect("\\begin{matrix}a&b\\\\ %hline\n\\hline %hline\n\\hline c&d\\end{matrix}").toParse(); - new Expect("\\def\\foo{a %}\nb}\n\\foo").toParseLike(`ab`); - new Expect("\\def\\foo{1\n2}\nx %\\foo\n").toParseLike(`x`); - new Expect(`x%y`).toNotParse(strictSettings()); - new Expect(`x%y`).toParse(); - new Expect("\\text{hello% comment 1\nworld}").toParseLike(r`\text{helloworld}`); - new Expect("\\text{hello% comment\n\nworld}").toParseLike(r`\text{hello world}`); - new Expect("5 % comment\n").toParseLike(`5`); - - assertion = "A font tree-builder should work" - let markup = temml.renderToString(r`\mathbb{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(''); - markup = temml.renderToString(r`\mathrm{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('R'); - markup = temml.renderToString(r`\mathcal{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(''); - markup = temml.renderToString(r`\mathfrak{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(''); - markup = temml.renderToString(r`\text{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('R'); - markup = temml.renderToString(r`\textit{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('𝑅'); - markup = temml.renderToString(r`\text{\textit{R}}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('𝑅'); - let markup1 = temml.renderToString(r`\textup{R}`).replace(mathTagRegEx, ""); - new Expect(markup1).toBe('R'); - let markup2 = temml.renderToString(r`\textit{\textup{R}}`).replace(mathTagRegEx, ""); - new Expect(markup2).toBe('R'); - let markup3 = temml.renderToString(r`\textup{\textit{R}}`).replace(mathTagRegEx, ""); - new Expect(markup3).toBe('𝑅'); - markup = temml.renderToString(r`\text{R\textit{S}T}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('R𝑆T'); - markup1 = temml.renderToString(r`\textmd{R}`).replace(mathTagRegEx, ""); - new Expect(markup1).toBe('R'); - markup2 = temml.renderToString(r`\textbf{\textmd{R}}`).replace(mathTagRegEx, ""); - new Expect(markup2).toBe('R'); - markup3 = temml.renderToString(r`\textmd{\textbf{R}}`).replace(mathTagRegEx, ""); - new Expect(markup3).toBe('𝐑'); - markup = temml.renderToString(r`\textsf{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('𝖱'); - markup = temml.renderToString(r`\textsf{\textit{R}G\textbf{B}}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('𝘙𝖦𝗕'); - markup = temml.renderToString(r`\texttt{R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe('𝚁'); - assertion = "A font tree-builder should render a combination of font and color changes" - markup = temml.renderToString(r`\textcolor{blue}{\mathbb R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(''); - markup = temml.renderToString(r`\mathbb{\textcolor{blue}{R}}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(''); - assertion = "A font tree-builder should render wide characters with and with the correct font" - markup = temml.renderToString("𝐀").replace(mathTagRegEx, ""); - new Expect(markup).toBe('𝐀'); - - assertion = "A parser should throw an error when the expression is of the wrong type" - new Expect([1, 2]).toNotParse() - new Expect({ badInputType: "yes" }).toNotParse() - new Expect(undefined).toNotParse() - new Expect(null).toNotParse() - new Expect(1.234).toNotParse() - assertion = "A parser should work when the expression is of the correct type" - new Expect(r`\sqrt{123}`).toParse() - new Expect(new String(r`\sqrt{123}`)).toParse() - - assertion = "A font tree-builder should render the correct mathvariants" - markup = temml.renderToString(r`Ax2k\omega\Omega\imath+`).replace(mathTagRegEx, ""); - new Expect(markup).toContain("A"); - new Expect(markup).toContain("x"); - new Expect(markup).toContain("2"); - new Expect(markup).toContain("ω"); // \omega - new Expect(markup).toContain('Ω'); // \Omega - new Expect(markup).toContain('ı'); // \imath - new Expect(markup).toContain("+"); - markup = temml.renderToString(r`\mathbb{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe("𝔸𝕩𝟚𝕜ωΩı+"); - markup = temml.renderToString(r`\mathrm{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toContain("A"); - new Expect(markup).toContain("x"); - new Expect(markup).toContain("2"); - new Expect(markup).toContain("ω"); // \omega - new Expect(markup).toContain("Ω"); // \Omega - new Expect(markup).toContain("ı"); // \imath - new Expect(markup).toContain("+"); - markup = temml.renderToString(r`\mathit{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(`Ax2kωΩı+`); - markup = temml.renderToString(r`\mathnormal{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toContain("A"); - new Expect(markup).toContain("x"); - new Expect(markup).toContain("2"); - new Expect(markup).toContain("ω"); // \omega - new Expect(markup).toContain("Ω"); // \Omega - new Expect(markup).toContain("ı"); // \imath - new Expect(markup).toContain("+"); - markup = temml.renderToString(r`\mathbf{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(`𝐀𝐱𝟐𝐤𝛚𝛀ı+`); - markup = temml.renderToString(r`\mathcal{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(`𝒜𝓍2𝓀ωΩı+`); - markup = temml.renderToString(r`\mathfrak{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(`𝔄𝔵2𝔨ωΩı+`); - markup = temml.renderToString(r`\mathscr{A}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(`𝒜`); - markup = temml.renderToString(r`\mathsf{Ax2k\omega\Omega\imath+}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(`𝖠𝗑𝟤𝗄𝞈𝝮ı+`); - - assertion = "A font tree-builder should render a combination of font and color changes" - markup = temml.renderToString(r`\textcolor{blue}{\mathbb R}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(``); - // reverse the order of the commands - markup = temml.renderToString(r`\mathbb{\textcolor{blue}{R}}`).replace(mathTagRegEx, ""); - new Expect(markup).toBe(``); - - assertion = "A font tree-builder should render text as " - markup = temml.renderToString(r`\text{for }`); - new Expect(markup).toContain("for\u00a0"); - - assertion = "A font tree-builder should render math within text as side-by-side children" - markup = temml.renderToString(r`\text{graph: $y = mx + b$}`); - new Expect(markup).toContain("y=mx+b"); - - assertion = "An includegraphics builder should work" - const img = "\\includegraphics[height=0.9em, totalheight=0.9em, width=0.9em, alt=KA logo]{https://cdn.kastatic.org/images/apple-touch-icon-57x57-precomposed.new.png}"; - new Expect(img).toNotParse() // no trust - new Expect(img, trustSettings()).toNotBuild(); - new Expect(img).toParse(trustSettings()) // no trust - markup = temml.renderToString(img, trustSettings()).replace(mathTagRegEx, ""); - new Expect(markup).toBe(`KA logo`); - - assertion = "An HTML extension builder should work" - const html = r`\id{bar}{x}\class{foo}{x}\style{color: red;}{x}\data{foo=a, bar=b}{x}`; - new Expect(html).toParse(trustSettings()); - new Expect(html).toBuild(trustSettings()); - let built = build(html, trustSettings())[0].children[0].children; - new Expect(built[0].attributes.id).toBe("bar"); - new Expect(built[1].classes).toContain("foo"); - new Expect(built[2].attributes.style).toBe("color: red;"); - - assertion = "A bin parser should work" - new Expect(parse('x + y')[1].family).toBe("bin") - new Expect(parse('+ x')[0].family).toBe("bin") - new Expect(parse(r`x + + 2`)[3].type).toBe("textord"); - new Expect(parse(r`( + 2`)[2].type).toBe("textord"); - new Expect(parse(r`= + 2`)[2].type).toBe("textord"); - new Expect(parse(r`\sin + 2`)[2].type).toBe("textord"); - new Expect(parse(r`, + 2`)[2].type).toBe("textord"); - new Expect(parse(r`\textcolor{blue}{x}+y`)[1].family).toBe("bin"); - new Expect(parse(r`\textcolor{blue}{x+}+y`)[2].type).toBe("mathord"); - - assertion = "A phantom and smash parser should work" - new Expect(parse(r`\hphantom{a}`)[0].type).toBe("hphantom"); - new Expect(parse(r`a\hphantom{=}b`)[2].type).toBe("mathord"); - new Expect(parse(r`\smash{a}`)[0].type).toBe("smash"); - new Expect(parse(r`a\smash{+}b`)[2].type).toBe("mathord"); - - assertion = "A markup generator should work" - // Just a few quick sanity checks here... - markup = temml.renderToString(r`\sigma^2`); - new Expect(markup.indexOf(" context.protocol === "ftp"})) - new Expect("\\href{ftp://x}{foo}").toBuild(new Settings({trust: (context) => context.protocol === "ftp"})) - assertion = "href and url commands should allow all protocols when trust option is true" - new Expect("\\href{ftp://x}{foo}").toParse(trustSettings()) - new Expect("\\href{ftp://x}{foo}").toBuild(trustSettings()) - assertion = "href and url commands should not allow explicitly disallowed protocols" - new Expect("\\href{javascript:alert('x')}{foo}").toNotParse(new Settings({trust: context => context.protocol !== "javascript"})) - - assertion = "The symbol table integrity should treat certain symbols as synonyms" - new Expect(`<`).toBuildLike(r`\lt`) - new Expect(`>`).toBuildLike(r`\gt`) - new Expect(r`\left<\frac{1}{x}\right>`).toBuildLike(r`\left\lt\frac{1}{x}\right\gt`) - - assertion = "Symbols should support AMS symbols in both text and math mode" - new Expect(r`\yen\checkmark\circledR\maltese`).toBuild(strictSettings()) - new Expect(r`\text{\yen\checkmark\circledR\maltese}`).toBuild(strictSettings()) - new Expect(r`\yen\checkmark\circledR\maltese`).toParse(strictSettings()) - new Expect(r`\text{\yen\checkmark\circledR\maltese}`).toParse(strictSettings()) - - assertion = "A macro expander should produce individual tokens" - new Expect(r`e^\foo`).toParseLike("e^a 23", new Settings({macros: {"\\foo": "a23"}})) - new Expect(r`e^\foo`).toParseLike("e^1 23", new Settings({strict: true, macros: {"\\foo": "123"}})) - assertion = "A macro expander should preserve leading spaces inside macro definition" - new Expect(r`\text{\foo}`).toParseLike(r`\text{ x}`, new Settings({macros: {"\\foo": " x"}})) - assertion = "A macro expander should preserve leading spaces inside macro argument" - new Expect(r`\text{\foo{ x}}`).toParseLike(r`\text{ x}`, new Settings({macros: {"\\foo": "#1"}})) - assertion = "A macro expander should ignore expanded spaces in math mode" - new Expect(r`\foo`).toParseLike("x", new Settings({macros: {"\\foo": " x"}})) - assertion = "A macro expander should consume spaces after control-word macro" - new Expect(r`\text{\foo }`).toParseLike(r`\text{x}`, new Settings({macros: {"\\foo": "x"}})) - assertion = "A macro expander should consume spaces after macro with \\relax" - new Expect(r`\text{\foo }`).toParseLike(r`\text{}`, new Settings({macros: {"\\foo": "\\relax"}})) - assertion = "A macro expander not should consume spaces after control-word expansion" - new Expect(r`\text{\\ }`).toParseLike(r`\text{ }`, new Settings({macros: {"\\\\": "\\relax"}})) - assertion = "A macro expander should consume spaces after \\relax" - new Expect(r`\text{\relax }`).toParseLike(r`\text{}`) - assertion = "A macro expander should consume spaces after control-word function" - new Expect(r`\text{\yen }`).toParseLike(r`\text{\yen}`) - assertion = "A macro expander should preserve spaces after control-symbol macro" - new Expect(r`\text{\% y}`).toParseLike(r`\text{x y}`, new Settings({macros: {"\\%": "x"}})) - assertion = "A macro expander should preserve spaces after control-symbol function" - new Expect(r`\text{\' }`).toParse() - assertion = "A macro expander should consume spaces between arguments" - new Expect(r`\text{\foo a 2}`).toParseLike(r`\text{a2end}`, new Settings({macros: {"\\foo": "#1#2end"}})) - new Expect(r`\text{\foo {a} {2}}`).toParseLike(r`\text{a2end}`, new Settings({macros: {"\\foo": "#1#2end"}})) - assertion = "A macro expander should allow for multiple expansion" - new Expect(r`1\foo2`).toParseLike("1aa2", new Settings({macros: { - "\\foo": "\\bar\\bar", - "\\bar": "a", - }})) - assertion = "A macro expander should allow for multiple expansion with argument" - new Expect(r`1\foo2`).toParseLike("1 2 2 2 2", new Settings({macros: { - "\\foo": "\\bar{#1}\\bar{#1}", - "\\bar": "#1#1", - }})) - assertion = "A macro expander should allow for macro argument" - new Expect(r`\foo\bar`).toParseLike("(xyz)", new Settings({macros: { - "\\foo": "(#1)", - "\\bar": "xyz", - }})) - assertion = "A macro expander should allow properly nested group for macro argument" - new Expect(r`\foo{e^{x_{12}+3}}`).toParseLike("(e^{x_{12}+3})", new Settings({macros: {"\\foo": "(#1)"}})) - - assertion = "A macro expander should delay expansion if preceded by \\expandafter" - new Expect(r`\expandafter\foo\bar`).toParseLike("x+y", new Settings({macros: { - "\\foo": "#1+#2", - "\\bar": "xy", - }})) - // \def is not expandable, i.e., \expandafter doesn't define the macro - new Expect(r`\def\foo{x}\def\bar{\def\foo{y}}\expandafter\bar\foo`).toParseLike(`x`) - - assertion = "A macro expander should not expand if preceded by \\noexpand" - // \foo is not expanded and interpreted as if its meaning were \relax - new Expect(r`\noexpand\foo y`).toParseLike(r`y`, new Settings({macros: {"\\foo": "x"}})) - new Expect(r`\expandafter\foo\noexpand\foo`).toParseLike("x", new Settings({macros: {"\\foo": "x"}})) - new Expect(r`\noexpand\frac xy`).toParseLike(`xy`) - new Expect(r`\noexpand\def\foo{xy}\foo`).toParseLike(`xy`) - - assertion = "A macro expander should allow for space macro argument (text version)" - new Expect(r`\text{\foo\bar}`).toParseLike(r`\text{( )}`, new Settings({macros: { - "\\foo": "(#1)", - "\\bar": " ", - }})) - - assertion = "A macro expander should allow for space macro argument (math version)" - new Expect(r`\foo\bar`).toParseLike("()", new Settings({macros: { - "\\foo": "(#1)", - "\\bar": " ", - }})) - - assertion = "A macro expander should allow for second argument (text version)" - new Expect(r`\text{\foo\bar\bar}`).toParseLike(r`\text{( , )}`, new Settings({macros: { - "\\foo": "(#1,#2)", - "\\bar": " ", - }})) - - assertion = "A macro expander should allow for second argument (math version)" - new Expect(r`\foo\bar\bar`).toParseLike("(,)", new Settings({macros: { - "\\foo": "(#1,#2)", - "\\bar": " ", - }})) - - assertion = "A macro expander should allow for empty macro argument" - new Expect(r`\foo\bar`).toParseLike("()", new Settings({macros: { - "\\foo": "(#1)", - "\\bar": "", - }})) - - assertion = "A macro expander should allow for space function arguments" - new Expect(r`\frac\bar\bar`).toParseLike(r`\frac{}{}`, new Settings({macros: { "\\bar": " " }})) - - assertion = "A macro expander should allow aliasing characters" - new Expect(r`x’=c`).toParseLike("x'=c", new Settings({macros: { "’": "'" }})) - - assertion = "In a macro expander, \\@firstoftwo should consume both, and avoid errors" - new Expect(r`\@firstoftwo{yes}{no}`).toParseLike("yes") - new Expect(r`\@firstoftwo{yes}{1'_2^3}`).toParseLike("yes") - - assertion = "In a macro expander, \\@ifstar should consume star but nothing else" - new Expect(r`\@ifstar{yes}{no}*!`).toParseLike("yes!") - new Expect(r`\@ifstar{yes}{no}?!`).toParseLike("no?!") - - assertion = "In a macro expander, \\@ifnextchar should not consume nonspaces" - new Expect(r`\@ifnextchar!{yes}{no}!!`).toParseLike("yes!!") - new Expect(r`\@ifnextchar!{yes}{no}?!`).toParseLike("no?!") - - assertion = "In a macro expander, \\@ifnextchar should consume spaces" - new Expect(r`\def\x#1{\@ifnextchar x{yes}{no}}\x{}x\x{} x`).toParseLike("yesxyesx") - - assertion = "In a macro expander, \\@ifstar should consume star but nothing else" - new Expect(r`\@ifstar{yes}{no}*!`).toParseLike("yes!") - new Expect(r`\@ifstar{yes}{no}?!`).toParseLike("no?!") - - assertion = "In a macro expander, \\def defines macros" - new Expect(r`\def\foo{x^2}\foo+\foo`).toParseLike(`x^2+x^2`) - new Expect(r`\def\foo{hi}\foo+\text\foo`).toParseLike(r`hi+\text{hi}`) - new Expect(r`\def\foo#1{hi #1}\text{\foo{Alice}, \foo{Bob}}`).toParseLike(r`\text{hi Alice, hi Bob}`) - new Expect(r`\def\foo#1#2{(#1,#2)}\foo 1 2+\foo 3 4`).toParseLike(r`(1, 2)+(3, 4)`) - new Expect(r`\def\foo#a{}`).toNotParse() - new Expect(r`\def\foo#1#2#3#4#5#6#7#8#9{}`).toParse() - new Expect(r`\def\foo#2{}`).toNotParse() - new Expect(r`\def\foo#1#2#3#4#5#6#7#8#9#10{}`).toNotParse() - new Expect(r`\def\foo1`).toNotParse() - new Expect(r`\def{\foo}{}`).toNotParse() - new Expect(r`\def\foo\bar`).toNotParse() - new Expect(r`\def{\foo\bar}{}`).toNotParse() - new Expect(r`\def{}{}`).toNotParse() - - assertion = "In a macro expander, \\def defines macros with delimited parameter" - new Expect(r`\def\foo|#1||{#1}\text{\foo| x y ||}`).toParseLike(r`\text{ x y }`) - new Expect(r`\def\foo#1|#2{#1+#2}\foo a 2 |34`).toParseLike(r`a2+34`) - new Expect(r`\def\foo#1#{#1}\foo1^{23}`).toParseLike(r`1^{23}`) - new Expect(r`\def\foo|{}\foo`).toNotParse() - new Expect(r`\def\foo#1|{#1}\foo1`).toNotParse() - new Expect(r`\def\foo#1|{#1}\foo1}|`).toNotParse() - - assertion = "In a macro expander, \\edef should expand definition" - new Expect(r`\def\foo{a}\edef\bar{\foo}\def\foo{}\bar`).toParseLike(`a`) - // \def\noexpand\foo{} expands into \def\foo{} - new Expect(r`\def\foo{a}\edef\bar{\def\noexpand\foo{}}\foo\bar\foo`).toParseLike(r`a`) - // \foo\noexpand\foo expands into a\foo - new Expect(r`\def\foo{a}\edef\bar{\foo\noexpand\foo}\def\foo{b}\bar`).toParseLike(r`ab`) - // \foo is not defined - new Expect(r`\edef\bar{\foo}`).toNotParse(strictSettings()) - - assertion = "In a macro expander, \\long needs to be followed by macro prefixes, \\def or \\edef" - new Expect(r`\long\def\foo{}\foo`).toParseLike("") - new Expect(r`\long\edef\foo{}\foo`).toParseLike("") - new Expect(r`\long\foo`).toNotParse() - - assertion = "In a macro expander, \\let copies the definition" - new Expect(r`\let\foo=\frac\def\frac{}\foo1a`).toParseLike(r`\frac1a`) - new Expect(r`\def\foo{1}\let\bar\foo\def\foo{2}\bar`).toParseLike(r`1`) - new Expect(r`\let\foo=\kern\edef\bar{\foo1em}\let\kern=\relax\bar`).toParseLike(r`\kern1em`) - // \foo = { (left brace) - new Expect(r`\let\foo{\sqrt\foo1}`).toParseLike(r`\sqrt{1}`) - // \equals = = (equal sign) - new Expect(r`\let\equals==a\equals b`).toParseLike(r`a=b`) - // \foo should not be expandable and not affected by \noexpand or \edef - new Expect(r`\let\foo=x\noexpand\foo`).toParseLike(r`x`) - new Expect(r`\let\foo=x\edef\bar{\foo}\def\foo{y}\bar`).toParseLike(r`y`) - - assertion = "In a macro expander, \\let should consume one optional space after equals sign" - // https://tex.stackexchange.com/questions/141166/let-foo-bar-vs-let-foo-bar-let-with-equals-sign - new Expect(r`\def\:{\let\space= }\: \text{\space}`).toParseLike(r`\text{ }`) - - assertion = "In a macro expander, \\futurelet should parse correctly" - new Expect(r`\futurelet\foo\frac1{2+\foo}`).toParseLike(r`\frac1{2+1}`) - - assertion = "In a macro expander, \\newcommand defines new macros" - new Expect(r`\newcommand\foo{x^2}\foo+\foo`).toParseLike(`x^2+x^2`, strictSettings()) - new Expect(r`\newcommand{\foo}{x^2}\foo+\foo`).toParseLike(`x^2+x^2`, strictSettings()) - // Function detection - new Expect(r`\newcommand\bar{x^2}\bar+\bar`).toNotParse() - new Expect(r`\newcommand{\bar}{x^2}\bar+\bar`).toNotParse() - // Symbol detection - new Expect(r`\newcommand\lambda{x^2}\lambda`).toNotParse() - new Expect(r`\newcommand\textdollar{x^2}\textdollar`).toNotParse() - // Macro detection - new Expect(r`\newcommand{\foo}{1}\foo\newcommand{\foo}{2}\foo`).toNotParse() - // Implicit detection - new Expect(r`\newcommand\limits{}`).toNotParse() - - assertion = "In a macro expander, \\renewcommand redefines macro" - new Expect(r`\renewcommand\foo{x^2}\foo+\foo`).toNotParse(strictSettings()) - new Expect(r`\renewcommand{\foo}{x^2}\foo+\foo`).toNotParse(strictSettings()) - new Expect(r`\renewcommand\bar{x^2}\bar+\bar`).toParseLike(r`x^2+x^2`, strictSettings()) - new Expect(r`\renewcommand{\bar}{x^2}\bar+\bar`).toParseLike(r`x^2+x^2`, strictSettings()) - new Expect(r`\newcommand{\foo}{1}\foo\renewcommand{\foo}{a}\foo`).toParseLike(r`1a`, strictSettings()) - - assertion = "In a macro expander, \\providecommand (re)defines macros" - new Expect(r`\providecommand\foo{x^2}\foo+\foo`).toParseLike(r`x^2+x^2`, strictSettings()) - new Expect(r`\providecommand{\foo}{x^2}\foo+\foo`).toParseLike(r`x^2+x^2`, strictSettings()) - new Expect(r`\providecommand\bar{x^2}\bar+\bar`).toParseLike(r`x^2+x^2`, strictSettings()) - new Expect(r`\providecommand{\bar}{x^2}\bar+\bar`).toParseLike(r`x^2+x^2`, strictSettings()) - new Expect(r`\newcommand{\foo}{1}\foo\providecommand{\foo}{b}\foo`).toParseLike(r`1b`, strictSettings()) - new Expect(r`\providecommand{\foo}{1}\foo\renewcommand{\foo}{b}\foo`).toParseLike(r`1b`, strictSettings()) - new Expect(r`\providecommand{\foo}{1}\foo\providecommand{\foo}{b}\foo`).toParseLike(r`1b`, strictSettings()) - - assertion = "In a macro expander, \\newcommand accepts number of arguments" - new Expect(r`\newcommand\foo[1]{#1^2}\foo x+\foo{y}`).toParseLike(r`x^2+y^2`, strictSettings()) - new Expect(r`\newcommand\foo[9]{#1^2}\foo abcdefghi`).toParseLike(r`a^2`, strictSettings()) - new Expect(r`\newcommand\foo[x]{}`).toNotParse(strictSettings()) - new Expect(r`\newcommand\foo[1.5]{}`).toNotParse(strictSettings()) - - // This may change in the future, if we support the extra features of \hspace. - assertion = "A macro expander should treat \\hspace, \\hskip like \\kern" - new Expect(r`\hspace{1em}`).toParseLike(r`\kern1em`) - new Expect(r`\hskip{1em}`).toParseLike(r`\kern1em`) - - assertion = "A macro expander should expand \\limsup and \\liminf as expected" - new Expect(r`\limsup`).toParseLike(r`\operatorname*{lim\,sup}`) - new Expect(r`\liminf`).toParseLike(r`\operatorname*{lim\,inf}`) - - assertion = "A macro expander should expand AMS log-like symbols as expected" - new Expect(r`\injlim`).toParseLike(r`\operatorname*{inj\,lim}`) - new Expect(r`\projlim`).toParseLike(r`\operatorname*{proj\,lim}`) - new Expect(r`\varlimsup`).toParseLike(r`\operatorname*{\overline{\text{lim}}}`) - new Expect(r`\varliminf`).toParseLike(r`\operatorname*{\underline{\text{lim}}}`) - new Expect(r`\varinjlim`).toParseLike(r`\operatorname*{\underrightarrow{\text{lim}}}`) - new Expect(r`\varinjlim`).toParseLike(r`\operatorname*{\underrightarrow{\text{lim}}}`) - new Expect(r`\varprojlim`).toParseLike(r`\operatorname*{\underleftarrow{\text{lim}}}`) - - assertion = "A macro expander should expand \\plim and \\argmin and \\argmax as expected" - new Expect(r`\plim`).toParseLike(r`\operatorname*{plim}`) - new Expect(r`\argmin`).toParseLike(r`\operatorname*{arg\,min}`) - new Expect(r`\argmax`).toParseLike(r`\operatorname*{arg\,max}`) - - assertion = "A macro expander should expand \\bra and \ket as expected" - new Expect(r`\bra{\phi}`).toParseLike(r`\mathinner{\langle{\phi}|}`) - new Expect(r`\ket{\psi}`).toParseLike(r`\mathinner{|{\psi}\rangle}`) - new Expect(r`\braket{\phi|\psi}`).toParseLike(r`\mathinner{\langle{\phi|\psi}\rangle}`) - new Expect(r`\Bra{\phi}`).toParseLike(r`\left\langle\phi\right|`) - new Expect(r`\Ket{\psi}`).toParseLike(r`\left|\psi\right\rangle`) - - assertion = "Macro arguments do not generate groups" - new Expect("\\def\\x{a}\\x\\def\\foo#1{#1}\\foo{\\x\\def\\x{b}\\x}\\x").toParseLike(`aabb`) - - assertion = "\\gdef or \\xdef should produce an error" - new Expect(temml.renderToString("\gdef\foo{Nope}")).toContain("#b22222") // color of error message - new Expect(temml.renderToString("\xdef\foo{Nope}")).toContain("#b22222") - - assertion = "A preamble should capture viable macros and definecolor." - let macros = temml.definePreamble(r`\definecolor{sortaGreen}{RGB}{128,128,0}`) - new Expect(r`\color{sortaGreen} F=ma`).toParse(new Settings({macros})) - macros = temml.definePreamble(r`\def\foo{x^2}`) - markup = temml.renderToString(r`\foo + \foo`, new Settings({macros})) - new Expect(markup).toContain(``) - macros = temml.definePreamble(r`\newcommand\d[0]{\operatorname{d}\!}`) - markup = temml.renderToString(r`\d x`, new Settings({macros})) - new Expect(markup).toContain(``) - - assertion = "\\textbf arguments do generate groups" - new Expect("\\def\\x{a}\\x\\textbf{\\x\\def\\x{b}\\x}\\x").toParseLike(r`a\textbf{ab}a`) - - assertion = "\\sqrt optional arguments generate groups" - new Expect("\\def\\x{a}\\def\\y{a}\\x\\y" + "\\sqrt[\\def\\x{b}\\x]{\\def\\y{b}\\y}\\x\\y").toParseLike(r`aa\sqrt[b]{b}aa`) - - assertion = "Array cells generate groups" - new Expect(r`\def\x{a}\begin{matrix}\x&\def\x{b}\x&\x\end{matrix}\x`).toParseLike(r`\begin{matrix}a&b&a\end{matrix}a`) - new Expect(r`\def\x{1}\begin{matrix}\def\x{2}\x&\x\end{matrix}\x`).toParseLike(r`\begin{matrix}2&1\end{matrix}1`) - - assertion = "\\char produces literal characters" - new Expect("\\char`a").toParseLike("\\char`\\a"); - new Expect("\\char`\\%").toParseLike("\\char37"); - new Expect("\\char`\\%").toParseLike("\\char'45"); - new Expect("\\char`\\%").toParseLike('\\char"25'); - new Expect("\\char").toNotParse(); - new Expect("\\char`").toNotParse(); - new Expect("\\char'").toNotParse(); - new Expect('\\char"').toNotParse(); - new Expect("\\char'a").toNotParse(); - new Expect('\\char"g').toNotParse(); - new Expect('\\char"g').toNotParse(); - - assertion = "Unicode private area characters should build" - new Expect(r`\gvertneqq\lvertneqq\ngeqq\ngeqslant\nleqq`).toParse() - new Expect(r`\nleqslant\nshortmid\nshortparallel\varsubsetneq`).toParse() - new Expect(r`\varsubsetneqq\varsupsetneq\varsupsetneqq`).toParse() - new Expect(r`\gvertneqq\lvertneqq\ngeqq\ngeqslant\nleqq`).toBuild() - new Expect(r`\nleqslant\nshortmid\nshortparallel\varsubsetneq`).toBuild() - new Expect(r`\varsubsetneqq\varsupsetneq\varsupsetneqq`).toBuild() - - assertion = "\\overset and \\underset should work" - new Expect(r`\overset{f}{\rightarrow} Y`).toParse() - new Expect("\\underset{f}{\\rightarrow} Y").toParse() - new Expect(r`\overset{f}{\rightarrow} Y`).toBuild() - new Expect("\\underset{f}{\\rightarrow} Y").toBuild() - - assertion = "\\iff, \\implies, and \\impliedby should work" - new Expect(r`X \iff Y`).toParse() - new Expect(r`X \implies Y`).toParse() - new Expect(r`X \impliedby Y`).toParse() - new Expect(r`X \iff Y`).toBuild() - new Expect(r`X \implies Y`).toBuild() - new Expect(r`X \impliedby Y`).toBuild() - - assertion = "\\tag support should fail outside display mode" - new Expect(r`\tag{hi}x+y`).toNotParse() - assertion = "\\tag support should fail with multiple tags" - new Expect(r`\tag{1}\tag{2}x+y`).toNotParse(displayMode()) - assertion = "\\tag should build" - new Expect(r`\tag{hi}x+y`).toParse(displayMode()); - new Expect(r`\tag{hi}x+y`).toBuild(displayMode()); - assertion = "\\tag support should ignore location of \\tag" - new Expect(r`\tag{hi}x+y`).toParseLike(r`x+y\tag{hi}`, displayMode()); - assertion = "\\tag support should handle \\tag* like \\tag" - new Expect(r`\tag{hi}x+y`).toParseLike(r`\tag*{({hi})}x+y`, displayMode()); - assertion = "\\tag support should add tml-tageqn class" - new Expect(temml.renderToString(r`\tag{hi}x+y`, displayMode())).toContain("tml-tageqn") - assertion = "leqno rendering option should differ from default" - new Expect(temml.renderToString(r`\tag{hi}x+y`, new Settings({ displayMode: true, leqno: true }))).toContain("rspace") - new Expect(temml.renderToString(r`\tag{hi}x+y`,displayMode())).toNotContain("rspace") - - assertion = "\\@binrel automatic bin/rel/ord should generate proper class" - new Expect(parse("L\\@binrel+xR")[1].mclass).toBe("mbin") - new Expect(parse("L\\@binrel=xR")[1].mclass).toBe("mrel") - new Expect(parse("L\\@binrel xxR")[1].mclass).toBe("mord") - new Expect(parse("L\\@binrel=xR")[1].mclass).toBe("mrel") - new Expect(parse("L\\@binrel{+}{x}R")[1].mclass).toBe("mbin") - new Expect(parse("L\\@binrel{=}{x}R")[1].mclass).toBe("mrel") - new Expect(parse("L\\@binrel{z}{x}R")[1].mclass).toBe("mord") - assertion = "\\@binrel automatic bin/rel/ord should base on just first character in group" - new Expect(parse("L\\@binrel{+x}xR")[1].mclass).toBe("mbin") - new Expect(parse("L\\@binrel{=x}xR")[1].mclass).toBe("mrel") - new Expect(parse("L\\@binrel{xx}xR")[1].mclass).toBe("mord") - - assertion = "A parser taking String objects should not fail on an empty String object" - new Expect(new String("")).toParse() - new Expect(new String("")).toBuild() - assertion = "A parser taking String objects should parse the same as a regular string" - new Expect(new String("xy")).toParseLike(`xy`) - new Expect(new String(r`\div`)).toParseLike(r`\div`) - new Expect(new String(r`\frac 1 2`)).toParseLike(r`\frac 1 2`) - - assertion = "Unicode accents should parse Latin-1 letters in math mode" - new Expect(`ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüýÿ`).toParseLike( - r`\grave A\acute A\hat A\tilde A\ddot A\mathring A` + - r`\grave E\acute E\hat E\ddot E` + - r`\grave I\acute I\hat I\ddot I` + - r`\tilde N` + - r`\grave O\acute O\hat O\tilde O\ddot O` + - r`\grave U\acute U\hat U\ddot U` + - r`\acute Y` + - r`\grave a\acute a\hat a\tilde a\ddot a\mathring a` + - r`\grave e\acute e\hat e\ddot e` + - r`\grave ı\acute ı\hat ı\ddot ı` + - r`\tilde n` + - r`\grave o\acute o\hat o\tilde o\ddot o` + - r`\grave u\acute u\hat u\ddot u` + - r`\acute y\ddot y` - ) - - assertion = "Unicode accents should parse Latin-1 letters in text mode" - new Expect(`\\text{ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüýÿ}`).toParseLike( - r`\text{\`A\'A\^A\~A\"A\r A` + - r`\`E\'E\^E\"E` + - r`\`I\'I\^I\"I` + - r`\~N` + - r`\`O\'O\^O\~O\"O` + - r`\`U\'U\^U\"U` + - r`\'Y` + - r`\`a\'a\^a\~a\"a\r a` + - r`\`e\'e\^e\"e` + - r`\`ı\'ı\^ı\"ı` + - r`\~n` + - r`\`o\'o\^o\~o\"o` + - r`\`u\'u\^u\"u` + - r`\'y\"y}` - ) - - assertion = "Unicode accents should parse combining characters" - new Expect("A\u0301C\u0301").toParseLike(r`Á\acute C`); - new Expect("\\text{A\u0301C\u0301}").toParseLike(r`\text{Á\'C}`, strictSettings()); - - assertion = "Unicode accents should build multi-accented characters" - new Expect(`ấā́ắ\text{ấā́ắ}`).toParse() - new Expect(`ấā́ắ\text{ấā́ắ}`).toBuild() - - assertion = "Unicode accents should parse accented i's and j's" - new Expect(`íȷ́`).toParseLike(r`\acute ı\acute ȷ`); - new Expect(`ấā́ắ\text{ấā́ắ}`).toParse(); - new Expect(`ấā́ắ\text{ấā́ắ}`).toBuild(); - - assertion = "Temml should build Unicode relations" - new Expect(`∈∋∝∼∽≂≃≅≈≊≍≎≏≐≑≒≓≖≗≜≡≤≥≦≧≪≫≬≳≷≺≻≼≽≾≿∴∵∣≔≕⩴⋘⋙⟂⊨∌⊶⊷⊂⊃⊆⊇⊏⊐⊑⊒⊢⊣⊩⊪⊸⋈⋍⋐⋑⋔⋛⋞⋟⌢⌣⩾⪆⪌⪕⪖⪯⪰⪷⪸⫅⫆≘≙≚≛≝≞≟≲⩽⪅≶⋚⪋`).toParse() - new Expect(`∈∋∝∼∽≂≃≅≈≊≍≎≏≐≑≒≓≖≗≜≡≤≥≦≧≪≫≬≳≷≺≻≼≽≾≿∴∵∣≔≕⩴⋘⋙⟂⊨∌⊶⊷⊂⊃⊆⊇⊏⊐⊑⊒⊢⊣⊩⊪⊸⋈⋍⋐⋑⋔⋛⋞⋟⌢⌣⩾⪆⪌⪕⪖⪯⪰⪷⪸⫅⫆≘≙≚≛≝≞≟≲⩽⪅≶⋚⪋`).toBuild() - assertion = "Temml should build Unicode negated relations" - new Expect(`∉∤∦≁≆≠≨≩≮≯≰≱⊀⊁⊈⊉⊊⊋⊬⊭⊮⊯⋠⋡⋦⋧⋨⋩⋬⋭⪇⪈⪉⪊⪵⪶⪹⪺⫋⫌`).toParse() - new Expect(`∉∤∦≁≆≠≨≩≮≯≰≱⊀⊁⊈⊉⊊⊋⊬⊭⊮⊯⋠⋡⋦⋧⋨⋩⋬⋭⪇⪈⪉⪊⪵⪶⪹⪺⫋⫌`).toBuild() - assertion = "Temml should build Unicode big operators" - new Expect(`∏∐∑∫∬∭∮⋀⋁⋂⋃⨀⨁⨂⨄⨆`).toParse() - new Expect(`∏∐∑∫∬∭∮⋀⋁⋂⋃⨀⨁⨂⨄⨆`).toBuild() - assertion = "Temml should build Unicode symbols" - new Expect(`£¥ℂℍℑℎℓℕ℘ℙℚℜℝℤℲℵðℶℷℸ⅁∀∁∂∃∇∞∠∡∢♠♡♢♣♭♮♯✓°¬‼⋮\u00B7\u00A9\\text{£¥ℂℍℎ\u00A9\u00AE\uFE0F}`).toParse() - new Expect(`£¥ℂℍℑℎℓℕ℘ℙℚℜℝℤℲℵðℶℷℸ⅁∀∁∂∃∇∞∠∡∢♠♡♢♣♭♮♯✓°¬‼⋮\u00B7\u00A9\\text{£¥ℂℍℎ\u00A9\u00AE\uFE0F}`).toBuild() - assertion = "Temml should build capital Greek letters" - new Expect(`\u0391\u0392\u0395\u0396\u0397\u0399\u039A\u039C\u039D\u039F\u03A1\u03A4\u03A7\u03DD`).toParse(strictSettings()) - new Expect(`\u0391\u0392\u0395\u0396\u0397\u0399\u039A\u039C\u039D\u039F\u03A1\u03A4\u03A7\u03DD`).toBuild(strictSettings()) - assertion = "Temml should build Unicode arrows" - new Expect(`←↑→↓↔↕↖↗↘↙↚↛↞↠↢↣↦↩↪↫↬↭↮↰↱↶↷↼↽↾↾↿⇀⇁⇂⇃⇄⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇚⇛⇝⟵⟶⟷⟸⟹⟺⟼`).toParse() - new Expect(`←↑→↓↔↕↖↗↘↙↚↛↞↠↢↣↦↩↪↫↬↭↮↰↱↶↷↼↽↾↾↿⇀⇁⇂⇃⇄⇆⇇⇈⇉⇊⇋⇌⇍⇎⇏⇐⇑⇒⇓⇔⇕⇚⇛⇝⟵⟶⟷⟸⟹⟺⟼`).toBuild() - assertion = "Temml should build Unicode binary operators" - new Expect(`±×÷∓∔∧∨∩∪≀⊎⊓⊔⊕⊖⊗⊘⊙⊚⊛⊝◯⊞⊟⊠⊡⊺⊻⊼⋇⋉⋊⋋⋌⋎⋏⋒⋓⩞\u22C5\u2216\u2218\u2219`).toParse() - new Expect(`±×÷∓∔∧∨∩∪≀⊎⊓⊔⊕⊖⊗⊘⊙⊚⊛⊝◯⊞⊟⊠⊡⊺⊻⊼⋇⋉⋊⋋⋌⋎⋏⋒⋓⩞\u22C5\u2216\u2218\u2219`).toBuild() - assertion = "Temml should build Unicode delimiters" - new Expect("\\left\u230A\\frac{a}{b}\\right\u230B").toParse() - new Expect("\\left\u2308\\frac{a}{b}\\right\u2308").toParse() - new Expect("\\left\u27ee\\frac{a}{b}\\right\u27ef").toParse() - new Expect("\\left\u27e8\\frac{a}{b}\\right\u27e9").toParse() - new Expect("\\left\u23b0\\frac{a}{b}\\right\u23b1").toParse() - new Expect(`┌x┐ └x┘`).toParse() - new Expect("\u231Cx\u231D \u231Ex\u231F").toParse() - new Expect("\u27E6x\u27E7").toParse() - new Expect("\\llbracket \\rrbracket").toParse() - new Expect("\\lBrace \\rBrace").toParse() - new Expect("\\left\u230A\\frac{a}{b}\\right\u230B").toBuild() - new Expect("\\left\u2308\\frac{a}{b}\\right\u2308").toBuild() - new Expect("\\left\u27ee\\frac{a}{b}\\right\u27ef").toBuild() - new Expect("\\left\u27e8\\frac{a}{b}\\right\u27e9").toBuild() - new Expect("\\left\u23b0\\frac{a}{b}\\right\u23b1").toBuild() - new Expect(`┌x┐ └x┘`).toBuild() - new Expect("\u231Cx\u231D \u231Ex\u231F").toBuild() - new Expect("\u27E6x\u27E7").toBuild() - new Expect("\\llbracket \\rrbracket").toBuild() - new Expect("\\lBrace \\rBrace").toBuild() - assertion = "Temml should build some Unicode surrogate pairs" - let wideCharStr = ""; - wideCharStr += String.fromCharCode(0xD835, 0xDC00); // bold A - wideCharStr += String.fromCharCode(0xD835, 0xDC68); // bold italic A - wideCharStr += String.fromCharCode(0xD835, 0xDD04); // Fraktur A - wideCharStr += String.fromCharCode(0xD835, 0xDD38); // double-struck - wideCharStr += String.fromCharCode(0xD835, 0xDC9C); // script A - wideCharStr += String.fromCharCode(0xD835, 0xDDA0); // sans serif A - wideCharStr += String.fromCharCode(0xD835, 0xDDD4); // bold sans A - wideCharStr += String.fromCharCode(0xD835, 0xDE08); // italic sans A - wideCharStr += String.fromCharCode(0xD835, 0xDE70); // monospace A - wideCharStr += String.fromCharCode(0xD835, 0xDFCE); // bold zero - wideCharStr += String.fromCharCode(0xD835, 0xDFE2); // sans serif zero - wideCharStr += String.fromCharCode(0xD835, 0xDFEC); // bold sans zero - wideCharStr += String.fromCharCode(0xD835, 0xDFF6); // monospace zero - new Expect(wideCharStr).toParse(strictSettings()); - new Expect(wideCharStr).toBuild(strictSettings()); - let wideCharText = "\text{"; - wideCharText += String.fromCharCode(0xD835, 0xDC00); // bold A - wideCharText += String.fromCharCode(0xD835, 0xDC68); // bold italic A - wideCharText += String.fromCharCode(0xD835, 0xDD04); // Fraktur A - wideCharText += String.fromCharCode(0xD835, 0xDD38); // double-struck - wideCharText += String.fromCharCode(0xD835, 0xDC9C); // script A - wideCharText += String.fromCharCode(0xD835, 0xDDA0); // sans serif A - wideCharText += String.fromCharCode(0xD835, 0xDDD4); // bold sans A - wideCharText += String.fromCharCode(0xD835, 0xDE08); // italic sans A - wideCharText += String.fromCharCode(0xD835, 0xDE70); // monospace A - wideCharText += String.fromCharCode(0xD835, 0xDFCE); // bold zero - wideCharText += String.fromCharCode(0xD835, 0xDFE2); // sans serif zero - wideCharText += String.fromCharCode(0xD835, 0xDFEC); // bold sans zero - wideCharText += String.fromCharCode(0xD835, 0xDFF6); // monospace zero - wideCharText += "}"; - new Expect(wideCharText).toParse(strictSettings()); - new Expect(wideCharText).toBuild(strictSettings()); - - assertion = "The maxSize setting should clamp size when set" - const rule = r`\rule{999em}{999em}` - markup = temml.renderToString(rule, new Settings({ maxSize: [5, 80] })) - new Expect(markup).toContain(`width="5em"`) - new Expect(markup).toContain(`height="5em"`) - assertion = "The maxSize setting should not clamp size when not set" - markup = temml.renderToString(rule) - new Expect(markup).toNotContain(`width="5em"`) - new Expect(markup).toNotContain(`height="5em"`) - assertion = "The maxSize setting should make zero-width rules if a negative maxSize is passed" - markup = temml.renderToString(rule, new Settings({ maxSize: [-5, -80] })) - new Expect(markup).toContain(`width="0em"`) - new Expect(markup).toContain(`height="0em"`) - - assertion = "The maxExpand setting should prevent expansion" - new Expect(r`\def\foo{1}\foo`).toParse() - new Expect(r`\def\foo{1}\foo`).toBuild() - new Expect(r`\def\foo{1}\foo`).toParse(new Settings({maxExpand: 1})) - new Expect(r`\def\foo{1}\foo`).toNotParse(new Settings({maxExpand: 0})) - assertion = "The maxExpand setting should prevent infinite loops" - new Expect(r`\def\foo{\foo}\foo`).toNotParse(new Settings({maxExpand: 10})) - - assertion = "The \\mathchoice function should render as if there is nothing other in display math" - const cmd = r`\sum_{k = 0}^{\infty} x^k` - new Expect(`\\displaystyle\\mathchoice{${cmd}}{T}{S}{SS}`).toBuildLike(`\\displaystyle${cmd}`) - assertion = "The \\mathchoice function should render as if there is nothing other in text" - new Expect(`\\textstyle\\mathchoice{D}{${cmd}}{S}{SS}`).toBuildLike(`\\textstyle${cmd}`) - assertion = "The \\mathchoice function should render as if there is nothing other in scriptstyle" - new Expect(`\\scriptstyle\\mathchoice{D}{T}{${cmd}}{SS}`).toBuildLike(`\\scriptstyle${cmd}`) - assertion = "The \\mathchoice function should render as if there is nothing other in scriptscriptstyle" - new Expect(`\\scriptscriptstyle\\mathchoice{D}{T}{S}{${cmd}}`).toBuildLike(`\\scriptscriptstyle${cmd}`) - - assertion = "Newlines via \\\\ and \\newline should build \\\\ without the optional argument and \\newline the same" - new Expect(r`hello \\ world`).toBuildLike(r`hello \newline world`) - assertion = "Newlines via \\\\ and \\newline should not allow \\newline to scan for an optional size argument" - new Expect(r`hello \newline[w]orld`).toParse() - new Expect(r`hello \newline[w]orld`).toBuild() - assertion = "Newlines via \\\\ and \\newline should not allow \\cr at top level" - new Expect(temml.renderToString(r`hello \cr world`)).toContain("#b22222") // color of error message - assertion = "Newlines via \\\\ and \\newline: \\\\ causes newline, even after mrel and mop" - markup = temml.renderToString(r`M = \\ a + \\ b \\ c`) - new Expect(markup).toMatch(/=.+mo linebreak.+\+.+mo linebreak.+b.+mo linebreak/) - - assertion = "Symbols should build" - new Expect(r`\text{\i\j}`).toParse(strictSettings()) - new Expect(r`A\;B\,C\nobreakspace \text{A\;B\,C\nobreakspace}`).toParse(strictSettings()) - new Expect(r`\standardstate`).toParse(strictSettings()) - new Expect(r`\text{\i\j}`).toBuild(strictSettings()) - new Expect(r`A\;B\,C\nobreakspace \text{A\;B\,C\nobreakspace}`).toBuild(strictSettings()) - new Expect(r`\standardstate`).toBuild(strictSettings()) - new Expect(r`\text{\ae\AE\oe\OE\o\O\ss}`).toBuildLike(r`\text{æÆœŒøØß}`, strictSettings()) - - assertion = "Settings should allow unicode text when not strict" - new Expect(`é`).toParse() - new Expect(`試`).toParse() - - assertion = "Settings should forbid unicode text when strict" - new Expect(`é`).toNotParse(strictSettings()) - new Expect(`試`).toNotParse(strictSettings()); - - - console.log("Number of tests: " + numTests) - console.log("Number of failures: " + numFailures) -} - -test() diff --git a/test/wiki-tests.md b/test/wiki-tests.md deleted file mode 100644 index 3f0f8ab4..00000000 --- a/test/wiki-tests.md +++ /dev/null @@ -1,928 +0,0 @@ - - - - - - Temml Wiki Tests - - - - - - - - -# Wiki Test - -Rows 1 thru 261 on this page reproduce the math examples from \ -https://en.wikipedia.org/wiki/Help:Displaying\_a\_formula - -A few of the functions on this page require Temml’s _texvc_ extension. - -
- -+-----+--------------------------------------------+------------------------------------------------+ -| | Source | Temml | -+=====+============================================+================================================+ -| 1 | \alpha | $`\alpha` | -+-----+--------------------------------------------+------------------------------------------------+ -| 2 | f(x) = x^2 | $`f(x) = x^2` | -+-----+--------------------------------------------+------------------------------------------------+ -| 3 | \\{1,e,\pi\\} | $`\{1,e,\pi\}` | -+-----+--------------------------------------------+------------------------------------------------+ -| 4 | |z + 1| \leq 2 | $`|z + 1| \leq 2` | -+-----+--------------------------------------------+------------------------------------------------+ -| 5 | `\# \$ \% ^\wedge \& \_ \{ \} \sim` \ | $`\# \$ \% ^\wedge \& \_ \{ \} \sim | -| | `\backslash` | \backslash` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Accents** | -+-----+--------------------------------------------+------------------------------------------------+ -| 6 | \dot{a}, \ddot{a}, \acute{a}, \grave{a} | $`\dot{a}, \ddot{a}, \acute{a}, \grave{a}` | -+-----+--------------------------------------------+------------------------------------------------+ -| 7 | \dot{a}, \ddot{a}, \acute{a}, \grave{a} | $`\dot{a}, \ddot{a}, \acute{a}, \grave{a}` | -+-----+--------------------------------------------+------------------------------------------------+ -| 8 | \check{a}, \breve{a}, \tilde{a}, \bar{a} | $`\check{a}, \breve{a}, \tilde{a}, \bar{a}` | -+-----+--------------------------------------------+------------------------------------------------+ -| 9 | \hat{a}, \widehat{a}, \vec{a} | $`\hat{a}, \widehat{a}, \vec{a}` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Functions** | -+-----+--------------------------------------------+------------------------------------------------+ -| 10 | \exp_a b = a^b, \exp b = e^b, 10^m | $`\exp_a b = a^b, \exp b = e^b, 10^m` | -+-----+--------------------------------------------+------------------------------------------------+ -| 11 | \ln c, \lg d = \log e, \log_{10} f | $`\ln c, \lg d = \log e, \log_{10} f` | -+-----+--------------------------------------------+------------------------------------------------+ -| 12 | \sin a, \cos b, \tan c, \cot d, \sec e, \ | $`\sin a, \cos b, \tan c, \cot d, \sec e, | -| | \csc f | \csc f` | -+-----+--------------------------------------------+------------------------------------------------+ -| 13 | \arcsin h, \arccos i, \arctan j | $`\arcsin h, \arccos i, \arctan j` | -+-----+--------------------------------------------+------------------------------------------------+ -| 14 | \sinh k, \cosh l, \tanh m, \coth n | $`\sinh k, \cosh l, \tanh m, \coth n` | -+-----+--------------------------------------------+------------------------------------------------+ -| 15 | \operatorname{sh}k, \operatorname{ch}l, \ | $`\operatorname{sh}k, \operatorname{ch}l, | -| | \operatorname{th}m, \operatorname{coth}n | \operatorname{th}m, \operatorname{coth}n` | -+-----+--------------------------------------------+------------------------------------------------+ -| 16 | \sgn r, \left\vert s \right\vert | $`\sgn r, \left\vert s \right\vert` | -+-----+--------------------------------------------+------------------------------------------------+ -| 17 | \min(x,y), \max(x,y) | $`\min(x,y), \max(x,y)` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Bounds** | -+-----+--------------------------------------------+------------------------------------------------+ -| 18 | \min x, \max y, \inf s, \sup t | $`\min x, \max y, \inf s, \sup t` | -+-----+--------------------------------------------+------------------------------------------------+ -| 19 | \lim u, \liminf v, \limsup w | $`\lim u, \liminf v, \limsup w` | -+-----+--------------------------------------------+------------------------------------------------+ -| 20 | \dim p, \deg q, \det m, \ker\phi | $`\dim p, \deg q, \det m, \ker\phi` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Projections** | -+-----+--------------------------------------------+------------------------------------------------+ -| 21 | \Pr j, \hom l, \lVert z \rVert, \arg z | $`\Pr j, \hom l, \lVert z \rVert, \arg z` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Differentials and derivatives** | -+-----+--------------------------------------------+------------------------------------------------+ -| 22 | dt, \mathrm{d}t, \partial t, \nabla\psi | $`dt, \mathrm{d}t, \partial t, \nabla\psi` | -+-----+--------------------------------------------+------------------------------------------------+ -| 23 | dy/dx, \mathrm{d}y/\mathrm{d}x, \ | $`dy/dx, \mathrm{d}y/\mathrm{d}x, | -| | \frac{dy}{dx}, \ | \frac{dy}{dx}, | -| | \frac{\mathrm{d}y}{\mathrm{d}x}, \ | \frac{\mathrm{d}y}{\mathrm{d}x}, | -| | \frac{\partial^2}\ | \frac{\partial^2} | -| | {\partial x\_1\partial x\_2}y | {\partial x_1\partial x_2}y` | -+-----+--------------------------------------------+------------------------------------------------+ -| 24 | \prime, \backprime, f^\prime, f', f'', \ | $`\prime, \backprime, f^\prime, f', f'', | -| | f^{(3)}, \dot y, \ddot y | f^{(3)}, \dot y, \ddot y` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Letter-like symbols or constants** | -+-----+--------------------------------------------+------------------------------------------------+ -| 25 | \infty, \aleph, \complement,\backepsilon,\ | $`\infty, \aleph, \complement,\backepsilon, | -| | \eth, \Finv, \hbar | \eth, \Finv, \hbar` | -+-----+--------------------------------------------+------------------------------------------------+ -| 26 | \Im, \imath, \jmath, \Bbbk, \ell, \mho, \ | $`\Im, \imath, \jmath, \Bbbk, \ell, \mho, | -| | \wp, \Re, \circledS, \S, \P, \AA | \wp, \Re, \circledS, \S, \P, \AA` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Modular arithmetic** | -+-----+--------------------------------------------+------------------------------------------------+ -| 27 | s_k \equiv 0 \pmod{m} | $`s_k \equiv 0 \pmod{m}` | -+-----+--------------------------------------------+------------------------------------------------+ -| 28 | a \bmod b | $`a \bmod b` | -+-----+--------------------------------------------+------------------------------------------------+ -| 29 | \gcd(m, n), \operatorname{lcm}(m, n) | $`\gcd(m, n), \operatorname{lcm}(m, n)` | -+-----+--------------------------------------------+------------------------------------------------+ -| 30 | \mid, \nmid, \shortmid, \nshortmid | $`\mid, \nmid, \shortmid, \nshortmid` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Radicals** | -+-----+--------------------------------------------+------------------------------------------------+ -| 31 | \surd, \sqrt{2}, \sqrt[n]{2}, \ | $`\surd, \sqrt{2}, \sqrt[n]{2}, | -| | \sqrt[3]{\frac{x^3+y^3}{2}} | \sqrt[3]{\frac{x^3+y^3}{2}}` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Operators** | -+-----+--------------------------------------------+------------------------------------------------+ -| 32 | +, -, \pm, \mp, \dotplus | $`+, -, \pm, \mp, \dotplus` | -+-----+--------------------------------------------+------------------------------------------------+ -| 33 | \times, \div, \divideontimes, /,\backslash | $`\times, \div, \divideontimes, /, \backslash` | -+-----+--------------------------------------------+------------------------------------------------+ -| 34 | \cdot, * \ast, \star, \circ, \bullet | $`\cdot, * \ast, \star, \circ, \bullet` | -+-----+--------------------------------------------+------------------------------------------------+ -| 35 | \boxplus, \boxminus, \boxtimes, \boxdot | $`\boxplus, \boxminus, \boxtimes, \boxdot` | -+-----+--------------------------------------------+------------------------------------------------+ -| 36 | \oplus, \ominus, \otimes, \oslash, \odot | $`\oplus, \ominus, \otimes, \oslash, \odot` | -+-----+--------------------------------------------+------------------------------------------------+ -| 37 | \circleddash, \circledcirc, \circledast | $`\circleddash, \circledcirc, \circledast` | -+-----+--------------------------------------------+------------------------------------------------+ -| 38 | \bigoplus, \bigotimes, \bigodot | $`\bigoplus, \bigotimes, \bigodot` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Sets** | -+-----+--------------------------------------------+------------------------------------------------+ -| 39 | \{ \}, \O \empty \emptyset, \varnothing | $`\{ \}, \O \empty \emptyset, \varnothing` | -+-----+--------------------------------------------+------------------------------------------------+ -| 40 | \in, \notin \not\in, \ni, \not\ni | $`\in, \notin \not\in, \ni, \not\ni` | -+-----+--------------------------------------------+------------------------------------------------+ -| 41 | \cap, \Cap, \sqcap, \bigcap | $`\cap, \Cap, \sqcap, \bigcap` | -+-----+--------------------------------------------+------------------------------------------------+ -| 42 | \cup, \Cup, \sqcup, \bigcup, \bigsqcup, \ | $`\cup, \Cup, \sqcup, \bigcup, \bigsqcup, | -| | \uplus, \biguplus | \uplus, \biguplus` | -+-----+--------------------------------------------+------------------------------------------------+ -| 43 | \setminus, \smallsetminus, \times | $`\setminus, \smallsetminus, \times` | -+-----+--------------------------------------------+------------------------------------------------+ -| 44 | \subset, \Subset, \sqsubset | $`\subset, \Subset, \sqsubset` | -+-----+--------------------------------------------+------------------------------------------------+ -| 45 | \supset, \Supset, \sqsupset | $`\supset, \Supset, \sqsupset` | -+-----+--------------------------------------------+------------------------------------------------+ -| 46 | \subseteq, \nsubseteq, \subsetneq, \ | $`\subseteq, \nsubseteq, \subsetneq, | -| | \varsubsetneq, \sqsubseteq | \varsubsetneq, \sqsubseteq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 47 | \supseteq, \nsupseteq, \supsetneq, \ | $`\supseteq, \nsupseteq, \supsetneq, | -| | \varsupsetneq, \sqsupseteq | \varsupsetneq, \sqsupseteq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 48 | \subseteqq, \nsubseteqq, \subsetneqq, \ | $`\subseteqq, \nsubseteqq, \subsetneqq, | -| | \varsubsetneqq | \varsubsetneqq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 49 | \supseteqq, \nsupseteqq, \supsetneqq, \ | $`\supseteqq, \nsupseteqq, \supsetneqq, | -| | \varsupsetneqq | \varsupsetneqq` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Relations** | -+-----+--------------------------------------------+------------------------------------------------+ -| 50 | =, \ne, \neq, \equiv, \not\equiv | $`=, \ne, \neq, \equiv, \not\equiv` | -+-----+--------------------------------------------+------------------------------------------------+ -| 51 | \doteq, \doteqdot, \ | $`\doteq, \doteqdot, | -| | \overset{\underset{\mathrm{def}}{}}{=}, := | \overset{\underset{\mathrm{def}}{}}{=}, :=` | -+-----+--------------------------------------------+------------------------------------------------+ -| 52 | \sim, \nsim, \backsim, \thicksim, \simeq,\ | $`\sim, \nsim, \backsim, \thicksim, \simeq, | -| | \backsimeq, \eqsim, \cong, \ncong | \backsimeq, \eqsim, \cong, \ncong` | -+-----+--------------------------------------------+------------------------------------------------+ -| 53 | \approx, \thickapprox, \approxeq, \asymp,\ | $`\approx, \thickapprox, \approxeq, \asymp, | -| | \propto, \varpropto | \propto, \varpropto` | -+-----+--------------------------------------------+------------------------------------------------+ -| 54 | <, \nless, \ll, \not\ll, \lll, \not\lll, \ | $`<, \nless, \ll, \not\ll, \lll, \not\lll, | -| | \lessdot | \lessdot` | -+-----+--------------------------------------------+------------------------------------------------+ -| 55 | \le, \leq, \lneq, \leqq, \nleq, \nleqq, \ | $`\le, \leq, \lneq, \leqq, \nleq, \nleqq, | -| | \lneqq, \lvertneqq | \lneqq, \lvertneqq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 56 | \ge, \geq, \gneq, \geqq, \ngeq, \ngeqq, \ | $`\ge, \geq, \gneq, \geqq, \ngeq, \ngeqq, | -| | \gneqq, \gvertneqq | \gneqq, \gvertneqq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 57 | \lessgtr, \lesseqgtr, \lesseqqgtr, \ | $`\lessgtr, \lesseqgtr, \lesseqqgtr, | -| | \gtrless, \gtreqless, \gtreqqless | \gtrless, \gtreqless, \gtreqqless` | -+-----+--------------------------------------------+------------------------------------------------+ -| 58 | \leqslant, \nleqslant, \eqslantless | $`\leqslant, \nleqslant, \eqslantless` | -+-----+--------------------------------------------+------------------------------------------------+ -| 59 | \geqslant, \ngeqslant, \eqslantgtr | $`\geqslant, \ngeqslant, \eqslantgtr` | -+-----+--------------------------------------------+------------------------------------------------+ -| 60 | \lesssim, \lnsim, \lessapprox, \lnapprox | $`\lesssim, \lnsim, \lessapprox, \lnapprox` | -+-----+--------------------------------------------+------------------------------------------------+ -| 61 | \gtrsim, \gnsim, \gtrapprox, \gnapprox | $`\gtrsim, \gnsim, \gtrapprox, \gnapprox` | -+-----+--------------------------------------------+------------------------------------------------+ -| 62 | \prec, \nprec, \preceq, \npreceq,\precneqq | $`\prec, \nprec, \preceq, \npreceq, \precneqq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 63 | \succ, \nsucc, \succeq, \nsucceq,\succneqq | $`\succ, \nsucc, \succeq, \nsucceq, \succneqq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 64 | \preccurlyeq, \curlyeqprec | $`\preccurlyeq, \curlyeqprec` | -+-----+--------------------------------------------+------------------------------------------------+ -| 65 | \succcurlyeq, \curlyeqsucc | $`\succcurlyeq, \curlyeqsucc` | -+-----+--------------------------------------------+------------------------------------------------+ -| 66 | \precsim, \precnsim, \precapprox, \ | $`\precsim, \precnsim, \precapprox, | -| | \precnapprox | \precnapprox` | -+-----+--------------------------------------------+------------------------------------------------+ -| 67 | \succsim, \succnsim, \succapprox, \ | $`\succsim, \succnsim, \succapprox, | -| | \succnapprox | \succnapprox` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Geometric** | -+-----+--------------------------------------------+------------------------------------------------+ -| 68 | \parallel, \nparallel, \shortparallel, \ | $`\parallel, \nparallel, \shortparallel, | -| | \nshortparallel | \nshortparallel` | -+-----+--------------------------------------------+------------------------------------------------+ -| 69 | \perp, \angle, \sphericalangle, \ | $`\perp, \angle, \sphericalangle, | -| | \measuredangle, 45^\circ | \measuredangle, 45^\circ` | -+-----+--------------------------------------------+------------------------------------------------+ -| 70 | \Box, \square, \blacksquare, \diamond, \ | $`\Box, \square, \blacksquare, \diamond, | -| | \Diamond, \lozenge, \blacklozenge,\bigstar | \Diamond, \lozenge, \blacklozenge,\bigstar` | -+-----+--------------------------------------------+------------------------------------------------+ -| 71 | \bigcirc, \triangle, \bigtriangleup, \ | $`\bigcirc, \triangle, \bigtriangleup, | -| | \bigtriangledown | \bigtriangledown` | -+-----+--------------------------------------------+------------------------------------------------+ -| 72 | \vartriangle, \triangledown | $`\vartriangle, \triangledown` | -+-----+--------------------------------------------+------------------------------------------------+ -| 73 | \blacktriangle, \blacktriangledown, \ | $`\blacktriangle, \blacktriangledown, | -| | \blacktriangleleft, \blacktriangleright | \blacktriangleleft, \blacktriangleright` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Logic** | -+-----+--------------------------------------------+------------------------------------------------+ -| 74 | \forall, \exists, \nexists | $`\forall, \exists, \nexists` | -+-----+--------------------------------------------+------------------------------------------------+ -| 75 | \therefore, \because, \And | $`\therefore, \because, \And` | -+-----+--------------------------------------------+------------------------------------------------+ -| 76 | \lor \vee, \curlyvee, \bigvee | $`\lor \vee, \curlyvee, \bigvee` | -+-----+--------------------------------------------+------------------------------------------------+ -| 77 | \land \wedge, \curlywedge, \bigwedge | $`\land \wedge, \curlywedge, \bigwedge` | -+-----+--------------------------------------------+------------------------------------------------+ -| 78 | \bar{q}, \bar{abc}, \overline{q}, \ | $`\bar{q}, \bar{abc}, \overline{q}, | -| | \overline{abc},\\\\ \ | \overline{abc}, \\ | -| | \lnot \neg, \not\operatorname{R},\bot,\top | \lnot \neg, \not\operatorname{R},\bot,\top` | -+-----+--------------------------------------------+------------------------------------------------+ -| 79 | \vdash \dashv, \vDash, \Vdash, \models | $`\vdash \dashv, \vDash, \Vdash, \models` | -+-----+--------------------------------------------+------------------------------------------------+ -| 80 | \Vvdash \nvdash \nVdash \nvDash \nVDash | $`\Vvdash \nvdash \nVdash \nvDash \nVDash` | -+-----+--------------------------------------------+------------------------------------------------+ -| 81 | \ulcorner \urcorner \llcorner \lrcorner | $`\ulcorner \urcorner \llcorner \lrcorner` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Arrows** | -+-----+--------------------------------------------+------------------------------------------------+ -| 82 | \Rrightarrow, \Lleftarrow | $`\Rrightarrow, \Lleftarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 83 | \Rightarrow, \nRightarrow, \ | $`\Rightarrow, \nRightarrow, | -| | \Longrightarrow, \implies | \Longrightarrow, \implies` | -+-----+--------------------------------------------+------------------------------------------------+ -| 84 | \Leftarrow, \nLeftarrow, \Longleftarrow | $`\Leftarrow, \nLeftarrow, \Longleftarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 85 | \Leftrightarrow, \nLeftrightarrow, \ | $`\Leftrightarrow, \nLeftrightarrow, | -| | \Longleftrightarrow, \iff | \Longleftrightarrow, \iff` | -+-----+--------------------------------------------+------------------------------------------------+ -| 86 | \Uparrow, \Downarrow, \Updownarrow | $`\Uparrow, \Downarrow, \Updownarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 87 | \rightarrow \to, \nrightarrow, \ | $`\rightarrow \to, \nrightarrow, | -| | \longrightarrow | \longrightarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 88 | \leftarrow \gets, \nleftarrow, \ | $`\leftarrow \gets, \nleftarrow, | -| | \longleftarrow | \longleftarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 89 | \leftrightarrow, \nleftrightarrow, \ | $`\leftrightarrow, \nleftrightarrow, | -| | \longleftrightarrow | \longleftrightarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 90 | \uparrow, \downarrow, \updownarrow | $`\uparrow, \downarrow, \updownarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 91 | \nearrow, \swarrow, \nwarrow, \searrow | $`\nearrow, \swarrow, \nwarrow, \searrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| 92 | \mapsto, \longmapsto | $`\mapsto, \longmapsto` | -+-----+--------------------------------------------+------------------------------------------------+ -| 93 | \rightharpoonup \rightharpoondown \ | $`\rightharpoonup \rightharpoondown | -| | \leftharpoonup \leftharpoondown \ | \leftharpoonup \leftharpoondown | -| | \upharpoonleft \upharpoonright \ | \upharpoonleft \upharpoonright | -| | \downharpoonleft \downharpoonright \ | \downharpoonleft \downharpoonright | -| | \rightleftharpoons \leftrightharpoons | \rightleftharpoons \leftrightharpoons` | -+-----+--------------------------------------------+------------------------------------------------+ -| 94 | \curvearrowleft \circlearrowleft \Lsh \ | $`\curvearrowleft \circlearrowleft \Lsh | -| | \upuparrows \rightrightarrows \ | \upuparrows \rightrightarrows | -| | \rightleftarrows \rightarrowtail \ | \rightleftarrows \rightarrowtail | -| | \looparrowright | \looparrowright` | -+-----+--------------------------------------------+------------------------------------------------+ -| 95 | \curvearrowright \circlearrowright \Rsh \ | $`\curvearrowright \circlearrowright \Rsh | -| | \downdownarrows \leftleftarrows \ | \downdownarrows \leftleftarrows | -| | \leftrightarrows \leftarrowtail \ | \leftrightarrows \leftarrowtail | -| | \looparrowleft | \looparrowleft` | -+-----+--------------------------------------------+------------------------------------------------+ -| 96 | \hookrightarrow \hookleftarrow \multimap \ | $`\hookrightarrow \hookleftarrow \multimap | -| | \leftrightsquigarrow \rightsquigarrow \ | \leftrightsquigarrow \rightsquigarrow | -| | \twoheadrightarrow \twoheadleftarrow | \twoheadrightarrow \twoheadleftarrow` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Special** | -+-----+--------------------------------------------+------------------------------------------------+ -| 97 | \amalg \P \S \%\dagger\ddagger\ldots\cdots | $`\amalg \P \S \% \dagger\ddagger\ldots\cdots` | -+-----+--------------------------------------------+------------------------------------------------+ -| 98 | \smile \frown \wr \triangleleft \ | $`\smile \frown \wr \triangleleft | -| | \triangleright | \triangleright` | -+-----+--------------------------------------------+------------------------------------------------+ -| 99 | \diamondsuit, \heartsuit, \clubsuit, \ | $`\diamondsuit, \heartsuit, \clubsuit, | -| | \spadesuit, \Game, \flat, \natural, \sharp | \spadesuit, \Game, \flat, \natural, \sharp` | -+-----+--------------------------------------------+------------------------------------------------+ -| **Unsorted** | -+-----+--------------------------------------------+------------------------------------------------+ -| 100 | \diagup \diagdown \centerdot \ltimes \ | $`\diagup \diagdown \centerdot \ltimes | -| | \rtimes \leftthreetimes \rightthreetimes | \rtimes \leftthreetimes \rightthreetimes` | -+-----+--------------------------------------------+------------------------------------------------+ -| 101 | \eqcirc \circeq \triangleq \bumpeq\Bumpeq\ | $`\eqcirc \circeq \triangleq \bumpeq\Bumpeq | -| | \doteqdot \risingdotseq \fallingdotseq | \doteqdot \risingdotseq \fallingdotseq` | -+-----+--------------------------------------------+------------------------------------------------+ -| 102 | \intercal \barwedge \veebar \ | $`\intercal \barwedge \veebar | -| | \doublebarwedge \between \pitchfork | \doublebarwedge \between \pitchfork` | -+-----+--------------------------------------------+------------------------------------------------+ -| 103 | \vartriangleleft \ntriangleleft \ | $`\vartriangleleft \ntriangleleft | -| | \vartriangleright \ntriangleright | \vartriangleright \ntriangleright` | -+-----+--------------------------------------------+------------------------------------------------+ -| 104 | \trianglelefteq \ntrianglelefteq \ | $`\trianglelefteq \ntrianglelefteq | -| | \trianglerighteq \ntrianglerighteq | \trianglerighteq \ntrianglerighteq` | -+-----+--------------------------------------------+------------------------------------------------+ - -
- -+-----+----------------------------------------------+------------------------------------------------+ -| Larger expressions | -+-----+----------------------------------------------+------------------------------------------------+ -| | Source | Temml | -+=====+==============================================+================================================+ -| 105 | a^2, a^{x+3} | $`a^2, a^{x+3}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 106 | a\_2 | $`a_2` | -+-----+----------------------------------------------+------------------------------------------------+ -| 107 | 10^{30} a^{2+2} \ | $`10^{30} a^{2+2} \\ | -| | a\_{i,j} b\_{f'} | a_{i,j} b_{f'}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 108 | x\_2^3 \ | $`x_2^3 \\ | -| | {x\_2}^3 | {x_2}^3` | -+-----+----------------------------------------------+------------------------------------------------+ -| 109 | 10^{10^{8}} | $`10^{10^{8}}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 110 | \sideset{\_1^2}{\_3^4}\prod\_a^b \ | $$\sideset{_1^2}{_3^4}\prod_a^b$$ | -| | {}\_1^2\\!\Omega\_3^4 | $${}_1^2\!\Omega_3^4$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 111 | \overset{\alpha}{\omega} \ | $`\overset{\alpha}{\omega} \\ | -| | \underset{\alpha}{\omega} \ | \underset{\alpha}{\omega} \\ | -| | \overset{\alpha}{\underset{\gamma}{\omega}}\ | \overset{\alpha}{\underset{\gamma}{\omega}}\\ | -| | \stackrel{\alpha}{\omega} | \stackrel{\alpha}{\omega}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 112 | x', y'', f', f'' \ | $`x', y'', f', f'' \\ | -| | x^\prime, y^{\prime\prime} | x^\prime, y^{\prime\prime}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 113 | \dot{x}, \ddot{x} | $`\dot{x}, \ddot{x}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 114 | \hat a \\ \bar b \\ \vec c \ | $`\hat a \ \bar b \ \vec c \\ | -| | \overrightarrow{a b} \\ \overleftarrow{c d}\ | \overrightarrow{a b} \ \overleftarrow{c d}\\ | -| | \widehat{d e f} \ | \widehat{d e f} \\ | -| | \overline{g h i} \\ \underline{j k l} | \overline{g h i} \ \underline{j k l}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 115 | \overset{\frown} {AB} | $`\overset{\frown} {AB}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 116 | A \xleftarrow{n+\mu-1} B \ | $`A \xleftarrow{n+\mu-1} B | -| | \xrightarrow[T]{n\pm i-1} C | \xrightarrow[T]{n\pm i-1} C` | -+-----+----------------------------------------------+------------------------------------------------+ -| 117 | \overbrace{ 1+2+\cdots+100 }^{5050} | $`\overbrace{ 1+2+\cdots+100 }^{5050}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 118 | \underbrace{ a+b+\cdots+z }\_{26} | $`\underbrace{ a+b+\cdots+z }_{26}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 119 | \sum\_{k=1}^N k^2 | $$\sum_{k=1}^N k^2$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 120 | \textstyle \sum\_{k=1}^N k^2 | $$\textstyle \sum_{k=1}^N k^2$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 121 | \frac{\sum\_{k=1}^N k^2}{a} | $$\frac{\sum_{k=1}^N k^2}{a}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 122 | \frac{\sum\limits^{^N}\_{k=1} k^2}{a} | $$\frac{\sum\limits^{^N}_{k=1} k^2}{a}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 123 | \prod\_{i=1}^N x\_i | $$\prod_{i=1}^N x_i$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 124 | \textstyle \prod\_{i=1}^N x\_i | $$\textstyle \prod_{i=1}^N x_i$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 125 | \coprod\_{i=1}^N x\_i | $$\coprod_{i=1}^N x_i$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 126 | \textstyle \coprod\_{i=1}^N x\_i | $$\textstyle \coprod_{i=1}^N x_i$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 127 | \lim\_{n \to \infty}x\_n | $$\lim_{n \to \infty}x_n$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 128 | \textstyle \lim\_{n \to \infty}x\_n | $$\textstyle \lim_{n \to \infty}x_n$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 129 | \int\limits\_{1}^{3}\frac{e^3/x}{x^2}\\, dx | $$\int\limits_{1}^{3}\frac{e^3/x}{x^2}\, dx$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 130 | \int\_{1}^{3}\frac{e^3/x}{x^2}\\, dx | $$\int_{1}^{3}\frac{e^3/x}{x^2}\, dx$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 131 | \textstyle \int\limits\_{-N}^{N} e^x dx | $$\textstyle \int\limits_{-N}^{N} e^x dx$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 132 | \textstyle \int\_{-N}^{N} e^x dx | $$\textstyle \int_{-N}^{N} e^x dx$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 133 | \iint\limits\_D dx\\,dy | $$\iint\limits_D dx\,dy$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 134 | \iiint\limits\_E dx\\,dy\\,dz | $$\iiint\limits_E dx\,dy\,dz$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 135 | \iiiint\limits\_F dx\\,dy\\,dz\\,dt | $$\iiiint\limits_F dx\,dy\,dz\,dt$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 136 | \int\_{(x,y)\in C} x^3\\, dx + 4y^2\\, dy | $$\int_{(x,y)\in C} x^3\, dx + 4y^2\, dy$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 137 | \oint\_{(x,y)\in C} x^3\\, dx + 4y^2\\, dy | $$\oint_{(x,y)\in C} x^3\, dx + 4y^2\, dy$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 138 | \bigcap\_{i=1}^n E\_i | $$\bigcap_{i=1}^n E_i$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 139 | \bigcup\_{i=1}^n E\_i | $$\bigcup_{i=1}^n E_i$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| **Fractions, matrices, multiline** | -+-----+----------------------------------------------+------------------------------------------------+ -| 140 | \frac{2}{4}=0.5 or {2 \over 4}=0.5 | $`\frac{2}{4}=0.5` or $`{2 \over 4}=0.5` | -+-----+----------------------------------------------+------------------------------------------------+ -| 141 | \tfrac{2}{4} = 0.5 | $$\tfrac{2}{4} = 0.5$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 142 | \dfrac{2}{4} = 0.5 \qquad \dfrac{2}{c + \ | $`\dfrac{2}{4} = 0.5 \qquad \dfrac{2}{c + | -| | \dfrac{2}{d + \dfrac{2}{4}}} = a | \dfrac{2}{d + \dfrac{2}{4}}} = a` | -+-----+----------------------------------------------+------------------------------------------------+ -| 143 | \cfrac{2}{c +\cfrac{2}{d +\cfrac{2}{4}}} = a | $$\cfrac{2}{c+\cfrac{2}{d+\cfrac{2}{4}}} = a$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 144 | \cfrac{x}{1 + \cfrac{\cancel{y}}\ | $`\cfrac{x}{1 + \cfrac{\cancel{y}} | -| | {\cancel{y}}} = \cfrac{x}{2} | {\cancel{y}}} = \cfrac{x}{2}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 145 | \binom{n}{k} | $`\binom{n}{k}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 146 | \tbinom{n}{k} | $$\tbinom{n}{k}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 147 | \dbinom{n}{k} | $`\dbinom{n}{k}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 148 | \begin{matrix} \ | $`\begin{matrix} | -| | x & y \\\\ \ | x & y \\ | -| | z & v \ | z & v | -| | \end{matrix} | \end{matrix}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 149 | \begin{vmatrix} \ | $`\begin{vmatrix} | -| | x & y \\\\ \ | x & y \\ | -| | z & v \ | z & v | -| | \end{vmatrix} | \end{vmatrix}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 150 | \begin{Vmatrix} \ | $`\begin{Vmatrix} | -| | x & y \\\\ \ | x & y \\ | -| | z & v \ | z & v | -| | \end{Vmatrix} | \end{Vmatrix}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 151 | \begin{bmatrix} \ | $`\begin{bmatrix} | -| | 0 & \cdots & 0 \\\\ \ | 0 & \cdots & 0 \\ | -| | \vdots & \ddots & \vdots \\\\ \ | \vdots & \ddots & \vdots \\ | -| | 0 & \cdots & 0 \ | 0 & \cdots & 0 | -| | \end{bmatrix} | \end{bmatrix}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 152 | \begin{Bmatrix} \ | $`\begin{Bmatrix} | -| | x & y \\\\ \ | x & y \\ | -| | z & v \ | z & v | -| | \end{Bmatrix} | \end{Bmatrix}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 153 | \begin{pmatrix} \ | $`\begin{pmatrix} | -| | x & y \\\\ \ | x & y \\ | -| | z & v \ | z & v | -| | \end{pmatrix} | \end{pmatrix}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 154 | \bigl( \begin{smallmatrix} \ | $`\bigl( \begin{smallmatrix} | -| | a&b\\\\ c&d \ | a&b\\ c&d | -| | \end{smallmatrix} \bigr) | \end{smallmatrix} \bigr)` | -+-----+----------------------------------------------+------------------------------------------------+ -| 155 | f(n) = \begin{cases} \ | $`f(n) = \begin{cases} | -| | n/2, & \text{if }n\text{ is even} \\\\ \ | n/2, & \text{if }n\text{ is even} \\ | -| | 3n+1, & \text{if }n\text{ is odd} | 3n+1, & \text{if }n\text{ is odd} | -| | \end{cases} | \end{cases}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 156 | \begin{cases} \ | $`\begin{cases} | -| | 3x + 5y + z \\\\ \ | 3x + 5y + z \\ | -| | 7x - 2y + 4z \\\\ \ | 7x - 2y + 4z \\ | -| | -6x + 3y + 2z | -6x + 3y + 2z | -| | \end{cases} | \end{cases}` | -+-----+----------------------------------------------+------------------------------------------------+ -| 157 | \begin{align} \ | $$\begin{align} | -| | f(x) & = (a+b)^2 \\\\ \ | f(x) & = (a+b)^2 \\ | -| | & = a^2+2ab+b^2 \\\\ \ | & = a^2+2ab+b^2 \\ | -| | \end{align} | \end{align}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 158 | \begin{alignat}{2} \ | $$\begin{alignat}{2} | -| | f(x) & = (a+b)^2 \\\\ \ | f(x) & = (a+b)^2 \\ | -| | & = a^2+2ab+b^2 \\\\ \ | & = a^2+2ab+b^2 \\ | -| | \end{alignat} | \end{alignat}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 159 | \begin{align} \ | $$\begin{align} | -| | f(a,b) & = (a+b)^2 && = (a+b)(a+b) \\\\ \ | f(a,b) & = (a+b)^2 && = (a+b)(a+b) \\ | -| | & = a^2+ab+ba+b^2 && = a^2+2ab+b^2 \\\\ \ | & = a^2+ab+ba+b^2 && = a^2+2ab+b^2 \\ | -| | \end{align} | \end{align}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 159 | \begin{alignat}{3} \ | $$\begin{alignat}{3} | -| | f(a,b) & = (a+b)^2 && = (a+b)(a+b) \\\\ \ | f(a,b) & = (a+b)^2 && = (a+b)(a+b) \\ | -| | & = a^2+ab+ba+b^2 && = a^2+2ab+b^2 \\\\ \ | & = a^2+ab+ba+b^2 && = a^2+2ab+b^2 \\ | -| | \end{alignat} | \end{alignat}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 160 | \begin{array}{lcl} \ | $$\begin{array}{lcl} | -| | z & = & a \\\\ \ | z & = & a \\ | -| | f(x,y,z) & = & x + y + z | f(x,y,z) & = & x + y + z | -| | \end{array} | \end{array}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 161 | \begin{array}{lcr} \ | $$\begin{array}{lcr} | -| | z & = & a \\\\ \ | z & = & a \\ | -| | f(x,y,z) & = & x + y + z | f(x,y,z) & = & x + y + z | -| | \end{array} | \end{array}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 162 | \begin{alignat}{4} \ | $$\begin{alignat}{4} | -| | F:\\; && C(X) && \\;\to\\; & C(X) \\\\ \ | F:\; && C(X) && \;\to\; & C(X) \\ | -| | && g && \\;\mapsto\\; & g^2 | && g && \;\mapsto\; & g^2 | -| | \end{alignat} | \end{alignat}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 163 | \begin{alignat}{4} \ | $$\begin{alignat}{4} | -| | F:\\; && C(X) && \\;\to\\; && C(X) \\\\ \ | F:\; && C(X) && \;\to\; && C(X) \\ | -| | && g && \\;\mapsto\\; && g^2 | && g && \;\mapsto\; && g^2 | -| | \end{alignat} | \end{alignat}$$ | -+-----+----------------------------------------------+------------------------------------------------+ -| 164 | `f(x) \,\!` `\sum_{n=0}^\infty a_n x^n` \ | $`f(x) \,\!` $` = \sum_{n=0}^\infty a_n x^n` | -| | `= a_0+a_1x+a_2x^2+\cdots` | $`= a_0+a_1x+a_2x^2+\cdots` | -+-----+----------------------------------------------+------------------------------------------------+ -| 165 | \begin{array}{|c|c|c|} \ | $`\begin{array}{|c|c|c|} | -| | a & b & S \\\\ \ | a & b & S \\ | -| | \hline \ | \hline | -| | 0 & 0 & 1 \\\\ \ | 0 & 0 & 1 \\ | -| | 0 & 1 & 1 \\\\ \ | 0 & 1 & 1 \\ | -| | 1 & 0 & 1 \\\\ \ | 1 & 0 & 1 \\ | -| | 1 & 1 & 0 \\\\ \ | 1 & 1 & 0 \\ | -| | \end{array} | \end{array}` | -+-----+----------------------------------------------+------------------------------------------------+ -{colWidths="null null 400"} - -+-----+-----------------------------------------------+--------------------------------------------------+ -| Delimiters | -+=====+===============================================+==================================================+ -| 166 | ( \frac{1}{2} )^n | $`( \frac{1}{2} )^n` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 167 | \left ( \frac{1}{2} \right )^n | $`\left ( \frac{1}{2} \right )^n` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 168 | \left ( \frac{a}{b} \right ) | $`\left ( \frac{a}{b} \right )` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 169 | \left [ \frac{a}{b} \right ] \quad \ | $`\left [ \frac{a}{b} \right ] \quad | -| | \left \lbrack \frac{a}{b} \right \rbrack | \left \lbrack \frac{a}{b} \right \rbrack` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 170 | \left \{ \frac{a}{b} \right \} \quad \ | $`\left \{ \frac{a}{b} \right \} \quad | -| | \left \lbrace \frac{a}{b} \right \rbrace | \left \lbrace \frac{a}{b} \right \rbrace` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 171 | \left \langle \frac{a}{b} \right \rangle | $`\left \langle \frac{a}{b} \right \rangle` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 172 | \left | \frac{a}{b} \right \vert \quad \ | $`\left | \frac{a}{b} \right \vert \quad | -| | \left \Vert \frac{c}{d} \right \| | \left \Vert \frac{c}{d} \right \|` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 173 | \left \lfloor \frac{a}{b} \right \rfloor \ | $`\left \lfloor \frac{a}{b} \right \rfloor | -| | \quad \left \lceil \frac{c}{d} \right \rceil | \quad \left \lceil \frac{c}{d} \right \rceil` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 174 | \left / \frac{a}{b} \right \backslash | $`\left / \frac{a}{b} \right \backslash` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 175 | \left\uparrow\frac{a}{b}\right\downarrow\\; \ | $`\left\uparrow\frac{a}{b}\right\downarrow\; | -| | \left\Uparrow\frac{a}{b}\right\Downarrow\\; \ | \left\Uparrow\frac{a}{b}\right\Downarrow\; | -| | \left \updownarrow \frac{a}{b} \right \ | \left \updownarrow \frac{a}{b} \right | -| | \Updownarrow | \Updownarrow` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 176 | \left [ 0,1 \right ) \ | $`\left [ 0,1 \right ) | -| | \left \langle \psi \right | | \left \langle \psi \right |` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 177 | \left . \frac{A}{B} \right \} \to X | $`\left . \frac{A}{B} \right \} \to X` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 178 | ( \bigl( \Bigl( \biggl( \Biggl( \dots \ | $`( \bigl( \Bigl( \biggl( \Biggl( \dots | -| | \Biggr] \biggr] \Bigr] \bigr] ] | \Biggr] \biggr] \Bigr] \bigr] ]` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 179 | \{ \bigl\{ \Bigl\{ \biggl\{ \Biggl\{ \dots \ | $`\{ \bigl\{ \Bigl\{ \biggl\{ \Biggl\{ \dots | -| | \Biggr\rangle \biggr\rangle \Bigr\rangle \ | \Biggr\rangle \biggr\rangle \Bigr\rangle | -| | \bigr\rangle \rangle | \bigr\rangle \rangle` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 180 | \| \big\| \Big\| \bigg\| \Bigg\| \dots \ | $`\| \big\| \Big\| \bigg\| \Bigg\| \dots | -| | \Bigg| \bigg| \Big| \big| | | \Bigg| \bigg| \Big| \big| |` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 181 | \lfloor \bigl\lfloor \Bigl\lfloor \ | $`\lfloor \bigl\lfloor \Bigl\lfloor | -| | \biggl\lfloor \Biggl\lfloor \dots \ | \biggl\lfloor \Biggl\lfloor \dots | -| | \Biggr\rceil \biggr\rceil \Bigr\rceil \ | \Biggr\rceil \biggr\rceil \Bigr\rceil | -| | \bigr\rceil \ceil | \bigr\rceil \rceil` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 182 | \uparrow \big\uparrow \Big\uparrow \ | $`\uparrow \big\uparrow \Big\uparrow | -| | \bigg\uparrow \Bigg\uparrow \dots \ | \bigg\uparrow \Bigg\uparrow \dots | -| | \Bigg\Downarrow \bigg\Downarrow \ | \Bigg\Downarrow \bigg\Downarrow | -| | \Big\Downarrow \big\Downarrow \Downarrow | \Big\Downarrow \big\Downarrow \Downarrow` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 183 | \updownarrow\big\updownarrow\Big\updownarrow\ | $`\updownarrow\big\updownarrow\Big\updownarrow | -| | \bigg\updownarrow \Bigg\updownarrow \dots \ | \bigg\updownarrow \Bigg\updownarrow \dots | -| | \Bigg\Updownarrow \bigg\Updownarrow \Big \ | \Bigg\Updownarrow \bigg\Updownarrow \Big | -| | \Updownarrow \big\Updownarrow \Updownarrow | \Updownarrow \big\Updownarrow \Updownarrow` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 184 | / \big/ \Big/ \bigg/ \Bigg/ \dots \ | $`/ \big/ \Big/ \bigg/ \Bigg/ \dots | -| | \Bigg\backslash \bigg\backslash \Big \ | \Bigg\backslash \bigg\backslash \Big | -| | \backslash \big\backslash \backslash | \backslash \big\backslash \backslash` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Greek Alphabet** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 185 | \Alpha \Beta \Gamma \Delta \Epsilon \Zeta \ | $`\Alpha \Beta \Gamma \Delta \Epsilon \Zeta | -| | \Eta \Theta | \Eta \Theta` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 186 | \Iota \Kappa \Lambda \Mu \Nu \Xi \Omicron \Pi | $`\Iota \Kappa \Lambda \Mu \Nu \Xi \Omicron \Pi` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 187 | \Rho \Sigma \Tau \Upsilon \Phi \Chi \Psi \ | $`\Rho \Sigma \Tau \Upsilon \Phi \Chi \Psi | -| | \Omega | \Omega` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 188 | \alpha \beta \gamma \delta \epsilon \zeta \ | $`\alpha \beta \gamma \delta \epsilon \zeta | -| | \eta \theta | \eta \theta` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 189 | \iota \kappa \lambda \mu \nu \xi \omicron \pi | $`\iota \kappa \lambda \mu \nu \xi \omicron \pi` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 190 | \rho \sigma \tau \upsilon \phi \chi \psi \ | $`\rho \sigma \tau \upsilon \phi \chi \psi | -| | \omega | \omega` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 191 | \varGamma \varDelta \varTheta \varLambda \ | $`\varGamma \varDelta \varTheta \varLambda | -| | \varXi \varPi \varSigma \varPhi \varUpsilon \ | \varXi \varPi \varSigma \varPhi \varUpsilon | -| | \varOmega | \varOmega` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 192 | \varepsilon \digamma \varkappa \varpi \ | $`\varepsilon \digamma \varkappa \varpi | -| | \varrho \varsigma \vartheta \varphi | \varrho \varsigma \vartheta \varphi` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Hebrew symbols** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 193 | \aleph \beth \gimel \daleth | $`\aleph \beth \gimel \daleth` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Blackboard bold** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 194 | \mathbb{ABCDEFGHI} \ | $`\mathbb{ABCDEFGHI} \\ | -| | \mathbb{JKLMNOPQR} \ | \mathbb{JKLMNOPQR} \\ | -| | \mathbb{STUVWXYZ} | \mathbb{STUVWXYZ}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Boldface** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 195 | \mathbf{ABCDEFGHI} \ | $`\mathbf{ABCDEFGHI} \\ | -| | \mathbf{JKLMNOPQR} \ | \mathbf{JKLMNOPQR} \\ | -| | \mathbf{STUVWXYZ} \ | \mathbf{STUVWXYZ} \\ | -| | \mathbf{abcdefghijklm} \ | \mathbf{abcdefghijklm} \\ | -| | \mathbf{nopqrstuvwxyz} \ | \mathbf{nopqrstuvwxyz} \\ | -| | \mathbf{0123456789} | \mathbf{0123456789}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Boldface Greek** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 196 | \boldsymbol{\Alpha \Beta \Gamma \Delta \ | $`\boldsymbol{\Alpha \Beta \Gamma \Delta | -| | \Epsilon \Zeta \Eta \Theta} | \Epsilon \Zeta \Eta \Theta}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 197 | \boldsymbol{\Iota \Kappa \Lambda \Mu \Nu \Xi\ | $`\boldsymbol{\Iota \Kappa \Lambda \Mu \Nu \Xi | -| | \Omicron \Pi} | \Omicron \Pi}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 198 | \boldsymbol{\Rho \Sigma \Tau \Upsilon \Phi \ | $`\boldsymbol{\Rho \Sigma \Tau \Upsilon \Phi | -| | \Chi \Psi \Omega} | \Chi \Psi \Omega}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 199 | \boldsymbol{\alpha \beta \gamma \delta \ | $`\boldsymbol{\alpha \beta \gamma \delta | -| | \epsilon \zeta \eta \theta} | \epsilon \zeta \eta \theta}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 200 | \boldsymbol{\iota \kappa \lambda \mu \nu \xi\ | $`\boldsymbol{\iota \kappa \lambda \mu \nu \xi | -| | \omicron \pi} | \omicron \pi}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 201 | \boldsymbol{\rho \sigma \tau \upsilon \phi \ | $`\boldsymbol{\rho \sigma \tau \upsilon \phi | -| | \chi \psi \omega} | \chi \psi \omega}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 202 | \boldsymbol{\varepsilon\digamma\varkappa\ | $`\boldsymbol{\varepsilon\digamma\varkappa | -| | \varpi} | \varpi}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 203 | \boldsymbol{\varrho\varsigma\vartheta\varphi} | $`\boldsymbol{\varrho\varsigma\vartheta\varphi}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Italics** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 204 | \mathit{0123456789} | $`\mathit{0123456789}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Greek Italics** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 205 | \mathit{\Alpha \Beta \Gamma \Delta \Epsilon \ | $`\mathit{\Alpha \Beta \Gamma \Delta \Epsilon | -| | \Zeta \Eta \Theta} | \Zeta \Eta \Theta}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 206 | \mathit{\Iota \Kappa \Lambda \Mu \Nu \Xi \ | $`\mathit{\Iota \Kappa \Lambda \Mu \Nu \Xi | -| | \Omicron \Pi} | \Omicron \Pi}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 207 | \mathit{\Rho \Sigma \Tau \Upsilon \Phi \Chi \ | $`\mathit{\Rho \Sigma \Tau \Upsilon \Phi \Chi | -| | \Psi \Omega} | \Psi \Omega}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Greek uppercase boldface italics** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 208 | \boldsymbol{\varGamma \varDelta \varTheta \ | $`\boldsymbol{\varGamma \varDelta \varTheta | -| | \varLambda} | \varLambda}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 209 | \boldsymbol{\varXi \varPi \varSigma \ | $`\boldsymbol{\varXi \varPi \varSigma | -| | \varUpsilon \varOmega} | \varUpsilon \varOmega}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Roman typeface** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 210 | \mathrm{ABCDEFGHI} \ | $`\mathrm{ABCDEFGHI} \\ | -| | \mathrm{JKLMNOPQR} \ | \mathrm{JKLMNOPQR} \\ | -| | \mathrm{STUVWXYZ} \ | \mathrm{STUVWXYZ} \\ | -| | \mathrm{abcdefghijklm} \ | \mathrm{abcdefghijklm} \\ | -| | \mathrm{nopqrstuvwxyz} \ | \mathrm{nopqrstuvwxyz} \\ | -| | \mathrm{0123456789} | \mathrm{0123456789}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Sans serif** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 211 | \mathsf{ABCDEFGHI} \ | $`\mathsf{ABCDEFGHI} \\ | -| | \mathsf{JKLMNOPQR} \ | \mathsf{JKLMNOPQR} \\ | -| | \mathsf{STUVWXYZ} \ | \mathsf{STUVWXYZ} \\ | -| | \mathsf{abcdefghijklm} \ | \mathsf{abcdefghijklm} \\ | -| | \mathsf{nopqrstuvwxyz} \ | \mathsf{nopqrstuvwxyz} \\ | -| | \mathsf{0123456789} | \mathsf{0123456789}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Sans serif Greek** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 212 | \mathsf{\Alpha \Beta \Gamma \Delta \Epsilon \ | $`\mathsf{\Alpha \Beta \Gamma \Delta \Epsilon | -| | \Zeta \Eta \Theta} | \Zeta \Eta \Theta}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 213 | \mathsf{\Iota \Kappa \Lambda \Mu \Nu \Xi \ | $`\mathsf{\Iota \Kappa \Lambda \Mu \Nu \Xi | -| | \Omicron \Pi} | \Omicron \Pi}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 214 | \mathsf{\Rho \Sigma \Tau \Upsilon \Phi \Chi \ | $`\mathsf{\Rho \Sigma \Tau \Upsilon \Phi \Chi | -| | \Psi \Omega} | \Psi \Omega}` | -+-----+-----------------------------------------------+--------------------------------------------------+ - -Unicode has special code points for bold Greek sans-serif, but no code points for\ -regular-weight Greek sans-serif. Since Chromium is not going to support the `math-variant`\ -attribute, these bold Greek sans-serif glyphs are the best approximation I can make to\ -sans-serif Greek. - -
- -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Calligraphy** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 215 | \mathcal{ABCDEFGHI} \ | $`\mathcal{ABCDEFGHI} \\ | -| | \mathcal{JKLMNOPQR} \ | \mathcal{JKLMNOPQR} \\ | -| | \mathcal{STUVWXYZ} \ | \mathcal{STUVWXYZ} \\ | -| | \mathcal{abcdefghi} \ | \mathcal{abcdefghi} \\ | -| | \mathcal{jklmnopqr} \ | \mathcal{jklmnopqr} \\ | -| | \mathcal{stuvwxyz} | \mathcal{stuvwxyz}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Fraktur** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 216 | \mathfrak{ABCDEFGHI} \ | $`\mathfrak{ABCDEFGHI} \\ | -| | \mathfrak{JKLMNOPQR} \ | \mathfrak{JKLMNOPQR} \\ | -| | \mathfrak{STUVWXYZ} \ | \mathfrak{STUVWXYZ} \\ | -| | \mathfrak{abcdefghi} \ | \mathfrak{abcdefghi} \\ | -| | \mathfrak{jklmnopqr} \ | \mathfrak{jklmnopqr} \\ | -| | \mathfrak{stuvwxyz} | \mathfrak{stuvwxyz}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Scriptstyle text** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 217 | {\scriptstyle\text{abcdefghijklm}} | $`{\scriptstyle\text{abcdefghijklm}}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Mixed text faces** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 218 | x y z | $`x y z` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 219 | \text{x y z} | $`\text{x y z}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 220 | \text{if} n \text{is even} | $`\text{if} n \text{is even}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 221 | \text{if }n\text{ is even} | $`\text{if }n\text{ is even}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 222 | \text{if}~n\ \text{is even} | $`\text{if}~n\ \text{is even}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Color** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 223 | {\color{Blue}x^2}+{\color{Orange}2x}-\ | $`{\color{Blue}x^2}+{\color{Orange}2x}- | -| | {\color{LimeGreen}1} | {\color{LimeGreen}1}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 224 | x_{1,2}=\frac{{\color{Blue}-b}\pm\ | $`x_{1,2}=\frac{{\color{Blue}-b}\pm | -| | \sqrt{\color{Red}b^2-4ac}}{\color{Green}2a } | \sqrt{\color{Red}b^2-4ac}}{\color{Green}2a }` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 225 | {\color{Blue}x^2}+{\color{Orange}2x}-\ | $`{\color{Blue}x^2}+{\color{Orange}2x}- | -| | {\color{LimeGreen}1} | {\color{LimeGreen}1}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 226 | \color{Blue}x^2\color{Black}+\color{Orange}\ | $`\color{Blue}x^2\color{Black}+\color{Orange} | -| | 2x\color{Black}-\color{LimeGreen}1 | 2x\color{Black}-\color{LimeGreen}1` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 227 | \color{Blue}{x^2}+\color{Orange}{2x}-\ | $`\color{Blue}{x^2}+\color{Orange}{2x}- | -| | \color{LimeGreen}{1} | \color{LimeGreen}{1}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 228 | \definecolor{myorange}{rgb}{1,0.65,0.4}\ | $`\definecolor{myorange}{rgb}{1,0.65,0.4} | -| | \color{myorange}e^{i \pi}\color{Black} + 1= 0 | \color{myorange}e^{i \pi}\color{Black} + 1= 0` | -+-----+-----------------------------------------------+--------------------------------------------------+ - -For color names, see the [color section](https://temml.org/docs/en/supported.html#color) -in the Temml function support page. - -
- -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Spacing** | -+=====+===============================================+==================================================+ -| 229 | a \qquad b \ | $`a \qquad b \\ | -| | a \quad b \ | a \quad b \\ | -| | a\ b \ | a\ b \\ | -| | a \text{ } b \ | a \text{ } b \\ | -| | a\\;b \ | a\;b \\ | -| | a\\,b \ | a\,b \\ | -| | ab \ | ab \\ | -| | a b \ | a b \\ | -| | \mathit{ab} \ | \mathit{ab} \\ | -| | a\\!b | a\!b` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 230 | | \uparrow \rangle | $`| \uparrow \rangle` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 231 | \left| \uparrow \right\rangle | $`\left| \uparrow \right\rangle` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 232 | | {\uparrow} \rangle | $`| {\uparrow} \rangle` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 233 | | \mathord\uparrow \rangle | $`| \mathord\uparrow \rangle` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Temml replacements for wiki workarounds** | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 234 | \oiint\limits\_D dx\\,dy \ | $$\oiint\limits_D dx\,dy$$ | -| | \oiiint\limits\_E dx\\,dy\\,dz | $$\oiiint\limits_E dx\,dy\,dz$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 234 | \wideparen{AB} | $`\wideparen{AB}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 235 | \dddot{x} | $`\dddot{x}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 236 | \operatorname*{median}\_\ | $$\operatorname*{median}_{j\,\ne\,i} X_{i,j}$$ | -| | {j\\,\ne\\,i} X\_{i,j} | | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 237 | \sout{q} | $`\sout{q}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 238 | \mathrlap{\\,/}{=} | $`\mathrlap{\,/}{=}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 239 | \text{\textsf{textual description}} | $`\text{\textsf{textual description}}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 240 | α π | $`α π` | -+-----+-----------------------------------------------+--------------------------------------------------+ - -`mhchem` examples are displayed on their own [test page](https://temml.org/tests/mhchem-tests.html). - -
- -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Examples of implemented TeX formulas** | -+=====+===============================================+==================================================+ -| 241 | ax^2 + bx + c = 0 | $`ax^2 + bx + c = 0` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 242 | x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} | $`x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 243 | \left( \frac{\left(3-x\right) \ | $`\left( \frac{\left(3-x\right) | -| | \times 2}{3-x} \right) | \times 2}{3-x} \right)` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 244 | S\_{\text{new}} = S\_{\text{old}} - \ | $$S_{\text{new}} = S_{\text{old}} - | -| | \frac{ \left( 5-T \right) ^2} {2} | \frac{ \left( 5-T \right) ^2} {2}$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 245 | \int\_a^x \int\_a^s f(y)\\,dy\\,ds = \ | $$\int_a^x \int_a^s f(y)\,dy\,ds = | -| | \int\_a^x f(y)(x-y)\\,dy | \int_a^x f(y)(x-y)\,dy$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 246 | \int\_e^{\infty}\frac {1}{t(\ln t)^2}dt = \ | $$\int_e^{\infty}\frac {1}{t(\ln t)^2}dt = | -| | \left. \frac{-1}{\ln t}\right\vert\_e^\infty\ | \left. \frac{-1}{\ln t} \right\vert_e^\infty | -| | = 1 | = 1$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 247 | \det(\mathsf{A}-\lambda\mathsf{I}) = 0 | $`\det(\mathsf{A}-\lambda\mathsf{I}) = 0` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 248 | \sum\_{i=0}^{n-1} i | $$\sum_{i=0}^{n-1} i$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 249 | \sum\_{m=1}^\infty\sum\_{n=1}^\infty \ | $$\sum_{m=1}^\infty\sum_{n=1}^\infty | -| | \frac{m^2 n}{3^m\left(m 3^n + n 3^m\right)} | \frac{m^2 n}{3^m\left(m 3^n + n 3^m\right)}$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 250 | u'' + p(x)u' + q(x)u=f(x),\quad x>a | $`u'' + p(x)u' + q(x)u=f(x),\quad x>a` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 251 | |\bar{z}| = |z|, |(\bar{z})^n| = |z|^n, \ | $`|\bar{z}| = |z|, |(\bar{z})^n| = |z|^n, | -| | \arg(z^n) = n \arg(z) | \arg(z^n) = n \arg(z)` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 252 | \lim\_{z\to z\_0} f(z)=f(z\_0) | $$\lim_{z\to z_0} f(z)=f(z_0)$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 253 | \phi_n(\kappa) = \ | $$\phi_n(\kappa) = | -| | \frac{1}{4\pi^2\kappa^2} \int\_0^\infty \ | \frac{1}{4\pi^2\kappa^2} \int_0^\infty | -| | \frac{\sin(\kappa R)}{\kappa R} \ | \frac{\sin(\kappa R)}{\kappa R} | -| | \frac{\partial}{\partial R} \ | \frac{\partial}{\partial R} | -| | \left [ R^2\frac{\partial D\_n(R)}\ | \left [ R^2\frac{\partial D_n(R)} | -| | {\partial R} \right ] \\,dR | {\partial R} \right ] \,dR$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 254 | \phi\_n(\kappa) = 0.033C\_n^2\kappa^{-11/3},\ | $`\phi_n(\kappa) = 0.033C_n^2\kappa^{-11/3}, | -| | \quad\frac{1}{L\_0}\ll\kappa\ll\frac{1}{l\_0} | \quad\frac{1}{L_0}\ll\kappa\ll\frac{1}{l_0}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 255 | f(x) = \begin{cases} \ | $`f(x) = \begin{cases} | -| | 1 & -1 \le x < 0 \\\\ \ | 1 & -1 \le x < 0 \\ | -| | \frac{1}{2} & x = 0 \\\\ \ | \frac{1}{2} & x = 0 \\ | -| | 1 - x^2 & \text{otherwise} \ | 1 - x^2 & \text{otherwise} | -| | \end{cases} | \end{cases}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 256 | {}\_pF\_q(a\_1,\dots,a\_p;c\_1,\dots,c\_q;z)\ | $`{}_pF_q(a_1,\dots,a_p;c_1,\dots,c_q;z) | -| | = \sum\_{n=0}^\infty \ | = \sum_{n=0}^\infty | -| | \frac{(a_1)\_n\cdots(a_p)\_n}\ | \frac{(a_1)_n\cdots(a_p)_n} | -| | {(c\_1)\_n\cdots(c\_q)_n}\frac{z^n}{n!} | {(c_1)_n\cdots(c_q)_n}\frac{z^n}{n!}` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 258 | \frac{a}{b}\ \tfrac{a}{b} | $$\frac{a}{b}\ \tfrac{a}{b}$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 259 | S=dD\sin\alpha | $`S=dD\sin\alpha` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 260 | V = \frac{1}{6} \pi h \left [ 3 \left \ | $`V = \frac{1}{6} \pi h \left [ 3 \left | -| | ( r_1^2 + r_2^2 \right ) + h^2 \right ] | ( r_1^2 + r_2^2 \right ) + h^2 \right ]` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 261 | \begin{align} \ | $$\begin{align} | -| | u & = \tfrac{1}{\sqrt{2}}(x+y) \qquad & \ | u & = \tfrac{1}{\sqrt{2}}(x+y) \qquad & | -| | x &= \tfrac{1}{\sqrt{2}}(u+v) \\\\[0.6ex] \ | x &= \tfrac{1}{\sqrt{2}}(u+v) \\[0.6ex] | -| | v & = \tfrac{1}{\sqrt{2}}(x-y) \qquad & \ | v & = \tfrac{1}{\sqrt{2}}(x-y) \qquad & | -| | y &= \tfrac{1}{\sqrt{2}}(u-v) \ | y &= \tfrac{1}{\sqrt{2}}(u-v) | -| | \end{align} | \end{align}$$ | -+-----+-----------------------------------------------+--------------------------------------------------+ - -That concludes the tests from Wikipedia. Now a few more tests. - -
- -+-----+-----------------------------------------------+--------------------------------------------------+ -| **Linear Logic** | -+=====+===============================================+==================================================+ -| 262 | A \with B \parr C | $`A \with B \parr C` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 263 | a \coh \oc b \incoh \wn c \scoh d \sincoh e | $`a \coh \oc b \incoh \wn c \scoh d \sincoh e` | -+-----+-----------------------------------------------+--------------------------------------------------+ -| 264 | a \Perp \shpos b \multimapinv \shneg c | $`a \Perp \shpos b \multimapinv \shneg c` | -+-----+-----------------------------------------------+--------------------------------------------------+ - -+-----+----------------------------------------------+-------------------------------------------------+ -| **Nested font size** | -+=====+==============================================+=================================================+ -| 265 | \mathrm{f{\large f{\normalsize f{\tiny f}}}} | $`\mathrm{f{\large f{\normalsize f{\tiny f}}}}` | -+-----+----------------------------------------------+-------------------------------------------------+ - -
- - diff --git a/utils/TeXZilla.js b/utils/TeXZilla.js deleted file mode 100644 index 84d96fa6..00000000 --- a/utils/TeXZilla.js +++ /dev/null @@ -1,4220 +0,0 @@ -/* THIS IS A GENERATED FILE. DO NOT EDIT THIS DIRECTLY. */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; -/* parser generated by jison 0.4.18 */ -/* - Returns a Parser object of the following structure: - - Parser: { - yy: {} - } - - Parser.prototype: { - yy: {}, - trace: function(), - symbols_: {associative list: name ==> number}, - terminals_: {associative list: number ==> name}, - productions_: [...], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), - table: [...], - defaultActions: {...}, - parseError: function(str, hash), - parse: function(input), - - lexer: { - EOF: 1, - parseError: function(str, hash), - setInput: function(input), - input: function(), - unput: function(str), - more: function(), - less: function(n), - pastInput: function(), - upcomingInput: function(), - showPosition: function(), - test_match: function(regex_match_array, rule_index), - next: function(), - lex: function(), - begin: function(condition), - popState: function(), - _currentRules: function(), - topState: function(), - pushState: function(condition), - - options: { - ranges: boolean (optional: true ==> token location info will include a .range[] member) - flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) - backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) - }, - - performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), - rules: [...], - conditions: {associative list: name ==> set}, - } - } - - - token location info (@$, _$, etc.): { - first_line: n, - last_line: n, - first_column: n, - last_column: n, - range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) - } - - - the parseError function receives a 'hash' object with these members for lexer and parser errors: { - text: (matched text) - token: (the produced terminal token, if any) - line: (yylineno) - } - while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { - loc: (yylloc) - expected: (string describing the set of expected tokens) - recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) - } -*/ -var TeXZilla = (function(){ -var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,4],$V1=[1,6],$V2=[1,7],$V3=[1,8],$V4=[1,9],$V5=[68,195,198,200,202,204],$V6=[1,27],$V7=[1,124],$V8=[1,52],$V9=[1,48],$Va=[1,28],$Vb=[1,29],$Vc=[1,30],$Vd=[1,31],$Ve=[1,32],$Vf=[1,33],$Vg=[1,34],$Vh=[1,35],$Vi=[1,37],$Vj=[1,38],$Vk=[1,39],$Vl=[1,40],$Vm=[1,41],$Vn=[1,42],$Vo=[1,43],$Vp=[1,44],$Vq=[1,45],$Vr=[1,46],$Vs=[1,47],$Vt=[1,49],$Vu=[1,50],$Vv=[1,51],$Vw=[1,53],$Vx=[1,54],$Vy=[1,55],$Vz=[1,56],$VA=[1,57],$VB=[1,58],$VC=[1,59],$VD=[1,60],$VE=[1,61],$VF=[1,62],$VG=[1,63],$VH=[1,64],$VI=[1,65],$VJ=[1,66],$VK=[1,67],$VL=[1,68],$VM=[1,69],$VN=[1,70],$VO=[1,71],$VP=[1,72],$VQ=[1,73],$VR=[1,74],$VS=[1,75],$VT=[1,76],$VU=[1,77],$VV=[1,78],$VW=[1,79],$VX=[1,80],$VY=[1,81],$VZ=[1,82],$V_=[1,83],$V$=[1,84],$V01=[1,85],$V11=[1,86],$V21=[1,87],$V31=[1,88],$V41=[1,89],$V51=[1,90],$V61=[1,91],$V71=[1,92],$V81=[1,93],$V91=[1,94],$Va1=[1,95],$Vb1=[1,96],$Vc1=[1,97],$Vd1=[1,98],$Ve1=[1,99],$Vf1=[1,100],$Vg1=[1,101],$Vh1=[1,102],$Vi1=[1,103],$Vj1=[1,104],$Vk1=[1,105],$Vl1=[1,106],$Vm1=[1,107],$Vn1=[1,24],$Vo1=[1,108],$Vp1=[1,109],$Vq1=[1,110],$Vr1=[1,111],$Vs1=[1,112],$Vt1=[1,113],$Vu1=[1,114],$Vv1=[1,115],$Vw1=[1,116],$Vx1=[1,117],$Vy1=[1,118],$Vz1=[1,119],$VA1=[1,120],$VB1=[1,121],$VC1=[1,122],$VD1=[1,123],$VE1=[1,16],$VF1=[1,17],$VG1=[1,18],$VH1=[1,19],$VI1=[1,20],$VJ1=[1,21],$VK1=[1,22],$VL1=[6,10,53,64,65,66,144,146,148,150,152,154,156,158,160,162,164,189,192,199,201,203,205],$VM1=[8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,145,147,149,151,153,155,157,159,161,163,165,166,173,174,179,180,181,182,183,184,185],$VN1=[1,134],$VO1=[6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,173,174,189,192,199,201,203,205],$VP1=[1,137],$VQ1=[6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,169,170,171,173,174,189,192,199,201,203,205],$VR1=[1,161],$VS1=[2,197],$VT1=[1,217],$VU1=[1,214],$VV1=[6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,169,170,173,174,189,192,199,201,203,205],$VW1=[1,241],$VX1=[1,243],$VY1=[1,244],$VZ1=[1,259],$V_1=[4,8],$V$1=[1,275],$V02=[8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,141,142,145,147,149,151,153,155,157,159,161,163,165,166],$V12=[1,286],$V22=[10,144,146,148,150,152,154,156,158,160,162,164,192],$V32=[1,288],$V42=[10,144,146,148,150,152,154,156,158,160,162,164,189,192],$V52=[164,189,192],$V62=[10,189,192],$V72=[1,343],$V82=[1,344],$V92=[1,352],$Va2=[1,353],$Vb2=[4,8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,145,147,149,151,153,155,157,159,161,163,165,166],$Vc2=[10,21,23],$Vd2=[10,21,23,25,27],$Ve2=[1,399],$Vf2=[1,400],$Vg2=[1,401],$Vh2=[1,402],$Vi2=[1,403],$Vj2=[1,404],$Vk2=[1,405],$Vl2=[1,406],$Vm2=[10,19,21,23,25,27,29,31,33,35,37,39,41],$Vn2=[10,19,21,23,29,31,33,35,37,39,41]; -var parser = {trace: function trace () { }, -yy: {}, -symbols_: {"error":2,"textOptArg":3,"[":4,"TEXTOPTARG":5,"]":6,"textArg":7,"{":8,"TEXTARG":9,"}":10,"lengthOptArg":11,"lengthArg":12,"attrOptArg":13,"attrArg":14,"tokenContent":15,"arrayAlign":16,"columnAlign":17,"collayout":18,"COLLAYOUT":19,"colalign":20,"COLALIGN":21,"rowalign":22,"ROWALIGN":23,"rowspan":24,"ROWSPAN":25,"colspan":26,"COLSPAN":27,"align":28,"ALIGN":29,"eqrows":30,"EQROWS":31,"eqcols":32,"EQCOLS":33,"rowlines":34,"ROWLINES":35,"collines":36,"COLLINES":37,"frame":38,"FRAME":39,"padding":40,"PADDING":41,"cellopt":42,"celloptList":43,"rowopt":44,"arrayopt":45,"arrayoptList":46,"rowoptList":47,"left":48,"LEFT":49,"OPFS":50,".":51,"right":52,"RIGHT":53,"closedTerm":54,"styledExpression":55,"BIG":56,"BBIG":57,"BIGG":58,"BBIGG":59,"BIGL":60,"BBIGL":61,"BIGGL":62,"BBIGGL":63,"TEXATOP":64,"TEXOVER":65,"TEXCHOOSE":66,"NUM":67,"TEXT":68,"A":69,"AILL":70,"AIUL":71,"AILG":72,"AIUG":73,"F":74,"MI":75,"MN":76,"MO":77,"OP":78,"OPS":79,"OPAS":80,"MS":81,"MTEXT":82,"HIGH_SURROGATE":83,"LOW_SURROGATE":84,"BMP_CHARACTER":85,"OPERATORNAME":86,"MATHOP":87,"MATHBIN":88,"MATHREL":89,"FRAC":90,"ROOT":91,"SQRT":92,"UNDERSET":93,"OVERSET":94,"UNDEROVERSET":95,"XARROW":96,"MATHRLAP":97,"MATHLLAP":98,"MATHCLAP":99,"PHANTOM":100,"TFRAC":101,"BINOM":102,"TBINOM":103,"PMOD":104,"UNDERBRACE":105,"UNDERLINE":106,"OVERBRACE":107,"ACCENT":108,"ACCENTNS":109,"BOXED":110,"SLASH":111,"QUAD":112,"QQUAD":113,"NEGSPACE":114,"NEGMEDSPACE":115,"NEGTHICKSPACE":116,"THINSPACE":117,"MEDSPACE":118,"THICKSPACE":119,"SPACE":120,"MATHRAISEBOX":121,"MATHBB":122,"MATHBF":123,"MATHBIT":124,"MATHSCR":125,"MATHBSCR":126,"MATHSF":127,"MATHFRAK":128,"MATHIT":129,"MATHTT":130,"MATHRM":131,"HREF":132,"STATUSLINE":133,"TOOLTIP":134,"TOGGLE":135,"BTOGGLE":136,"closedTermList":137,"ETOGGLE":138,"TENSOR":139,"subsupList":140,"MULTI":141,"BMATRIX":142,"tableRowList":143,"EMATRIX":144,"BGATHERED":145,"EGATHERED":146,"BPMATRIX":147,"EPMATRIX":148,"BBMATRIX":149,"EBMATRIX":150,"BVMATRIX":151,"EVMATRIX":152,"BBBMATRIX":153,"EBBMATRIX":154,"BVVMATRIX":155,"EVVMATRIX":156,"BSMALLMATRIX":157,"ESMALLMATRIX":158,"BCASES":159,"ECASES":160,"BALIGNED":161,"EALIGNED":162,"BARRAY":163,"EARRAY":164,"SUBSTACK":165,"ARRAY":166,"ARRAYOPTS":167,"compoundTerm":168,"_":169,"^":170,"OPP":171,"opm":172,"OPM":173,"FM":174,"compoundTermList":175,"subsupTermScript":176,"subsupTerm":177,"textstyle":178,"DISPLAYSTYLE":179,"TEXTSTYLE":180,"TEXTSIZE":181,"SCRIPTSIZE":182,"SCRIPTSCRIPTSIZE":183,"COLOR":184,"BGCOLOR":185,"tableCell":186,"CELLOPTS":187,"tableCellList":188,"COLSEP":189,"tableRow":190,"ROWOPTS":191,"ROWSEP":192,"document":193,"documentItemList":194,"EOF":195,"documentItem":196,"mathItem":197,"STARTMATH0":198,"ENDMATH0":199,"STARTMATH1":200,"ENDMATH1":201,"STARTMATH2":202,"ENDMATH2":203,"STARTMATH3":204,"ENDMATH3":205,"$accept":0,"$end":1}, -terminals_: {2:"error",4:"[",5:"TEXTOPTARG",6:"]",8:"{",9:"TEXTARG",10:"}",19:"COLLAYOUT",21:"COLALIGN",23:"ROWALIGN",25:"ROWSPAN",27:"COLSPAN",29:"ALIGN",31:"EQROWS",33:"EQCOLS",35:"ROWLINES",37:"COLLINES",39:"FRAME",41:"PADDING",49:"LEFT",50:"OPFS",51:".",53:"RIGHT",56:"BIG",57:"BBIG",58:"BIGG",59:"BBIGG",60:"BIGL",61:"BBIGL",62:"BIGGL",63:"BBIGGL",64:"TEXATOP",65:"TEXOVER",66:"TEXCHOOSE",67:"NUM",68:"TEXT",69:"A",70:"AILL",71:"AIUL",72:"AILG",73:"AIUG",74:"F",75:"MI",76:"MN",77:"MO",78:"OP",79:"OPS",80:"OPAS",81:"MS",82:"MTEXT",83:"HIGH_SURROGATE",84:"LOW_SURROGATE",85:"BMP_CHARACTER",86:"OPERATORNAME",87:"MATHOP",88:"MATHBIN",89:"MATHREL",90:"FRAC",91:"ROOT",92:"SQRT",93:"UNDERSET",94:"OVERSET",95:"UNDEROVERSET",96:"XARROW",97:"MATHRLAP",98:"MATHLLAP",99:"MATHCLAP",100:"PHANTOM",101:"TFRAC",102:"BINOM",103:"TBINOM",104:"PMOD",105:"UNDERBRACE",106:"UNDERLINE",107:"OVERBRACE",108:"ACCENT",109:"ACCENTNS",110:"BOXED",111:"SLASH",112:"QUAD",113:"QQUAD",114:"NEGSPACE",115:"NEGMEDSPACE",116:"NEGTHICKSPACE",117:"THINSPACE",118:"MEDSPACE",119:"THICKSPACE",120:"SPACE",121:"MATHRAISEBOX",122:"MATHBB",123:"MATHBF",124:"MATHBIT",125:"MATHSCR",126:"MATHBSCR",127:"MATHSF",128:"MATHFRAK",129:"MATHIT",130:"MATHTT",131:"MATHRM",132:"HREF",133:"STATUSLINE",134:"TOOLTIP",135:"TOGGLE",136:"BTOGGLE",138:"ETOGGLE",139:"TENSOR",141:"MULTI",142:"BMATRIX",144:"EMATRIX",145:"BGATHERED",146:"EGATHERED",147:"BPMATRIX",148:"EPMATRIX",149:"BBMATRIX",150:"EBMATRIX",151:"BVMATRIX",152:"EVMATRIX",153:"BBBMATRIX",154:"EBBMATRIX",155:"BVVMATRIX",156:"EVVMATRIX",157:"BSMALLMATRIX",158:"ESMALLMATRIX",159:"BCASES",160:"ECASES",161:"BALIGNED",162:"EALIGNED",163:"BARRAY",164:"EARRAY",165:"SUBSTACK",166:"ARRAY",167:"ARRAYOPTS",169:"_",170:"^",171:"OPP",173:"OPM",174:"FM",179:"DISPLAYSTYLE",180:"TEXTSTYLE",181:"TEXTSIZE",182:"SCRIPTSIZE",183:"SCRIPTSCRIPTSIZE",184:"COLOR",185:"BGCOLOR",187:"CELLOPTS",189:"COLSEP",191:"ROWOPTS",192:"ROWSEP",195:"EOF",198:"STARTMATH0",199:"ENDMATH0",200:"STARTMATH1",201:"ENDMATH1",202:"STARTMATH2",203:"ENDMATH2",204:"STARTMATH3",205:"ENDMATH3"}, -productions_: [0,[3,3],[7,3],[11,3],[12,3],[13,1],[14,1],[15,1],[16,1],[17,1],[18,2],[20,2],[22,2],[24,2],[26,2],[28,2],[30,2],[32,2],[34,2],[36,2],[38,2],[40,2],[42,1],[42,1],[42,1],[42,1],[43,1],[43,2],[44,1],[44,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[46,1],[46,2],[47,1],[47,2],[48,2],[48,2],[52,2],[52,2],[54,2],[54,3],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,3],[54,5],[54,5],[54,5],[54,5],[54,5],[54,5],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,2],[54,2],[54,2],[54,1],[54,1],[54,1],[54,1],[54,1],[54,2],[54,4],[54,2],[54,2],[54,1],[54,2],[54,2],[54,2],[54,2],[54,3],[54,3],[54,2],[54,5],[54,3],[54,3],[54,4],[54,5],[54,2],[54,2],[54,2],[54,2],[54,2],[54,3],[54,3],[54,3],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,4],[54,5],[54,4],[54,3],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,3],[54,3],[54,3],[54,3],[54,3],[54,5],[54,8],[54,7],[54,7],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,5],[54,4],[54,4],[54,4],[54,8],[137,1],[137,2],[168,3],[168,5],[168,4],[168,5],[168,4],[168,3],[168,3],[168,2],[168,1],[168,5],[168,5],[168,3],[168,3],[168,1],[172,1],[172,1],[175,1],[175,2],[176,1],[176,1],[177,4],[177,2],[177,2],[177,3],[140,1],[140,2],[178,1],[178,1],[178,1],[178,1],[178,1],[178,2],[178,2],[55,2],[55,1],[186,0],[186,5],[186,1],[188,1],[188,3],[190,5],[190,1],[143,1],[143,3],[193,2],[194,1],[194,2],[196,1],[196,1],[197,2],[197,3],[197,2],[197,3],[197,3],[197,3]], -performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { -/* this == yyval */ - -var $0 = $$.length - 1; -switch (yystate) { -case 1: - - /* Unescape \] and \\. */ - this.$ = $$[$0-1].replace(/\\[\\\]]/g, function(match) { return match.slice(1); }); - /* Escape some XML characters. */ - this.$ = escapeText(this.$); - -break; -case 2: - - /* Unescape \} and \\. */ - this.$ = $$[$0-1].replace(/\\[\\\}]/g, function(match) { return match.slice(1); }); - /* Escape some XML characters. */ - this.$ = escapeText(this.$); - -break; -case 3: case 4: - - this.$ = parseLength($$[$0-1]); - -break; -case 5: case 6: - this.$ = escapeQuote($$[$0]); -break; -case 7: - - /* The MathML specification indicates that trailing/leading whitespaces - should be removed and that inner whitespace should be collapsed. Let's - replace trailing/leading whitespace by no-break space so that people can - write e.g. \text{ if }. We also collapse internal whitespace here. - See https://github.com/fred-wang/TeXZilla/issues/25. */ - this.$ = $$[$0].replace(/\s+/g, " ").replace(/^ | $/g, "\u00A0"); - -break; -case 8: - - $$[$0] = $$[$0].trim(); - if ($$[$0] === "t") { - this.$ = "axis 1"; - } else if ($$[$0] === "c") { - this.$ = "center"; - } else if ($$[$0] === "b") { - this.$ = "axis -1"; - } else { - throw "Unknown array alignment"; - } - -break; -case 9: - - this.$ = ""; - $$[$0] = $$[$0].replace(/\s+/g, "");; - for (var i = 0; i < $$[$0].length; i++) { - if ($$[$0][i] === "c") { - this.$ += " center"; - } else if ($$[$0][i] === "l") { - this.$ += " left"; - } else if ($$[$0][i] === "r") { - this.$ += " right"; - } - } - if (this.$.length) { - this.$ = this.$.slice(1); - } else { - throw "Invalid column alignments"; - } - -break; -case 10: case 11: - this.$ = {"columnalign": $$[$0]}; -break; -case 12: - this.$ = {"rowalign": $$[$0]}; -break; -case 13: - this.$ = {"rowspan": $$[$0]}; -break; -case 14: - this.$ = {"colspan": $$[$0]}; -break; -case 15: - this.$ = {"align": $$[$0]}; -break; -case 16: - this.$ = {"equalrows": $$[$0]}; -break; -case 17: - this.$ = {"equalcolumns": $$[$0]}; -break; -case 18: - this.$ = {"rowlines": $$[$0]}; -break; -case 19: - this.$ = {"columnlines": $$[$0]}; -break; -case 20: - this.$ = {"frame": $$[$0]}; -break; -case 21: - this.$ = {"rowspacing": $$[$0], "columnspacing": $$[$0]}; -break; -case 22: case 23: case 24: case 25: case 26: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 42: case 170: case 175: case 180: case 181: case 186: case 196: case 207: case 209: - this.$ = $$[$0]; -break; -case 27: case 41: case 43: - this.$ = Object.assign($$[$0-1], $$[$0]); -break; -case 44: case 46: - - this.$ = newMo($$[$0]); - -break; -case 45: case 47: - - this.$ = ""; - -break; -case 48: - this.$ = newTag("mrow"); -break; -case 49: - this.$ = newMrow($$[$0-1]); -break; -case 50: case 54: - - this.$ = newTag("mo", $$[$0], {"maxsize": "1.2em", "minsize": "1.2em"}); - -break; -case 51: case 55: - - this.$ = newTag("mo", $$[$0], {"maxsize": "1.8em", "minsize": "1.8em"}); - -break; -case 52: case 56: - - this.$ = newTag("mo", $$[$0], {"maxsize": "2.4em", "minsize": "2.4em"}); - -break; -case 53: case 57: - - this.$ = newTag("mo", $$[$0], {"maxsize": "3em", "minsize": "3em"}); - -break; -case 58: - - this.$ = newTag("mrow", [$$[$0-2], newMrow($$[$0-1]), $$[$0]]); - -break; -case 59: - - this.$ = newTag("mfrac", [newMrow($$[$0-3]), newMrow($$[$0-1])], {"linethickness": "0px"}); - -break; -case 60: - - this.$ = newTag("mfrac", [newMrow($$[$0-3]), newMrow($$[$0-1])], {"linethickness": "0px"}); - this.$ = newTag("mrow", [$$[$0-4], this.$, $$[$0]]); - -break; -case 61: - - this.$ = newTag("mfrac", [newMrow($$[$0-3]), newMrow($$[$0-1])]); - -break; -case 62: - - this.$ = newTag("mfrac", [newMrow($$[$0-3]), newMrow($$[$0-1])]); - this.$ = newTag("mrow", [$$[$0-4], this.$, $$[$0]]); - -break; -case 63: - - this.$ = newTag("mfrac", [newMrow($$[$0-3]), newMrow($$[$0-1])], {"linethickness": "0px"}); - this.$ = newTag("mrow", [newMo("("), this.$, newMo(")")]); - -break; -case 64: - - this.$ = newTag("mfrac", [newMrow($$[$0-3]), newMrow($$[$0-1])], {"linethickness": "0px"}); - this.$ = newTag("mrow", [$$[$0-4], this.$, $$[$0]]); - this.$ = newTag("mrow", [newMo("("), this.$, newMo(")")]); - -break; -case 65: case 74: - this.$ = newTag("mn", $$[$0]); -break; -case 66: case 83: case 85: - this.$ = newTag("mtext", $$[$0]); -break; -case 67: case 68: case 69: case 70: - this.$ = newMi($$[$0]); -break; -case 71: - this.$ = newMi($$[$0], true); -break; -case 72: case 177: - this.$ = newMo($$[$0], 0, 0); -break; -case 73: - this.$ = newTag("mi", $$[$0]); -break; -case 75: case 76: case 77: case 176: - this.$ = newMo($$[$0]); -break; -case 78: case 79: case 80: - this.$ = newTag("mo", $$[$0], {"stretchy": "false"}); -break; -case 81: - this.$ = newTag("ms", $$[$0]); -break; -case 82: - - this.$ = newTag("ms", $$[$0], {"lquote": $$[$0-2], "rquote": $$[$0-1]}); - -break; -case 84: - this.$ = newTag("mtext", $$[$0-1] + $$[$0]); -break; -case 86: - - this.$ = newMo($$[$0], 0, namedSpaceToEm("thinmathspace")); - -break; -case 87: - - this.$ = newMo($$[$0], namedSpaceToEm("thinmathspace"), - namedSpaceToEm("thinmathspace")); - -break; -case 88: - - this.$ = newMo($$[$0], namedSpaceToEm("mediummathspace"), - namedSpaceToEm("mediummathspace")); - -break; -case 89: - - this.$ = newMo($$[$0], namedSpaceToEm("thickmathspace"), - namedSpaceToEm("thickmathspace")); - -break; -case 90: - this.$ = newTag("mfrac", [$$[$0-1], $$[$0]]); -break; -case 91: - this.$ = newTag("mroot", [$$[$0], $$[$0-1]]); -break; -case 92: - this.$ = newTag("msqrt", [$$[$0]]); -break; -case 93: - - this.$ = newTag("mroot", [$$[$0], newMrow($$[$0-2])]); - -break; -case 94: - this.$ = newTag("munder", [$$[$0], $$[$0-1]]); -break; -case 95: - this.$ = newTag("mover", [$$[$0], $$[$0-1]]); -break; -case 96: - - this.$ = newTag("munderover", [$$[$0], $$[$0-2], $$[$0-1]]); -break; -case 97: - - this.$ = (isEmptyMrow($$[$0]) ? - newTag("munder", [newMo($$[$0-4]), newMrow($$[$0-2])]) : - newTag("munderover", [newMo($$[$0-4]), newMrow($$[$0-2]), $$[$0]])); - -break; -case 98: - - this.$ = newTag("mover", [newMo($$[$0-1]), $$[$0]]); - -break; -case 99: - this.$ = newTag("mpadded", [$$[$0]], {"width": "0em"}); -break; -case 100: - - this.$ = newTag("mpadded", [$$[$0]], {"width": "0em", "lspace": "-100%width"}); - -break; -case 101: - - this.$ = newTag("mpadded", [$$[$0]], {"width": "0em", "lspace": "-50%width"}); - -break; -case 102: - this.$ = newTag("mphantom", [$$[$0]]); -break; -case 103: - - this.$ = newTag("mfrac", [$$[$0-1], $$[$0]]); - this.$ = newMrow([this.$], "mstyle", {"displaystyle": "false"}); - -break; -case 104: - - this.$ = newTag("mfrac", [$$[$0-1], $$[$0]], {"linethickness": "0px"}); - this.$ = newTag("mrow", [newMo("("), this.$, newMo(")")]); - -break; -case 105: - - this.$ = newTag("mfrac", [$$[$0-1], $$[$0]], {"linethickness": "0px"}); - this.$ = newMrow([this.$], "mstyle", {"displaystyle": "false"}); - this.$ = newTag("mrow", [newMo("("), this.$, newMo(")")]); - -break; -case 106: - - this.$ = newTag("mrow", - [newMo("(", namedSpaceToEm("mediummathspace")), - newMo("mod", undefined, namedSpaceToEm("thinmathspace")), $$[$0], - newMo(")", undefined, namedSpaceToEm("mediummathspace"))]); - -break; -case 107: - this.$ = newTag("munder", [$$[$0], newMo("\u23DF")]); -break; -case 108: - this.$ = newTag("munder", [$$[$0], newMo("_")]); -break; -case 109: - this.$ = newTag("mover", [$$[$0], newMo("\u23DE")]); -break; -case 110: - - this.$ = newTag("mover", [$$[$0], newMo($$[$0-1])]); - -break; -case 111: - - this.$ = newTag("mover", [$$[$0], newTag("mo", $$[$0-1], {"stretchy": "false"})]); - -break; -case 112: - this.$ = newTag("menclose", [$$[$0]], {"notation": "box"}); -break; -case 113: - - this.$ = newTag("menclose", [$$[$0]], {"notation": "updiagonalstrike"}); - -break; -case 114: - this.$ = newSpace(1); -break; -case 115: - this.$ = newSpace(2); -break; -case 116: - this.$ = newSpace(namedSpaceToEm("negativethinmathspace")); -break; -case 117: - this.$ = newSpace(namedSpaceToEm("negativemediummathspace")); -break; -case 118: - this.$ = newSpace(namedSpaceToEm("negativethickmathspace")); -break; -case 119: - this.$ = newSpace(namedSpaceToEm("thinmathspace")); -break; -case 120: - this.$ = newSpace(namedSpaceToEm("mediummathspace")); -break; -case 121: - this.$ = newSpace(namedSpaceToEm("thickmathspace")); -break; -case 122: - - this.$ = newTag("mspace", null, - {"height": "." + $$[$0-2] + "ex", - "depth": "." + $$[$0-1] + "ex", - "width": "." + $$[$0] + "em"}); - -break; -case 123: - - this.$ = newTag("mpadded", [$$[$0]], - {"voffset": $$[$0-3].l + $$[$0-3].u, - "height": $$[$0-2].l + $$[$0-2].u, - "depth": $$[$0-1].l + $$[$0-1].u}); - -break; -case 124: - - this.$ = newTag("mpadded", [$$[$0]], - {"voffset": $$[$0-2].l + $$[$0-2].u, - "height": $$[$0-1].l + $$[$0-1].u, - "depth": ($$[$0-2].l < 0 ? "+" + (-$$[$0-2].l) + $$[$0-2].u : "depth")}); - -break; -case 125: - - var attributes = {"voffset": $$[$0-1].l + $$[$0-1].u}; - if ($$[$0-1].l >= 0) - attributes.height = "+" + $$[$0-1].l + $$[$0-1].u; - else { - attributes.height = "0pt"; - attributes.depth = "+" + (-$$[$0-1].l) + $$[$0-1].u; - } - this.$ = newTag("mpadded", [$$[$0]], attributes); - -break; -case 126: - - this.$ = newMrow([$$[$0]], "mstyle", {"mathvariant": "double-struck"}); - -break; -case 127: - this.$ = newMrow([$$[$0]], "mstyle", {"mathvariant": "bold"}); -break; -case 128: - this.$ = newMrow([$$[$0]], "mstyle", - {"mathvariant": "bold-italic"}); -break; -case 129: - this.$ = newMrow([$$[$0]], "mstyle", - {"mathvariant": "script"}); -break; -case 130: - - this.$ = newMrow([$$[$0]], "mstyle", {"mathvariant": "bold-script"}); - -break; -case 131: - - this.$ = newMrow([$$[$0]], "mstyle", {"mathvariant": "sans-serif"}); - -break; -case 132: - this.$ = newMrow([$$[$0]], "mstyle", - {"mathvariant": "fraktur"}); -break; -case 133: - this.$ = newMrow([$$[$0]], "mstyle", - {"mathvariant": "italic"}); -break; -case 134: - this.$ = newMrow([$$[$0]], "mstyle", - {"mathvariant": "monospace"}); -break; -case 135: - this.$ = newMrow([$$[$0]], "mstyle", - {"mathvariant": "normal"}); -break; -case 136: - - this.$ = newTag("mrow", [$$[$0]], yy.mSafeMode ? null : {"href": $$[$0-1]}); - -break; -case 137: - - this.$ = yy.mSafeMode ? $$[$0] : - newTag("maction", - [$$[$0], newTag("mtext", $$[$0-1])], {"actiontype": "statusline"}); - -break; -case 138: - - this.$ = yy.mSafeMode ? $$[$0] : - newTag("maction", - [$$[$0], newTag("mtext", $$[$0-1])], {"actiontype": "tooltip"}); - -break; -case 139: - - /* Backward compatibility with itex2MML */ - this.$ = yy.mSafeMode ? $$[$0] : - newTag("maction", [$$[$0-1], $$[$0]], {"actiontype": "toggle", selection: "2"}); - -break; -case 140: - - this.$ = yy.mSafeMode ? newTag("mrow", $$[$0-1]) : - newTag("maction", $$[$0-1], {"actiontype": "toggle"}); - -break; -case 141: case 144: - - this.$ = newTag("mmultiscripts", [$$[$0-3]].concat($$[$0-1])); - -break; -case 142: - - this.$ = newTag("mmultiscripts", [$$[$0-3]].concat($$[$0-1]).concat(newTag("mprescripts")).concat($$[$0-5])); - -break; -case 143: - - this.$ = newTag("mmultiscripts", [$$[$0-2], newTag("mprescripts")].concat($$[$0-4])); - -break; -case 145: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", "rowspacing": "0.5ex"}); - -break; -case 146: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "true", "rowspacing": "1.0ex"}); - -break; -case 147: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", "rowspacing": "0.5ex"}); - this.$ = newTag("mrow", [newMo("("), this.$, newMo(")")]); - -break; -case 148: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", "rowspacing": "0.5ex"}); - this.$ = newTag("mrow", [newMo("["), this.$, newMo("]")]); - -break; -case 149: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", "rowspacing": "0.5ex"}); - this.$ = newTag("mrow", [newMo("|"), this.$, newMo("|")]); - -break; -case 150: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", "rowspacing": "0.5ex"}); - this.$ = newTag("mrow", [newMo("{"), this.$, newMo("}")]); - -break; -case 151: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", "rowspacing": "0.5ex"}); - this.$ = newTag("mrow", [newMo("\u2016"), this.$, newMo("\u2016")]); - -break; -case 152: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", "rowspacing": "0.5ex"}); - this.$ = newMrow([this.$], "mstyle", {"scriptlevel": "2"}); - -break; -case 153: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false", - "columnalign": "left left"}); - this.$ = newTag("mrow", [newMo("{"), this.$]); - -break; -case 154: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "true", - "columnalign": "right left right left right left right left right left", - "columnspacing": "0em"}); - -break; -case 155: - - this.$ = newTag("mtable", $$[$0-1], - {"displaystyle": "false", "rowspacing": "0.5ex", "align": $$[$0-3], - "columnalign": $$[$0-2]}); - -break; -case 156: - - this.$ = newTag("mtable", $$[$0-1], - {"displaystyle": "false", "rowspacing": "0.5ex", - "columnalign": $$[$0-2]}); - -break; -case 157: - - this.$ = newTag("mtable", $$[$0-1], - {"displaystyle": "false", "columnalign": "center", - "rowspacing": "0.5ex"}); - -break; -case 158: - - this.$ = newTag("mtable", $$[$0-1], {"displaystyle": "false"}); - -break; -case 159: - - this.$ = newTag("mtable", $$[$0-1], Object.assign($$[$0-3], {"displaystyle": "false"})); - -break; -case 160: - - this.$ = [$$[$0]]; - -break; -case 161: - - this.$ = $$[$0-1].concat([$$[$0]]); - -break; -case 162: - - this.$ = newTag("mmultiscripts", [$$[$0-1]].concat($$[$0])); - -break; -case 163: - - this.$ = newTag("msubsup", [$$[$0-4], $$[$0-2], $$[$0]]); - -break; -case 164: - - this.$ = newTag("msubsup", [$$[$0-3], $$[$0-1], newMo($$[$0])]); - -break; -case 165: - - this.$ = newTag("msubsup", [$$[$0-4], $$[$0], $$[$0-2]]); - -break; -case 166: - - this.$ = newTag("msubsup", [$$[$0-3], $$[$0], newMo($$[$0-2])]); - -break; -case 167: - - this.$ = newTag("msub", [$$[$0-2], $$[$0]]); - -break; -case 168: - - this.$ = newTag("msup", [$$[$0-2], $$[$0]]); - -break; -case 169: - - this.$ = newTag("msup", [$$[$0-1], newMo($$[$0])]); - -break; -case 171: - - this.$ = newTag("munderover", [$$[$0-4], $$[$0-2], $$[$0]]); - -break; -case 172: - - this.$ = newTag("munderover", [$$[$0-4], $$[$0], $$[$0-2]]); - -break; -case 173: - - this.$ = newTag("munder", [$$[$0-2], $$[$0]]); - -break; -case 174: - - this.$ = newTag("mover", [$$[$0-2], $$[$0]]); - -break; -case 178: case 200: case 204: - this.$ = [$$[$0]]; -break; -case 179: - this.$ = $$[$0-1].concat([$$[$0]]); -break; -case 182: - this.$ = [$$[$0-2], $$[$0]]; -break; -case 183: - this.$ = [$$[$0], newTag("none")]; -break; -case 184: case 185: - this.$ = [newTag("none"), $$[$0]]; -break; -case 187: - this.$ = $$[$0-1].concat($$[$0]); -break; -case 188: - this.$ = {"displaystyle": "true"}; -break; -case 189: - this.$ = {"displaystyle": "false"}; -break; -case 190: - this.$ = {"scriptlevel": "0"}; -break; -case 191: - this.$ = {"scriptlevel": "1"}; -break; -case 192: - this.$ = {"scriptlevel": "2"}; -break; -case 193: - this.$ = {"mathcolor": $$[$0]}; -break; -case 194: - this.$ = {"mathbackground": $$[$0]}; -break; -case 195: - this.$ = [newMrow($$[$0], "mstyle", $$[$0-1])]; -break; -case 197: - this.$ = newTag("mtd", []); -break; -case 198: - - this.$ = newMrow($$[$0], "mtd", $$[$0-2]); - -break; -case 199: - this.$ = newMrow($$[$0], "mtd"); -break; -case 201: case 205: - this.$ = $$[$0-2].concat([$$[$0]]); -break; -case 202: - - this.$ = this.$ = newTag("mtr", $$[$0], $$[$0-2]); - -break; -case 203: - this.$ = newTag("mtr", $$[$0]); -break; -case 206: - - this.$ = $$[$0-1] - return this.$; - -break; -case 208: - this.$ = $$[$0-1] + $$[$0] -break; -case 210: - - this.$ = serializeTree($$[$0]); - -break; -case 211: - - // \( \) - this.$ = newMath([newTag("mrow")], false, false, yy.tex); - -break; -case 212: - - // \( ... \) - this.$ = newMath($$[$0-1], false, false, yy.tex); - -break; -case 213: - - // \[ \] - this.$ = newMath([newTag("mrow")], true, false, yy.tex); - -break; -case 214: - - // \[ ... \] - this.$ = newMath($$[$0-1], true, false, yy.tex); - -break; -case 215: - - // $ ... $ - this.$ = newMath($$[$0-1], false, false, yy.tex); - -break; -case 216: - - // this.$ ... this.$ - this.$ = newMath($$[$0-1], true, false, yy.tex); - -break; -} -}, -table: [{68:$V0,193:1,194:2,196:3,197:5,198:$V1,200:$V2,202:$V3,204:$V4},{1:[3]},{68:$V0,195:[1,10],196:11,197:5,198:$V1,200:$V2,202:$V3,204:$V4},o($V5,[2,207]),o($V5,[2,209]),o($V5,[2,210]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:13,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,199:[1,12]},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:126,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,201:[1,125]},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:127,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:128,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{1:[2,206]},o($V5,[2,208]),o($V5,[2,211]),{199:[1,129]},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:130,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},o($VL1,[2,196],{54:25,172:26,48:36,168:131,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1}),o($VM1,[2,188]),o($VM1,[2,189]),o($VM1,[2,190]),o($VM1,[2,191]),o($VM1,[2,192]),{7:133,8:$VN1,14:132},{7:133,8:$VN1,14:135},o($VO1,[2,178]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:136,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VO1,[2,170],{169:[1,138],170:[1,139],171:[1,140]}),o($VO1,[2,175],{169:[1,141],170:[1,142]}),{8:$V6,10:[1,143],48:36,49:$V7,50:$V8,51:$V9,54:25,55:144,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{50:[1,145]},{50:[1,146]},{50:[1,147]},{50:[1,148]},{50:[1,149]},{50:[1,150]},{50:[1,151]},{50:[1,152]},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:153,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},o($VQ1,[2,65]),o($VQ1,[2,66]),o($VQ1,[2,67]),o($VQ1,[2,68]),o($VQ1,[2,69]),o($VQ1,[2,70]),o($VQ1,[2,71]),o($VQ1,[2,72]),{7:155,8:$VN1,15:154},{7:155,8:$VN1,15:156},{7:155,8:$VN1,15:157},o($VQ1,[2,76]),o($VQ1,[2,77]),o($VQ1,[2,78]),o($VQ1,[2,79]),o($VQ1,[2,80]),{3:160,4:$VR1,7:155,8:$VN1,13:159,15:158},{7:155,8:$VN1,15:162},{84:[1,163]},o($VQ1,[2,85]),{7:164,8:$VN1},{7:165,8:$VN1},{7:166,8:$VN1},{7:167,8:$VN1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:168,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:169,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{4:[1,171],8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:170,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:172,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:173,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:174,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{4:[1,175],8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:176,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:177,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:178,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:179,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:180,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:181,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:182,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:183,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:184,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:185,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:186,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:187,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:188,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:189,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:190,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:191,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,114]),o($VQ1,[2,115]),o($VQ1,[2,116]),o($VQ1,[2,117]),o($VQ1,[2,118]),o($VQ1,[2,119]),o($VQ1,[2,120]),o($VQ1,[2,121]),{7:192,8:$VN1},{8:[1,194],12:193},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:195,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:196,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:197,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:198,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:199,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:200,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:201,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:202,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:203,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:204,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{7:133,8:$VN1,14:205},{7:206,8:$VN1},{7:207,8:$VN1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:208,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:210,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,137:209,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:[1,211]},o([144,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,143:212,190:213,188:215,186:216,55:218,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([146,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:219,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([148,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:220,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([150,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:221,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([152,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:222,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([154,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:223,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([156,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:224,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([158,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:225,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([160,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:226,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o([162,189,192],$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:227,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),{3:230,4:$VR1,7:231,8:$VN1,16:228,17:229},{8:[1,232]},{8:[1,233]},o($VV1,[2,176]),o($VV1,[2,177]),{50:[1,234],51:[1,235]},o($V5,[2,213]),{201:[1,236]},{203:[1,237]},{205:[1,238]},o($V5,[2,212]),o($VL1,[2,195]),o($VO1,[2,179]),o($VM1,[2,193]),o([8,10,19,21,23,25,27,29,31,33,35,37,39,41,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,145,147,149,151,153,155,157,159,161,163,165,166,173,174,179,180,181,182,183,184,185],[2,6]),{9:[1,239]},o($VM1,[2,194]),{8:$VW1,140:240,169:$VX1,170:$VY1,177:242},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:245,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:246,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:247,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VO1,[2,169],{169:[1,248]}),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:249,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:250,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,48]),{10:[1,251],64:[1,252],65:[1,253],66:[1,254]},o($VQ1,[2,50]),o($VQ1,[2,51]),o($VQ1,[2,52]),o($VQ1,[2,53]),o($VQ1,[2,54]),o($VQ1,[2,55]),o($VQ1,[2,56]),o($VQ1,[2,57]),{52:255,53:$VZ1,64:[1,256],65:[1,257],66:[1,258]},o($VQ1,[2,73]),o($VQ1,[2,7]),o($VQ1,[2,74]),o($VQ1,[2,75]),o($VQ1,[2,81]),{3:160,4:$VR1,13:260},o($V_1,[2,5]),{5:[1,261]},o($VQ1,[2,83]),o($VQ1,[2,84]),o($VQ1,[2,86]),o($VQ1,[2,87]),o($VQ1,[2,88]),o($VQ1,[2,89]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:262,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:263,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,92]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:264,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:265,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:266,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:267,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:268,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},o($VQ1,[2,98]),o($VQ1,[2,99]),o($VQ1,[2,100]),o($VQ1,[2,101]),o($VQ1,[2,102]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:269,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:270,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:271,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,106]),o($VQ1,[2,107]),o($VQ1,[2,108]),o($VQ1,[2,109]),o($VQ1,[2,110]),o($VQ1,[2,111]),o($VQ1,[2,112]),o($VQ1,[2,113]),{7:272,8:$VN1},{4:$V$1,8:$V6,11:273,48:36,49:$V7,50:$V8,51:$V9,54:274,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{9:[1,276]},o($VQ1,[2,126]),o($VQ1,[2,127]),o($VQ1,[2,128]),o($VQ1,[2,129]),o($VQ1,[2,130]),o($VQ1,[2,131]),o($VQ1,[2,132]),o($VQ1,[2,133]),o($VQ1,[2,134]),o($VQ1,[2,135]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:277,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:278,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:279,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:280,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:282,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,138:[1,281],139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($V02,[2,160]),{10:[1,284],140:283,169:$VX1,170:$VY1,177:242},{144:[1,285],192:$V12},o($V22,[2,204]),{8:[1,287]},o($V22,[2,203],{189:$V32}),o($V42,[2,200]),{8:[1,289]},o($V42,[2,199]),{146:[1,290],192:$V12},{148:[1,291],192:$V12},{150:[1,292],192:$V12},{152:[1,293],192:$V12},{154:[1,294],192:$V12},{156:[1,295],192:$V12},{158:[1,296],192:$V12},{160:[1,297],192:$V12},{162:[1,298],192:$V12},{7:231,8:$VN1,17:299},o($V52,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:300,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),{8:[2,8]},o([8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,145,147,149,151,153,155,157,159,161,163,164,165,166,173,174,179,180,181,182,183,184,185,187,189,191,192],[2,9]),o($V62,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:301,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o($V62,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:302,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,167:[1,303],173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o($VM1,[2,44]),o($VM1,[2,45]),o($V5,[2,214]),o($V5,[2,215]),o($V5,[2,216]),{10:[1,304]},o($VO1,[2,162],{177:305,169:$VX1,170:$VY1}),{140:306,169:$VX1,170:$VY1,177:242},o($VV1,[2,186]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:309,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,170:[1,308],172:310,173:$VC1,174:$VD1,176:307},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:309,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,172:310,173:$VC1,174:$VD1,176:311},{8:$VW1},o($VO1,[2,167],{170:[1,312],171:[1,313]}),o($VO1,[2,168],{169:[1,314]}),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:315,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VO1,[2,173],{170:[1,316]}),o($VO1,[2,174],{169:[1,317]}),o($VQ1,[2,49]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:318,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:319,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:320,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},o($VQ1,[2,58]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:321,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:322,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:323,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},{50:[1,324],51:[1,325]},{7:155,8:$VN1,15:326},{6:[1,327]},o($VQ1,[2,90]),o($VQ1,[2,91]),{6:[1,328]},o($VQ1,[2,94]),o($VQ1,[2,95]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:329,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{6:[1,330]},o($VQ1,[2,103]),o($VQ1,[2,104]),o($VQ1,[2,105]),{7:331,8:$VN1},{4:$V$1,8:$V6,11:332,48:36,49:$V7,50:$V8,51:$V9,54:333,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,125]),{5:[1,334]},{10:[1,335]},o($VQ1,[2,136]),o($VQ1,[2,137]),o($VQ1,[2,138]),o($VQ1,[2,139]),o($VQ1,[2,140]),o($V02,[2,161]),{10:[1,336],169:$VX1,170:$VY1,177:305},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:337,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,145]),o($V42,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,188:215,186:216,55:218,190:338,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),{20:341,21:$V72,22:342,23:$V82,44:340,47:339},o($V42,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,55:218,186:345,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1}),{20:348,21:$V72,22:349,23:$V82,24:350,25:$V92,26:351,27:$Va2,42:347,43:346},o($VQ1,[2,146]),o($VQ1,[2,147]),o($VQ1,[2,148]),o($VQ1,[2,149]),o($VQ1,[2,150]),o($VQ1,[2,151]),o($VQ1,[2,152]),o($VQ1,[2,153]),o($VQ1,[2,154]),o($V52,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:354,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),{164:[1,355],192:$V12},{10:[1,356],192:$V12},{10:[1,357],192:$V12},{8:[1,358]},o([6,8,10,19,21,23,25,27,29,31,33,35,37,39,41,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,169,170,171,173,174,179,180,181,182,183,184,185,187,189,191,192,199,201,203,205],[2,2]),o($VV1,[2,187]),{10:[1,359],169:$VX1,170:$VY1,177:305},o([6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,169,173,174,189,192,199,201,203,205],[2,183],{170:[1,360]}),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:309,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,172:310,173:$VC1,174:$VD1,176:361},o($VV1,[2,180]),o($VV1,[2,181]),o($VV1,[2,184]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:362,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VO1,[2,164]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:363,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VO1,[2,166]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:364,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:365,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{10:[1,366]},{10:[1,367]},{10:[1,368]},{52:369,53:$VZ1},{52:370,53:$VZ1},{52:371,53:$VZ1},o($VQ1,[2,46]),o($VQ1,[2,47]),o($VQ1,[2,82]),o($V_1,[2,1]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:372,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,96]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:373,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,122]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:374,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},o($VQ1,[2,124]),{6:[1,375]},o($Vb2,[2,4]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:376,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1},{8:[1,377]},o($V22,[2,205]),{10:[1,378],20:341,21:$V72,22:342,23:$V82,44:379},o($Vc2,[2,42]),o($Vc2,[2,28]),o($Vc2,[2,29]),{7:133,8:$VN1,14:380},{7:133,8:$VN1,14:381},o($V42,[2,201]),{10:[1,382],20:348,21:$V72,22:349,23:$V82,24:350,25:$V92,26:351,27:$Va2,42:383},o($Vd2,[2,26]),o($Vd2,[2,22]),o($Vd2,[2,23]),o($Vd2,[2,24]),o($Vd2,[2,25]),{7:133,8:$VN1,14:384},{7:133,8:$VN1,14:385},{164:[1,386],192:$V12},o($VQ1,[2,156]),o($VQ1,[2,157]),o($VQ1,[2,158]),{18:389,19:$Ve2,20:390,21:$V72,22:391,23:$V82,28:392,29:$Vf2,30:393,31:$Vg2,32:394,33:$Vh2,34:395,35:$Vi2,36:396,37:$Vj2,38:397,39:$Vk2,40:398,41:$Vl2,45:388,46:387},o($VQ1,[2,141]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:309,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$VP1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,172:310,173:$VC1,174:$VD1,176:407},o($VV1,[2,185]),o($VO1,[2,163]),o($VO1,[2,165]),o($VO1,[2,171]),o($VO1,[2,172]),o($VQ1,[2,59]),o($VQ1,[2,61]),o($VQ1,[2,63]),o($VQ1,[2,60]),o($VQ1,[2,62]),o($VQ1,[2,64]),o($VQ1,[2,93]),o($VQ1,[2,97]),o($VQ1,[2,123]),o($Vb2,[2,3]),{8:[1,408]},{140:409,169:$VX1,170:$VY1,177:242},o($V42,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,186:216,55:218,188:410,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1}),o($Vc2,[2,43]),o($Vm2,[2,11]),o($Vm2,[2,12]),{8:$V6,48:36,49:$V7,50:$V8,51:$V9,54:25,55:411,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,168:23,172:26,173:$VC1,174:$VD1,175:15,178:14,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1},o($Vd2,[2,27]),o($Vd2,[2,13]),o($Vd2,[2,14]),o($VQ1,[2,155]),{10:[1,412],18:389,19:$Ve2,20:390,21:$V72,22:391,23:$V82,28:392,29:$Vf2,30:393,31:$Vg2,32:394,33:$Vh2,34:395,35:$Vi2,36:396,37:$Vj2,38:397,39:$Vk2,40:398,41:$Vl2,45:413},o($Vn2,[2,40]),o($Vn2,[2,30]),o($Vn2,[2,31]),o($Vn2,[2,32]),o($Vn2,[2,33]),o($Vn2,[2,34]),o($Vn2,[2,35]),o($Vn2,[2,36]),o($Vn2,[2,37]),o($Vn2,[2,38]),o($Vn2,[2,39]),{7:133,8:$VN1,14:414},{7:133,8:$VN1,14:415},{7:133,8:$VN1,14:416},{7:133,8:$VN1,14:417},{7:133,8:$VN1,14:418},{7:133,8:$VN1,14:419},{7:133,8:$VN1,14:420},{7:133,8:$VN1,14:421},o($VV1,[2,182]),{10:[1,423],140:422,169:$VX1,170:$VY1,177:242},{10:[1,424],169:$VX1,170:$VY1,177:305},o($V22,[2,202],{189:$V32}),o($V42,[2,198]),o($V62,$VS1,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:425,8:$V6,49:$V7,50:$V8,51:$V9,56:$Va,57:$Vb,58:$Vc,59:$Vd,60:$Ve,61:$Vf,62:$Vg,63:$Vh,67:$Vi,68:$Vj,69:$Vk,70:$Vl,71:$Vm,72:$Vn,73:$Vo,74:$Vp,75:$Vq,76:$Vr,77:$Vs,78:$Vt,79:$Vu,80:$Vv,81:$Vw,82:$Vx,83:$Vy,85:$Vz,86:$VA,87:$VB,88:$VC,89:$VD,90:$VE,91:$VF,92:$VG,93:$VH,94:$VI,95:$VJ,96:$VK,97:$VL,98:$VM,99:$VN,100:$VO,101:$VP,102:$VQ,103:$VR,104:$VS,105:$VT,106:$VU,107:$VV,108:$VW,109:$VX,110:$VY,111:$VZ,112:$V_,113:$V$,114:$V01,115:$V11,116:$V21,117:$V31,118:$V41,119:$V51,120:$V61,121:$V71,122:$V81,123:$V91,124:$Va1,125:$Vb1,126:$Vc1,127:$Vd1,128:$Ve1,129:$Vf1,130:$Vg1,131:$Vh1,132:$Vi1,133:$Vj1,134:$Vk1,135:$Vl1,136:$Vm1,139:$Vn1,141:$Vo1,142:$Vp1,145:$Vq1,147:$Vr1,149:$Vs1,151:$Vt1,153:$Vu1,155:$Vv1,157:$Vw1,159:$Vx1,161:$Vy1,163:$Vz1,165:$VA1,166:$VB1,173:$VC1,174:$VD1,179:$VE1,180:$VF1,181:$VG1,182:$VH1,183:$VI1,184:$VJ1,185:$VK1,187:$VT1,191:$VU1}),o($Vn2,[2,41]),o($Vn2,[2,10]),o($Vn2,[2,15]),o($Vn2,[2,16]),o($Vn2,[2,17]),o($Vn2,[2,18]),o($Vn2,[2,19]),o($Vn2,[2,20]),o($Vn2,[2,21]),{10:[1,426],169:$VX1,170:$VY1,177:305},o($VQ1,[2,143]),o($VQ1,[2,144]),{10:[1,427],192:$V12},o($VQ1,[2,142]),o($VQ1,[2,159])], -defaultActions: {10:[2,206],230:[2,8]}, -parseError: function parseError (str, hash) { - if (hash.recoverable) { - this.trace(str); - } else { - var error = new Error(str); - error.hash = hash; - throw error; - } -}, -parse: function parse(input) { - var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; - var args = lstack.slice.call(arguments, 1); - var lexer = Object.create(this.lexer); - var sharedState = { yy: {} }; - for (var k in this.yy) { - if (Object.prototype.hasOwnProperty.call(this.yy, k)) { - sharedState.yy[k] = this.yy[k]; - } - } - lexer.setInput(input, sharedState.yy); - sharedState.yy.lexer = lexer; - sharedState.yy.parser = this; - if (typeof lexer.yylloc == 'undefined') { - lexer.yylloc = {}; - } - var yyloc = lexer.yylloc; - lstack.push(yyloc); - var ranges = lexer.options && lexer.options.ranges; - if (typeof sharedState.yy.parseError === 'function') { - this.parseError = sharedState.yy.parseError; - } else { - this.parseError = Object.getPrototypeOf(this).parseError; - } - function popStack(n) { - stack.length = stack.length - 2 * n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - _token_stack: - var lex = function () { - var token; - token = lexer.lex() || EOF; - if (typeof token !== 'number') { - token = self.symbols_[token] || token; - } - return token; - }; - var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == 'undefined') { - symbol = lex(); - } - action = table[state] && table[state][symbol]; - } - if (typeof action === 'undefined' || !action.length || !action[0]) { - var errStr = ''; - expected = []; - for (p in table[state]) { - if (this.terminals_[p] && p > TERROR) { - expected.push('\'' + this.terminals_[p] + '\''); - } - } - if (lexer.showPosition) { - errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; - } else { - errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); - } - this.parseError(errStr, { - text: lexer.match, - token: this.terminals_[symbol] || symbol, - line: lexer.yylineno, - loc: yyloc, - expected: expected - }); - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(lexer.yytext); - lstack.push(lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = lexer.yyleng; - yytext = lexer.yytext; - yylineno = lexer.yylineno; - yyloc = lexer.yylloc; - if (recovering > 0) { - recovering--; - } - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = { - first_line: lstack[lstack.length - (len || 1)].first_line, - last_line: lstack[lstack.length - 1].last_line, - first_column: lstack[lstack.length - (len || 1)].first_column, - last_column: lstack[lstack.length - 1].last_column - }; - if (ranges) { - yyval._$.range = [ - lstack[lstack.length - (len || 1)].range[0], - lstack[lstack.length - 1].range[1] - ]; - } - r = this.performAction.apply(yyval, [ - yytext, - yyleng, - yylineno, - sharedState.yy, - action[1], - vstack, - lstack - ].concat(args)); - if (typeof r !== 'undefined') { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; -}}; - -var MathMLNameSpace = "http://www.w3.org/1998/Math/MathML", - SVGNameSpace = "http://www.w3.org/2000/svg", - TeXMimeTypes = ["TeX", "LaTeX", "text/x-tex", "text/x-latex", - "application/x-tex", "application/x-latex"]; - -function escapeText(aString) { - /* Escape reserved XML characters for use as text nodes. */ - return aString.replace(/&/g, "&").replace(//g, ">"); -} - -function escapeQuote(aString) { - /* Escape the double quote characters for use as attribute. */ - return aString.replace(/"/g, """); -} - -function namedSpaceToEm(aString) { - var index = [ - "negativeveryverythinmathspace", - "negativeverythinmathspace", - "negativemediummathspace", - "negativethickmathspace", - "negativeverythickmathspace", - "negativeveryverythickmathspace", - "", - "veryverythinmathspace", - "verythinmathspace", - "thinmathspace", - "mediummathspace", - "thickmathspace", - "verythickmathspace", - "veryverythickmathspace" - ].indexOf(aString); - return (index === -1 ? 0 : index - 6) / 18.0; -} - -function parseLength(aString) { - /* See http://www.w3.org/TR/MathML3/appendixa.html#parsing_length */ - aString = aString.trim(); - var lengthRegexp = /(-?[0-9]*(?:[0-9]\.?|\.[0-9])[0-9]*)(e[mx]|in|cm|mm|p[xtc]|%)?/, result = lengthRegexp.exec(aString); - if (result) { - result[1] = parseFloat(result[1]); - if (!result[2]) { - /* Unitless values are treated as a percent */ - result[1] *= 100; - result[2] = "%"; - } - return { l: result[1], u: result[2] }; - } - return { l: namedSpaceToEm(aString), u: "em" }; -} - -function serializeTree(aTree) { - var output = "<" + aTree["tag"]; - for (var name in aTree["attributes"]) { - if (aTree["attributes"][name] !== undefined) - output += " " + name + "=\"" + aTree["attributes"][name] + "\""; - } - if (aTree["content"]) { - output += ">"; - if (Array.isArray(aTree["content"])) { - aTree["content"].forEach(function(child) { - output += serializeTree(child); - }); - } else - output += aTree["content"]; - output += ""; - } else { - output += "/>"; - } - return output; -} - -function newTag(aTag, aChildren, aAttributes) { - return { - "tag": aTag, - "content": aChildren, - "attributes": aAttributes - }; -} - -function isEmptyMrow(aTree) { - return aTree["tag"] === "mrow" && !aTree["content"] && !aTree["attributes"]; -} - -function newMo(aContent, aLeftSpace, aRightSpace) { - return newTag("mo", escapeText(aContent), { - "lspace": aLeftSpace !== undefined ? aLeftSpace + "em" : undefined, - "rspace": aRightSpace !== undefined ? aRightSpace + "em" : undefined - }); -} - -function newMi(aContent, aNormal) { - return newTag("mi", escapeText(aContent), - aNormal ? { "mathvariant": "normal" } : undefined); -} - -function newSpace(aWidth) { - return newTag("mspace", null, {"width": aWidth + "em"}); -} - -function applyMathVariantToCharacter(codePoint, aMathVariant) { - // FIXME: We should have LaTeX commmands for all these variants. - // See https://github.com/fred-wang/TeXZilla/issues/64 - var mathvariant = [ - "bold", - "italic", - "bold-italic", - "script", - "bold-script", - "fraktur", - "double-struck", - "bold-fraktur", - "sans-serif", - "bold-sans-serif", - "sans-serif-italic", - "sans-serif-bold-italic", - "monospace", - "initial", - "tailed", - "looped", - "stretched" - ].indexOf(aMathVariant); - var Bold = 0; - var Italic = 1; - var BoldItalic = 2; - var Script = 3; - var BoldScript = 4; - var Fraktur = 5; - var DoubleStruck = 6; - var BoldFraktur = 7; - var SansSerif = 8; - var BoldSansSerif = 9; - var SansSerifItalic = 10; - var SansSerifBoldItalic = 11; - var Monospace = 12; - var Initial = 13; - var Tailed = 14; - var Looped = 15; - var Stretched = 16; - - var greekUpperTheta = 0x03F4; - var holeGreekUpperTheta = 0x03A2; - var nabla = 0x2207; - var partialDifferential = 0x2202; - var greekUpperAlpha = 0x0391; - var greekUpperOmega = 0x03A9; - var greekLowerAlpha = 0x03B1; - var greekLowerOmega = 0x03C9; - var greekLunateEpsilonSymbol = 0x03F5; - var greekThetaSymbol = 0x03D1; - var greekKappaSymbol = 0x03F0; - var greekPhiSymbol = 0x03D5; - var greekRhoSymbol = 0x03F1; - var greekPiSymbol = 0x03D6; - var greekLetterDigamma = 0x03DC; - var greekSmallLetterDigamma = 0x03DD; - var mathBoldCapitalDigamma = 0x1D7CA; - var mathBoldSmallDigamma = 0x1D7CB; - - var latinSmallLetterDotlessI = 0x0131; - var latinSmallLetterDotlessJ = 0x0237; - - var mathItalicSmallDotlessI = 0x1D6A4; - var mathItalicSmallDotlessJ = 0x1D6A5; - - var digit0 = 0x30; - var digit9 = 0x39; - var upperA = 0x41; - var upperZ = 0x5A; - var smallA = 0x61; - var smallZ = 0x7A; - - var mathBoldUpperA = 0x1D400; - var mathItalicUpperA = 0x1D434; - var mathBoldSmallA = 0x1D41A; - var mathBoldUpperAlpha = 0x1D6A8; - var mathBoldSmallAlpha = 0x1D6C2; - var mathItalicUpperAlpha = 0x1D6E2; - var mathBoldDigitZero = 0x1D7CE; - var mathDoubleStruckZero = 0x1D7D8; - - var mathBoldUpperTheta = 0x1D6B9; - var mathBoldNabla = 0x1D6C1; - var mathBoldPartialDifferential = 0x1D6DB; - var mathBoldEpsilonSymbol = 0x1D6DC; - var mathBoldThetaSymbol = 0x1D6DD; - var mathBoldKappaSymbol = 0x1D6DE; - var mathBoldPhiSymbol = 0x1D6DF; - var mathBoldRhoSymbol = 0x1D6E0; - var mathBoldPiSymbol = 0x1D6E1; - - /* Exceptional characters with at most one possible transformation. */ - if (codePoint == holeGreekUpperTheta) - return codePoint; - if (codePoint == greekLetterDigamma) { - if (mathvariant == Bold) - return mathBoldCapitalDigamma; - return codePoint; - } - if (codePoint == greekSmallLetterDigamma) { - if (mathvariant == Bold) - return mathBoldSmallDigamma; - return codePoint; - } - if (codePoint == latinSmallLetterDotlessI) { - if (mathvariant == Italic) - return mathItalicSmallDotlessI; - return codePoint; - } - if (codePoint == latinSmallLetterDotlessJ) { - if (mathvariant == Italic) - return mathItalicSmallDotlessJ; - return codePoint; - } - - var baseChar, multiplier, map; - - /* Latin */ - if (upperA <= codePoint && codePoint <= upperZ || - smallA <= codePoint && codePoint <= smallZ) { - baseChar = codePoint <= upperZ ? codePoint - upperA : - mathBoldSmallA - mathBoldUpperA + codePoint - smallA; - multiplier = mathvariant; - if (mathvariant > Monospace) - return codePoint; // Latin doesn't support the Arabic mathvariants - var transformedChar = baseChar + mathBoldUpperA + - multiplier * (mathItalicUpperA - mathBoldUpperA); - map = { - 0x1D455: 0x210E, - 0x1D49D: 0x212C, - 0x1D4A0: 0x2130, - 0x1D4A1: 0x2131, - 0x1D4A3: 0x210B, - 0x1D4A4: 0x2110, - 0x1D4A7: 0x2112, - 0x1D4A8: 0x2133, - 0x1D4AD: 0x211B, - 0x1D4BA: 0x212F, - 0x1D4BC: 0x210A, - 0x1D4C4: 0x2134, - 0x1D506: 0x212D, - 0x1D50B: 0x210C, - 0x1D50C: 0x2111, - 0x1D515: 0x211C, - 0x1D51D: 0x2128, - 0x1D53A: 0x2102, - 0x1D53F: 0x210D, - 0x1D545: 0x2115, - 0x1D547: 0x2119, - 0x1D548: 0x211A, - 0x1D549: 0x211D, - 0x1D551: 0x2124 - }; - return map[transformedChar] ? map[transformedChar] : transformedChar; - } - - /* Digits */ - if (digit0 <= codePoint && codePoint <= digit9) { - baseChar = codePoint - digit0; - switch (mathvariant) { - case Bold: - multiplier = 0; - break; - case DoubleStruck: - multiplier = 1; - break; - case SansSerif: - multiplier = 2; - break; - case BoldSansSerif: - multiplier = 3; - break; - case Monospace: - multiplier = 4; - break; - default: - return codePoint; - } - return baseChar + multiplier * (mathDoubleStruckZero - mathBoldDigitZero) + - mathBoldDigitZero; - } - - // Arabic characters are defined within this range - if (0x0600 <= codePoint && codePoint <= 0x06FF) { - // The Arabic mathematical block is not continuous, nor does it have a - // monotonic mapping to the unencoded characters, requiring the use of a - // lookup table. - switch (mathvariant) { - case Initial: - map = { - 0x628: 0x1EE21, - 0x62A: 0x1EE35, - 0x62B: 0x1EE36, - 0x62C: 0x1EE22, - 0x62D: 0x1EE27, - 0x62E: 0x1EE37, - 0x633: 0x1EE2E, - 0x634: 0x1EE34, - 0x635: 0x1EE31, - 0x636: 0x1EE39, - 0x639: 0x1EE2F, - 0x63A: 0x1EE3B, - 0x641: 0x1EE30, - 0x642: 0x1EE32, - 0x643: 0x1EE2A, - 0x644: 0x1EE2B, - 0x645: 0x1EE2C, - 0x646: 0x1EE2D, - 0x647: 0x1EE24, - 0x64A: 0x1EE29 - }; - break; - case Tailed: - map = { - 0x62C: 0x1EE42, - 0x62D: 0x1EE47, - 0x62E: 0x1EE57, - 0x633: 0x1EE4E, - 0x634: 0x1EE54, - 0x635: 0x1EE51, - 0x636: 0x1EE59, - 0x639: 0x1EE4F, - 0x63A: 0x1EE5B, - 0x642: 0x1EE52, - 0x644: 0x1EE4B, - 0x646: 0x1EE4D, - 0x64A: 0x1EE49, - 0x66F: 0x1EE5F, - 0x6BA: 0x1EE5D - }; - break; - case Stretched: - map = { - 0x628: 0x1EE61, - 0x62A: 0x1EE75, - 0x62B: 0x1EE76, - 0x62C: 0x1EE62, - 0x62D: 0x1EE67, - 0x62E: 0x1EE77, - 0x633: 0x1EE6E, - 0x634: 0x1EE74, - 0x635: 0x1EE71, - 0x636: 0x1EE79, - 0x637: 0x1EE68, - 0x638: 0x1EE7A, - 0x639: 0x1EE6F, - 0x63A: 0x1EE7B, - 0x641: 0x1EE70, - 0x642: 0x1EE72, - 0x643: 0x1EE6A, - 0x645: 0x1EE6C, - 0x646: 0x1EE6D, - 0x647: 0x1EE64, - 0x64A: 0x1EE69, - 0x66E: 0x1EE7C, - 0x6A1: 0x1EE7E - }; - break; - case Looped: - map = { - 0x627: 0x1EE80, - 0x628: 0x1EE81, - 0x62A: 0x1EE95, - 0x62B: 0x1EE96, - 0x62C: 0x1EE82, - 0x62D: 0x1EE87, - 0x62E: 0x1EE97, - 0x62F: 0x1EE83, - 0x630: 0x1EE98, - 0x631: 0x1EE93, - 0x632: 0x1EE86, - 0x633: 0x1EE8E, - 0x634: 0x1EE94, - 0x635: 0x1EE91, - 0x636: 0x1EE99, - 0x637: 0x1EE88, - 0x638: 0x1EE9A, - 0x639: 0x1EE8F, - 0x63A: 0x1EE9B, - 0x641: 0x1EE90, - 0x642: 0x1EE92, - 0x644: 0x1EE8B, - 0x645: 0x1EE8C, - 0x646: 0x1EE8D, - 0x647: 0x1EE84, - 0x648: 0x1EE85, - 0x64A: 0x1EE89 - }; - break; - case DoubleStruck: - map = { - 0x628: 0x1EEA1, - 0x62A: 0x1EEB5, - 0x62B: 0x1EEB6, - 0x62C: 0x1EEA2, - 0x62D: 0x1EEA7, - 0x62E: 0x1EEB7, - 0x62F: 0x1EEA3, - 0x630: 0x1EEB8, - 0x631: 0x1EEB3, - 0x632: 0x1EEA6, - 0x633: 0x1EEAE, - 0x634: 0x1EEB4, - 0x635: 0x1EEB1, - 0x636: 0x1EEB9, - 0x637: 0x1EEA8, - 0x638: 0x1EEBA, - 0x639: 0x1EEAF, - 0x63A: 0x1EEBB, - 0x641: 0x1EEB0, - 0x642: 0x1EEB2, - 0x644: 0x1EEAB, - 0x645: 0x1EEAC, - 0x646: 0x1EEAD, - 0x648: 0x1EEA5, - 0x64A: 0x1EEA9 - }; - break; - default: - return codePoint; - } - return map[codePoint] ? map[codePoint] : codePoint; - } - - // Greek - if (greekUpperAlpha <= codePoint && codePoint <= greekUpperOmega) { - baseChar = codePoint - greekUpperAlpha; - } else if (greekLowerAlpha <= codePoint && codePoint <= greekLowerOmega) { - baseChar = mathBoldSmallAlpha - mathBoldUpperAlpha + codePoint - greekLowerAlpha; - } else { - switch (codePoint) { - case greekUpperTheta: - baseChar = mathBoldUpperTheta - mathBoldUpperAlpha; - break; - case nabla: - baseChar = mathBoldNabla - mathBoldUpperAlpha; - break; - case partialDifferential: - baseChar = mathBoldPartialDifferential - mathBoldUpperAlpha; - break; - case greekLunateEpsilonSymbol: - baseChar = mathBoldEpsilonSymbol - mathBoldUpperAlpha; - break; - case greekThetaSymbol: - baseChar = mathBoldThetaSymbol - mathBoldUpperAlpha; - break; - case greekKappaSymbol: - baseChar = mathBoldKappaSymbol - mathBoldUpperAlpha; - break; - case greekPhiSymbol: - baseChar = mathBoldPhiSymbol - mathBoldUpperAlpha; - break; - case greekRhoSymbol: - baseChar = mathBoldRhoSymbol - mathBoldUpperAlpha; - break; - case greekPiSymbol: - baseChar = mathBoldPiSymbol - mathBoldUpperAlpha; - break; - default: - return codePoint; - } - } - - switch (mathvariant) { - case Bold: - multiplier = 0; - break; - case Italic: - multiplier = 1; - break; - case BoldItalic: - multiplier = 2; - break; - case BoldSansSerif: - multiplier = 3; - break; - case SansSerifBoldItalic: - multiplier = 4; - break; - default: - // This mathvariant isn't defined for Greek or is otherwise normal. - return codePoint; - } - - return baseChar + mathBoldUpperAlpha + multiplier * (mathItalicUpperAlpha - mathBoldUpperAlpha); -} - -function applyMathVariant(aToken, aMathVariant) { - if (aMathVariant === "normal") - return; - var content = aToken["content"]; - var transformedText = ""; - for (var i = 0; i < content.length; i++) { - var c = content["codePointAt"](i); - if (c > 0xFFFF) { - transformedText += content[i]; i++; - transformedText += content[i]; - } else { - transformedText += String["fromCodePoint"]( - applyMathVariantToCharacter(c, aMathVariant) - ); - } - } - aToken["content"] = transformedText; -} - -function isToken(aTree) { - return ["mi", "mn", "mo", "mtext", "ms"].indexOf(aTree["tag"]) !== -1; -} - -function isSingleCharMi(aTree) { - if (aTree["tag"] !== "mi") - return false; - var content = aTree["content"]; - var c = content["codePointAt"](0); - return content.length === 1 && c <= 0xFFFF || - content.length === 2 && c > 0xFFFF; -} - -function isTokenAttribute(aAttribute) { - return ["mathcolor", "mathbackground", "mathvariant"].indexOf(aAttribute) !== -1; -} - -function applyTokenAttributes(aChildren, aAttributes) { - var allAttributesAppliedToAllChildren = true; - for (var name in aAttributes) { - // Only consider mstyle attributes that apply to token elements. - if (!isTokenAttribute(name)) { - allAttributesAppliedToAllChildren = false; - continue; - } - // In general, keep mstyle element if there are multiple children. - if (name !== "mathvariant" && aChildren.length != 1) { - allAttributesAppliedToAllChildren = false; - continue; - } - aChildren.forEach(function(child) { - if (!isToken(child)) { - allAttributesAppliedToAllChildren = false; - return; - } - if (!child["attributes"]) - child["attributes"] = {}; - if (child["attributes"][name]) - return; - if (name === "mathvariant") { - // Transform the text instead of using a mathvariant attribute. - // Explicit "normal" attribute is only needed on single-char 's. - if (aAttributes[name] !== "normal" || !isSingleCharMi(child)) - applyMathVariant(child, aAttributes[name]) - else - child["attributes"][name] = aAttributes[name]; - } else { - // Apply the token attribute to the child. - child["attributes"][name] = aAttributes[name]; - } - }); - } - return allAttributesAppliedToAllChildren; -} - -/* FIXME: try to restore the operator grouping when compoundTermList does not - contain any fences. - https://github.com/fred-wang/TeXZilla/issues/9 */ -function newMrow(aChildren, aTag, aAttributes) { - aTag = aTag || "mrow"; - if (aTag === "mstyle") { - // Mstyle with one mrow child that does not have any attribute. - if (aChildren.length == 1 && - aChildren[0]["tag"] === "mrow" && !aChildren[0]["attributes"]) - return newMrow(aChildren[0]["content"], aTag, aAttributes); - - // Try an apply all the attributes to chidren and replace mstyle with mrow. - if (applyTokenAttributes(aChildren, aAttributes)) - return newMrow(aChildren); - } - // Mrow with one child and no attributes: return the child. - if (aChildren.length == 1 && aTag === "mrow" && !aAttributes) - return aChildren[0]; - return newTag(aTag, aChildren, aAttributes); -} - -function newMath(aChildren, aDisplay, aRTL, aTeX) -{ - return newTag("math", [ - newTag("semantics", [ - newMrow(aChildren), - newTag("annotation", escapeText(aTeX), {"encoding": "TeX"}) - ]) - ], { - "xmlns": MathMLNameSpace, - "display": aDisplay ? "block" : undefined, - "dir": aRTL ? "rtl" : undefined - }); -} - -function getTeXSourceInternal(aMathMLElement) { - var child; - if (!aMathMLElement || - aMathMLElement.namespaceURI !== MathMLNameSpace) { - return null; - } - - if (aMathMLElement.tagName === "semantics") { - // Note: we can't use aMathMLElement.children on WebKit/Blink because of - // https://bugs.webkit.org/show_bug.cgi?id=109556. - for (child = aMathMLElement.firstElementChild; child; - child = child.nextElementSibling) { - if (child.namespaceURI === MathMLNameSpace && - child.localName === "annotation" && - TeXMimeTypes.indexOf(child.getAttribute("encoding")) !== -1) { - return child.textContent; - } - } - } else if (aMathMLElement.childElementCount === 1) { - return getTeXSourceInternal(aMathMLElement.firstElementChild); - } - - return null; -} - -try { - // Try to create a DOM Parser object if it exists (e.g. in a Web page, - // in a chrome script running in a window etc) - parser.mDOMParser = new DOMParser(); -} catch (e) { - // Make the DOMParser throw an exception if used. - parser.mDOMParser = { - parseFromString: function() { - throw "DOMParser undefined. Did you call TeXZilla.setDOMParser?"; - } - }; -} - -parser.setDOMParser = function(aDOMParser) -{ - this.mDOMParser = aDOMParser; -} - -try { - // Try to create a XMLSerializer object if it exists (e.g. in a Web page, - // in a chrome script running in a window etc) - parser.mXMLSerializer = new XMLSerializer(); -} catch (e) { - // Make the XMLSerializer throw an exception if used. - parser.mXMLSerializer = { - serializeToString: function() { - throw "XMLSerializer undefined. Did you call TeXZilla.setXMLSerializer?"; - } - }; -} - -parser.setXMLSerializer = function(aXMLSerializer) -{ - this.mXMLSerializer = aXMLSerializer; -} - -parser.parseMathMLDocument = function (aString) { - // Parse the string into a MathML document and return the root. - return this.mDOMParser. - parseFromString(aString, "application/xml").documentElement; -} - -parser.setSafeMode = function(aEnable) -{ - this.yy.mSafeMode = aEnable; -} - -parser.setItexIdentifierMode = function(aEnable) -{ - this.yy.mItexIdentifierMode = aEnable; -} - -parser.getTeXSource = function(aMathMLElement) { - if (typeof aMathMLElement === "string") { - aMathMLElement = this.parseMathMLDocument(aMathMLElement); - } - - return getTeXSourceInternal(aMathMLElement); -} - -parser.toMathMLString = function(aTeX, aDisplay, aRTL, aThrowExceptionOnError) { - var output, mathml; - /* Parse the TeX source and get the main MathML node. */ - try { - output = this.parse("\\(" + aTeX + "\\)"); - if (aRTL) { - /* Set the RTL mode if specified. */ - output = output.replace(/^ element. */ - return this.parseMathMLDocument(this.toMathMLString(aTeX, aDisplay, aRTL, aThrowExceptionOnError)); -} - -function escapeHTML(aString) -{ - var rv = "", code1, code2; - for (var i = 0; i < aString.length; i++) { - var code1 = aString.charCodeAt(i); - if (code1 < 0x80) { - rv += aString.charAt(i); - continue; - } - if (0xD800 <= code1 && code1 <= 0xDBFF) { - i++; - code2 = aString.charCodeAt(i); - rv += "&#x" + - ((code1-0xD800)*0x400 + code2-0xDC00 + 0x10000).toString(16) + ";"; - continue; - } - rv += "&#x" + code1.toString(16) + ";"; - } - return rv; -} - -parser.toImage = function(aTeX, aRTL, aRoundToPowerOfTwo, aSize, aDocument) { - var math, el, box, svgWidth, svgHeight, svg, image; - - // Set default values. - if (aSize === undefined) { - aSize = 64; - } - if (aDocument === undefined) { - aDocument = window.document; - } - - // Create the MathML element. - math = this.toMathML(aTeX, true, aRTL); - math.setAttribute("mathsize", aSize + "px"); - - // Temporarily insert the MathML element in the document to measure it. - el = document.createElement("div"); - el.style.visibility = "hidden"; - el.style.position = "absolute"; - el.appendChild(math); - aDocument.body.appendChild(el); - box = math.getBoundingClientRect(); - aDocument.body.removeChild(el); - el.removeChild(math); - - // Round up the computed sizes. - if (aRoundToPowerOfTwo) { - // Harmony's Math.log2() is not supported by all rendering engines and is - // removed by closure-compiler, so we use Math.log() / Math.LN2 instead. - svgWidth = Math.pow(2, Math.ceil(Math.log(box.width) / Math.LN2)); - svgHeight = Math.pow(2, Math.ceil(Math.log(box.height) / Math.LN2)); - } else { - svgWidth = Math.ceil(box.width); - svgHeight = Math.ceil(box.height); - } - - // Embed the MathML in an SVG element. - svg = document.createElementNS(SVGNameSpace, "svg"); - svg.setAttribute("width", svgWidth + "px"); - svg.setAttribute("height", svgHeight + "px"); - el = document.createElementNS(SVGNameSpace, "g"); - el.setAttribute("transform", "translate(" + - (svgWidth - box.width) / 2.0 + "," + (svgHeight - box.height) / 2.0 + ")"); - svg.appendChild(el); - el = document.createElementNS(SVGNameSpace, "foreignObject"); - el.setAttribute("width", box.width); - el.setAttribute("height", box.height); - el.appendChild(math); - svg.firstChild.appendChild(el); - - // Create the image element. - image = new Image(); - image.src = "data:image/svg+xml;base64," + - window.btoa(escapeHTML(this.mXMLSerializer.serializeToString(svg))); - image.width = svgWidth; - image.height = svgHeight; - image.alt = escapeText(aTeX); - - return image; -} - -parser.filterString = function(aString, aThrowExceptionOnError) { - try { - return this.parse(aString); - } catch (e) { - if (aThrowExceptionOnError) { - throw e; - } - return aString; - } -} - -parser.filterElement = function(aElement, aThrowExceptionOnError) { - var root, child, node; - for (var node = aElement.firstChild; node; node = node.nextSibling) { - switch(node.nodeType) { - case 1: // Node.ELEMENT_NODE - this.filterElement(node, aThrowExceptionOnError); - break; - case 3: // Node.TEXT_NODE - this.yy.escapeXML = true; - root = this.mDOMParser.parseFromString("" + - TeXZilla.filterString(node.data, aThrowExceptionOnError) + - "", "application/xml").documentElement; - this.yy.escapeXML = false; - while (child = root.firstChild) { - aElement.insertBefore(root.removeChild(child), node); - } - child = node.previousSibling; - aElement.removeChild(node); node = child; - break; - default: - } - } -} - -function parseError(aString, aHash) { - // We delete the last line, which contains token names that are obscure - // to the users. See issue #16 - throw new Error(aString.replace(/\nExpecting [^\n]*$/, "\n")); -} - -/* generated by jison-lex 0.3.4 */ -var lexer = (function(){ -var lexer = ({ - -EOF:1, - -parseError:function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, - -// resets the lexer, sets new input -setInput:function (input, yy) { - this.yy = yy || this.yy || {}; - this._input = input; - this._more = this._backtrack = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = { - first_line: 1, - first_column: 0, - last_line: 1, - last_column: 0 - }; - if (this.options.ranges) { - this.yylloc.range = [0,0]; - } - this.offset = 0; - return this; - }, - -// consumes and returns one char from the input -input:function () { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) { - this.yylloc.range[1]++; - } - - this._input = this._input.slice(1); - return ch; - }, - -// unshifts one char (or a string) into the input -unput:function (ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length - len); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length - 1); - this.matched = this.matched.substr(0, this.matched.length - 1); - - if (lines.length - 1) { - this.yylineno -= lines.length - 1; - } - var r = this.yylloc.range; - - this.yylloc = { - first_line: this.yylloc.first_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.first_column, - last_column: lines ? - (lines.length === oldLines.length ? this.yylloc.first_column : 0) - + oldLines[oldLines.length - lines.length].length - lines[0].length : - this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - this.yyleng = this.yytext.length; - return this; - }, - -// When called from action, caches matched text and appends it on next action -more:function () { - this._more = true; - return this; - }, - -// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead. -reject:function () { - if (this.options.backtrack_lexer) { - this._backtrack = true; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - - } - return this; - }, - -// retain first n characters of the match -less:function (n) { - this.unput(this.match.slice(n)); - }, - -// displays already matched input, i.e. for error messages -pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, - -// displays upcoming input, i.e. for error messages -upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); - } - return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); - }, - -// displays the character position where the lexing error occurred, i.e. for error messages -showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c + "^"; - }, - -// test the lexed token: return FALSE when not a match, otherwise return token -test_match:function(match, indexed_rule) { - var token, - lines, - backup; - - if (this.options.backtrack_lexer) { - // save context - backup = { - yylineno: this.yylineno, - yylloc: { - first_line: this.yylloc.first_line, - last_line: this.last_line, - first_column: this.yylloc.first_column, - last_column: this.yylloc.last_column - }, - yytext: this.yytext, - match: this.match, - matches: this.matches, - matched: this.matched, - yyleng: this.yyleng, - offset: this.offset, - _more: this._more, - _input: this._input, - yy: this.yy, - conditionStack: this.conditionStack.slice(0), - done: this.done - }; - if (this.options.ranges) { - backup.yylloc.range = this.yylloc.range.slice(0); - } - } - - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno += lines.length; - } - this.yylloc = { - first_line: this.yylloc.last_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.last_column, - last_column: lines ? - lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : - this.yylloc.last_column + match[0].length - }; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._backtrack = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]); - if (this.done && this._input) { - this.done = false; - } - if (token) { - return token; - } else if (this._backtrack) { - // recover context - for (var k in backup) { - this[k] = backup[k]; - } - return false; // rule action called reject() implying the next rule should be tested instead. - } - return false; - }, - -// return next match in input -next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) { - this.done = true; - } - - var token, - match, - tempMatch, - index; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i = 0; i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (this.options.backtrack_lexer) { - token = this.test_match(tempMatch, rules[i]); - if (token !== false) { - return token; - } else if (this._backtrack) { - match = false; - continue; // rule action called reject() implying a rule MISmatch. - } else { - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - } else if (!this.options.flex) { - break; - } - } - } - if (match) { - token = this.test_match(match, rules[index]); - if (token !== false) { - return token; - } - // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace) - return false; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { - text: "", - token: null, - line: this.yylineno - }); - } - }, - -// return next match that has a token -lex:function lex () { - var r = this.next(); - if (r) { - return r; - } else { - return this.lex(); - } - }, - -// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack) -begin:function begin (condition) { - this.conditionStack.push(condition); - }, - -// pop the previously active lexer condition state off the condition stack -popState:function popState () { - var n = this.conditionStack.length - 1; - if (n > 0) { - return this.conditionStack.pop(); - } else { - return this.conditionStack[0]; - } - }, - -// produce the lexer rule set which is active for the currently active lexer condition state -_currentRules:function _currentRules () { - if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) { - return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; - } else { - return this.conditions["INITIAL"].rules; - } - }, - -// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available -topState:function topState (n) { - n = this.conditionStack.length - 1 - Math.abs(n || 0); - if (n >= 0) { - return this.conditionStack[n]; - } else { - return "INITIAL"; - } - }, - -// alias for begin(condition) -pushState:function pushState (condition) { - this.begin(condition); - }, - -// return the number of states currently on the stack -stateStackSize:function stateStackSize() { - return this.conditionStack.length; - }, -options: {}, -performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { -var YYSTATE=YY_START; -switch($avoiding_name_collisions) { -case 0: this.unput(yy_.yytext); this.pushState("DOCUMENT"); -break; -case 1: - this.pushState("MATH" + (0+!!yy.mItexIdentifierMode)); - yy.startMath = this.matched.length; - return "STARTMATH" + (2 * (yy_.yytext[0] == "$") + - (yy_.yytext[1] == "$" || yy_.yytext[1] == "[")); - -break; -case 2: this.popState(); return "EOF"; -break; -case 3: yy_.yytext = yy_.yytext[1]; return "TEXT"; -break; -case 4: - if (yy.escapeXML) { - yy_.yytext = escapeText(yy_.yytext); - } - return "TEXT"; - -break; -case 5:return "TEXT"; -break; -case 6: this.popState(); return "["; -break; -case 7: this.unput(yy_.yytext); this.popState(); this.popState(); -break; -case 8: return "TEXTOPTARG"; -break; -case 9: this.popState(); return "]"; -break; -case 10:return "{"; -break; -case 11:return "TEXTARG"; -break; -case 12: this.popState(); return "}"; -break; -case 13: this.popState(); return "]"; -break; -case 14:/* skip whitespace */ -break; -case 15: - this.popState(); - yy.endMath = this.matched.length - this.match.length; - yy.tex = this.matched.substring(yy.startMath, yy.endMath); - return "ENDMATH" + (2 * (yy_.yytext[0] == "$") + - (yy_.yytext[1] == "$" || yy_.yytext[1] == "]")); - -break; -case 16:return "{"; -break; -case 17:return "}"; -break; -case 18:return "^"; -break; -case 19:return "_"; -break; -case 20:return "."; -break; -case 21:return "COLSEP"; -break; -case 22:return "ROWSEP" -break; -case 23:return "NUM"; -break; -case 24: return "A"; -break; -case 25: yy_.yytext = "\u0396"; return "AIUG"; -break; -case 26: yy_.yytext = "\u03B6"; return "AILG"; -break; -case 27: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21CC"; return "XARROW"; -break; -case 28: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21D2"; return "XARROW"; -break; -case 29: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u2192"; return "XARROW"; -break; -case 30: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21A6"; return "XARROW"; -break; -case 31: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21CB"; return "XARROW"; -break; -case 32: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21D4"; return "XARROW"; -break; -case 33: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u2194"; return "XARROW"; -break; -case 34: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21D0"; return "XARROW"; -break; -case 35: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u2190"; return "XARROW"; -break; -case 36: yy_.yytext = "\u039E"; return "AIUG"; -break; -case 37: yy_.yytext = "\u03BE"; return "AILG"; -break; -case 38: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21AA"; return "XARROW"; -break; -case 39: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); yy_.yytext = "\u21A9"; return "XARROW"; -break; -case 40: yy_.yytext = "\u2240"; return "OP"; -break; -case 41: yy_.yytext = "\u2118"; return "A"; -break; -case 42: yy_.yytext = "\u21C0"; return "ACCENT"; -break; -case 43: yy_.yytext = "\u02DC"; return "ACCENT"; -break; -case 44: yy_.yytext = "\u005E"; return "ACCENT"; -break; -case 45: yy_.yytext = "\u02C7"; return "ACCENT"; -break; -case 46: yy_.yytext = "\u00AF"; return "ACCENT"; -break; -case 47: yy_.yytext = "\u2259"; return "OP"; -break; -case 48: yy_.yytext = "\u22C0"; return "OPM"; -break; -case 49: yy_.yytext = "\u2227"; return "OP"; -break; -case 50: yy_.yytext = "\u2980"; return "OPFS"; -break; -case 51: yy_.yytext = "\u22AA"; return "OP"; -break; -case 52: yy_.yytext = "\u2016"; return "OPFS"; -break; -case 53: yy_.yytext = "\u007C"; return "OPFS"; -break; -case 54: yy_.yytext = "\u22BB"; return "OP"; -break; -case 55: yy_.yytext = "\u22C1"; return "OPM"; -break; -case 56: yy_.yytext = "\u2228"; return "OP"; -break; -case 57: yy_.yytext = "\u21C0"; return "ACCENTNS"; -break; -case 58: yy_.yytext = "\u22EE"; return "OP"; -break; -case 59: yy_.yytext = "\u22AB"; return "OP"; -break; -case 60: yy_.yytext = "\u22A9"; return "OP"; -break; -case 61: yy_.yytext = "\u22A8"; return "OP"; -break; -case 62: yy_.yytext = "\u22A2"; return "OP"; -break; -case 63: yy_.yytext = "\u2AEB"; return "OP"; -break; -case 64: yy_.yytext = "\u22B3"; return "OP"; -break; -case 65: yy_.yytext = "\u22B2"; return "OP"; -break; -case 66: yy_.yytext = "\u25B5"; return "OP"; -break; -case 67: yy_.yytext = "\u03D1"; return "AILG"; -break; -case 68: yy_.yytext = "\u2ACC\uFE00"; return "OP"; -break; -case 69: yy_.yytext = "\u228B\uFE00"; return "OP"; -break; -case 70: yy_.yytext = "\u2ACB\uFE00"; return "OP"; -break; -case 71: yy_.yytext = "\u228A\uFE00"; return "OP"; -break; -case 72: yy_.yytext = "\u228A\uFE00"; return "OP"; -break; -case 73: yy_.yytext = "\u03C2"; return "A"; -break; -case 74: yy_.yytext = "\u03F1"; return "AILG"; -break; -case 75: yy_.yytext = "\u221D"; return "OP"; -break; -case 76: yy_.yytext = "\u03D6"; return "AILG"; -break; -case 77: yy_.yytext = "\u03C6"; return "AILG"; -break; -case 78: yy_.yytext = "\u2205"; return "A"; -break; -case 79: yy_.yytext = "\u03F0"; return "AILG"; -break; -case 80: yy_.yytext = "\u03B5"; return "AILG"; -break; -case 81: yy_.yytext = "\u290A"; return "OPS"; -break; -case 82: yy_.yytext = "\u21C8"; return "OPS"; -break; -case 83: yy_.yytext = "\u03D2"; return "A"; -break; -case 84: yy_.yytext = "\u03C5"; return "AILG"; -break; -case 85: yy_.yytext = "\u03D2"; return "A"; -break; -case 86: yy_.yytext = "\u228E"; return "OP"; -break; -case 87: yy_.yytext = "\u2A1B"; return "OP"; -break; -case 88: yy_.yytext = "\u21BF"; return "OPS"; -break; -case 89: yy_.yytext = "\u21BE"; return "OPS"; -break; -case 90: yy_.yytext = "\u21D5"; return "OPS"; -break; -case 91: yy_.yytext = "\u2195"; return "OPS"; -break; -case 92: yy_.yytext = "\u2195"; return "OPS"; -break; -case 93: yy_.yytext = "\u21D1"; return "OPS"; -break; -case 94: yy_.yytext = "\u2191"; return "OPS"; -break; -case 95: yy_.yytext = "\u2191"; return "OPS"; -break; -case 96: yy_.yytext = "\u22B5"; return "OP"; -break; -case 97: yy_.yytext = "\u22B4"; return "OP"; -break; -case 98: yy_.yytext = "\u22C3"; return "OPM"; -break; -case 99: yy_.yytext = "\u222A"; return "OP"; -break; -case 100:return "UNDERSET"; -break; -case 101:return "UNDEROVERSET"; -break; -case 102:return "UNDERLINE"; -break; -case 103:return "UNDERBRACE"; -break; -case 104: yy_.yytext = "\u22F0"; return "OP"; -break; -case 105:return "OP"; -break; -case 106:return "OP"; -break; -case 107:return "OP"; -break; -case 108:return "OP"; -break; -case 109:return "OP"; -break; -case 110:return "OP"; -break; -case 111:return "OP"; -break; -case 112:return "OP"; -break; -case 113:return "OP"; -break; -case 114:return "OP"; -break; -case 115:return "OP"; -break; -case 116:return "OP"; -break; -case 117:return "OP"; -break; -case 118:return "OP"; -break; -case 119:return "OP"; -break; -case 120:return "OP"; -break; -case 121:return "OP"; -break; -case 122:return "OP"; -break; -case 123:return "OP"; -break; -case 124:return "OP"; -break; -case 125:return "OP"; -break; -case 126:return "OP"; -break; -case 127:return "OP"; -break; -case 128:return "OP"; -break; -case 129:return "OP"; -break; -case 130:return "OP"; -break; -case 131:return "OP"; -break; -case 132:return "OP"; -break; -case 133:return "OP"; -break; -case 134:return "OP"; -break; -case 135:return "OP"; -break; -case 136:return "OP"; -break; -case 137:return "OP"; -break; -case 138:return "OPFS"; -break; -case 139:return "OPFS"; -break; -case 140:return "OP"; -break; -case 141:return "OP"; -break; -case 142:return "OP"; -break; -case 143:return "OP"; -break; -case 144:return "OP"; -break; -case 145:return "OP"; -break; -case 146:return "OP"; -break; -case 147:return "OP"; -break; -case 148:return "OP"; -break; -case 149:return "OP"; -break; -case 150:return "OP"; -break; -case 151:return "OP"; -break; -case 152:return "OP"; -break; -case 153:return "OP"; -break; -case 154:return "OP"; -break; -case 155:return "OP"; -break; -case 156:return "OP"; -break; -case 157:return "OP"; -break; -case 158:return "OP"; -break; -case 159:return "OP"; -break; -case 160:return "OP"; -break; -case 161: yy_.yytext = "\u2916"; return "OP"; -break; -case 162: yy_.yytext = "\u21A0"; return "OPS"; -break; -case 163: yy_.yytext = "\u219E"; return "OPS"; -break; -case 164: yy_.yytext = "\u222D"; return "OP"; -break; -case 165: yy_.yytext = "\u22B5"; return "OP"; -break; -case 166: yy_.yytext = "\u25B9"; return "OP"; -break; -case 167: yy_.yytext = "\u225C"; return "OP"; -break; -case 168: yy_.yytext = "\u22B4"; return "OP"; -break; -case 169: yy_.yytext = "\u25C3"; return "OP"; -break; -case 170: yy_.yytext = "\u25BF"; return "OP"; -break; -case 171: yy_.yytext = "\u25B5"; return "OP"; -break; -case 172: yy_.yytext = "\u292A"; return "OP"; -break; -case 173: yy_.yytext = "\u2929"; return "OP"; -break; -case 174: yy_.yytext = "\u22A4"; return "OP"; -break; -case 175: this.pushState("TEXTARG"); return "TOOLTIP"; -break; -case 176: yy_.yytext = "\u2927"; return "OP"; -break; -case 177: return "TOGGLE"; -break; -case 178: yy_.yytext = "\u2928"; return "OP"; -break; -case 179: yy_.yytext = "\u2192"; return "OPS"; -break; -case 180: yy_.yytext = "\u22A0"; return "OP"; -break; -case 181: yy_.yytext = "\u00D7"; return "OP"; -break; -case 182: yy_.yytext = "\u02DC"; return "ACCENTNS"; -break; -case 183:return "THINSPACE"; -break; -case 184:return "THICKSPACE"; -break; -case 185: yy_.yytext = "\u223C"; return "OP"; -break; -case 186: yy_.yytext = "\u2248"; return "OP"; -break; -case 187: yy_.yytext = "\u0398"; return "AIUG"; -break; -case 188: yy_.yytext = "\u03B8"; return "AILG"; -break; -case 189: yy_.yytext = "\u2234"; return "OP"; -break; -case 190:return "TFRAC"; -break; -case 191:return "TEXTSTYLE"; -break; -case 192:return "TEXTSIZE"; -break; -case 193: yy_.yytext = "\u201D"; return "OPF"; -break; -case 194: yy_.yytext = "\u201C"; return "OPF"; -break; -case 195: yy_.yytext = "\u007E"; return "OPS"; -break; -case 196: yy_.yytext = "\u0060"; return "OP"; -break; -case 197: yy_.yytext = "\u005E"; return "OPS"; -break; -case 198: yy_.yytext = "\u00B4"; return "OP"; -break; -case 199: this.begin("TEXTARG"); return "MTEXT"; -break; -case 200:return "TENSOR"; -break; -case 201:return "TBINOM"; -break; -case 202: yy_.yytext = "\u03A4"; return "AIUG"; -break; -case 203: yy_.yytext = "\u03C4"; return "AILG"; -break; -case 204: yy_.yytext = "\u21D9"; return "OPS"; -break; -case 205: yy_.yytext = "\u2199"; return "OPS"; -break; -case 206: yy_.yytext = "\u21D9"; return "OPS"; -break; -case 207: yy_.yytext = "\u2199"; return "OPS"; -break; -case 208: yy_.yytext = "\u221A"; return "OPS"; -break; -case 209: yy_.yytext = "\u2ACC"; return "OP"; -break; -case 210: yy_.yytext = "\u228B"; return "OP"; -break; -case 211: yy_.yytext = "\u2AC6"; return "OP"; -break; -case 212: yy_.yytext = "\u2287"; return "OP"; -break; -case 213: yy_.yytext = "\u22D1"; return "OP"; -break; -case 214: yy_.yytext = "\u2283"; return "OP"; -break; -case 215: yy_.yytext = "\u2211"; return "OPM"; -break; -case 216: yy_.yytext = "\u227F"; return "OP"; -break; -case 217: yy_.yytext = "\u22E9"; return "OP"; -break; -case 218: yy_.yytext = "\u2AB6"; return "OP"; -break; -case 219: yy_.yytext = "\u2ABA"; return "OP"; -break; -case 220: yy_.yytext = "\u2AB0"; return "OP"; -break; -case 221: yy_.yytext = "\u227D"; return "OP"; -break; -case 222: yy_.yytext = "\u2AB8"; return "OP"; -break; -case 223: yy_.yytext = "\u227B"; return "OP"; -break; -case 224:return "SUBSTACK"; -break; -case 225: yy_.yytext = "\u2ACB"; return "OP"; -break; -case 226: yy_.yytext = "\u228A"; return "OP"; -break; -case 227: yy_.yytext = "\u2AC5"; return "OP"; -break; -case 228: yy_.yytext = "\u2286"; return "OP"; -break; -case 229: yy_.yytext = "\u22D0"; return "OP"; -break; -case 230: yy_.yytext = "\u2282"; return "OP"; -break; -case 231: this.pushState("TEXTARG"); return "STATUSLINE"; -break; -case 232: yy_.yytext = "\u22C6"; return "OP"; -break; -case 233:return "OVERSET"; -break; -case 234: yy_.yytext = "\u2AFD"; return "OP"; -break; -case 235: yy_.yytext = "\u25A1"; return "OP"; -break; -case 236: yy_.yytext = "\u2292"; return "OP"; -break; -case 237: yy_.yytext = "\u2290"; return "OP"; -break; -case 238: yy_.yytext = "\u2291"; return "OP"; -break; -case 239: yy_.yytext = "\u228F"; return "OP"; -break; -case 240: this.pushState("OPTARG"); this.pushState("TRYOPTARG"); return "SQRT"; -break; -case 241: yy_.yytext = "\u2294"; return "OP"; -break; -case 242: yy_.yytext = "\u2293"; return "OP"; -break; -case 243: yy_.yytext = "\u2222"; return "OP"; -break; -case 244: yy_.yytext = "\u2660"; return "OP"; -break; -case 245: this.pushState("TEXTARG"); this.pushState("TEXTARG"); this.pushState("TEXTARG"); return "SPACE"; -break; -case 246: yy_.yytext = "\u2323"; return "OP"; -break; -case 247: yy_.yytext = "\u2323"; return "OP"; -break; -case 248: yy_.yytext = "\u2216"; return "OP"; -break; -case 249: yy_.yytext = "\u2322"; return "OP"; -break; -case 250:return "SLASH"; -break; -case 251: yy_.yytext = "\u2243"; return "OP"; -break; -case 252: yy_.yytext = "\u223C"; return "OP"; -break; -case 253: yy_.yytext = "\u03A3"; return "AIUG"; -break; -case 254: yy_.yytext = "\u03C3"; return "AILG"; -break; -case 255: yy_.yytext = "\u29E2"; return "OP"; -break; -case 256: yy_.yytext = "\u2225"; return "OP"; -break; -case 257: yy_.yytext = "\u2223"; return "OP"; -break; -case 258: yy_.yytext = "\u266F"; return "OP"; -break; -case 259: yy_.yytext = "\u2216"; return "OP"; -break; -case 260: yy_.yytext = "\u292D"; return "OP"; -break; -case 261: yy_.yytext = "\u21D8"; return "OPS"; -break; -case 262: yy_.yytext = "\u2198"; return "OPS"; -break; -case 263: yy_.yytext = "\u21D8"; return "OPS"; -break; -case 264: yy_.yytext = "\u2198"; return "OPS"; -break; -case 265:return "SCRIPTSIZE"; -break; -case 266:return "SCRIPTSCRIPTSIZE"; -break; -case 267: yy_.yytext = "\u22CA"; return "OP"; -break; -case 268: yy_.yytext = "\u21B1"; return "OPS"; -break; -case 269: yy_.yytext = "\u21DB"; return "OPS"; -break; -case 270: yy_.yytext = "\u27EB"; return "OPFS"; -break; -case 271: yy_.yytext = "\u2019"; return "OPF"; -break; -case 272: this.begin("TEXTARG"); return "ROWSPAN"; -break; -case 273:return "ROWOPTS"; -break; -case 274: this.pushState("TEXTARG"); return "ROWLINES"; -break; -case 275: this.begin("TEXTARG"); return "ROWALIGN"; -break; -case 276:return "ROOT"; -break; -case 277: yy_.yytext = "\u23B1"; return "OP"; -break; -case 278: yy_.yytext = "\u2253"; return "OP"; -break; -case 279: yy_.yytext = "\u27F2"; return "OP"; -break; -case 280: yy_.yytext = "\u22CC"; return "OP"; -break; -case 281: yy_.yytext = "\u219D"; return "OPS"; -break; -case 282: yy_.yytext = "\u21C9"; return "OPS"; -break; -case 283: yy_.yytext = "\u21CC"; return "OPS"; -break; -case 284: yy_.yytext = "\u21C4"; return "OPS"; -break; -case 285: yy_.yytext = "\u21C0"; return "OPS"; -break; -case 286: yy_.yytext = "\u21C1"; return "OPS"; -break; -case 287: yy_.yytext = "\u21FE"; return "OPS"; -break; -case 288: yy_.yytext = "\u21A3"; return "OPS"; -break; -case 289: yy_.yytext = "\u21D2"; return "OPS"; -break; -case 290: yy_.yytext = "\u2192"; return "OPS"; -break; -case 291:return "RIGHT"; -break; -case 292: yy_.yytext = "\u03A1"; return "AIUG"; -break; -case 293: yy_.yytext = "\u03C1"; return "AILG"; -break; -case 294: yy_.yytext = "\u22B3"; return "OP"; -break; -case 295: yy_.yytext = "\u230B"; return "OPFS"; -break; -case 296: yy_.yytext = "\u211C"; return "A"; -break; -case 297: yy_.yytext = "\u2930"; return "OP"; -break; -case 298: yy_.yytext = "\u292B"; return "OP"; -break; -case 299: yy_.yytext = "\u2309"; return "OPFS"; -break; -case 300: yy_.yytext = "\u005D"; return "OPFS"; -break; -case 301: yy_.yytext = "\u007D"; return "OPFS"; -break; -case 302: yy_.yytext = "\u27E9"; return "OPFS"; -break; -case 303: yy_.yytext = "\u27E9"; return "OPFS"; -break; -case 304: yy_.yytext = "\u225F"; return "OP"; -break; -case 305: yy_.yytext = "\u2A0C"; return "OP"; -break; -case 306:return "QUAD"; -break; -case 307:return "QQUAD"; -break; -case 308: yy_.yytext = "\u25AA"; return "OP"; -break; -case 309: yy_.yytext = "\u03A8"; return "AIUG"; -break; -case 310: yy_.yytext = "\u03C8"; return "AILG"; -break; -case 311: yy_.yytext = "\u221D"; return "OP"; -break; -case 312: yy_.yytext = "\u220F"; return "OPM"; -break; -case 313: yy_.yytext = "\u220F"; return "OPM"; -break; -case 314: yy_.yytext = "\u2032"; return "OPP"; -break; -case 315: yy_.yytext = "\u227E"; return "OP"; -break; -case 316: yy_.yytext = "\u22E8"; return "OP"; -break; -case 317: yy_.yytext = "\u2AB5"; return "OP"; -break; -case 318: yy_.yytext = "\u2AB9"; return "OP"; -break; -case 319: yy_.yytext = "\u2AAF"; return "OP"; -break; -case 320: yy_.yytext = "\u227C"; return "OP"; -break; -case 321: yy_.yytext = "\u2AB7"; return "OP"; -break; -case 322: yy_.yytext = "\u227A"; return "OP"; -break; -case 323:return "PMOD"; -break; -case 324: yy_.yytext = "\u00B1"; return "OP"; -break; -case 325: yy_.yytext = "\u2A25"; return "OP"; -break; -case 326: yy_.yytext = "\u229E"; return "OP"; -break; -case 327: yy_.yytext = "\u22D4"; return "OP"; -break; -case 328: yy_.yytext = "\u03A0"; return "AIUG"; -break; -case 329: yy_.yytext = "\u03C0"; return "AILG"; -break; -case 330: yy_.yytext = "\u03A6"; return "AIUG"; -break; -case 331: yy_.yytext = "\u03D5"; return "AILG"; -break; -case 332:return "PHANTOM"; -break; -case 333: yy_.yytext = "\u2AEB"; return "OP"; -break; -case 334: yy_.yytext = "\u22A5"; return "OP"; -break; -case 335: yy_.yytext = "\u2AA3"; return "OP"; -break; -case 336: yy_.yytext = "\u2202"; return "OP"; -break; -case 337: yy_.yytext = "\u214B"; return "OP"; -break; -case 338: yy_.yytext = "\u2225"; return "OP"; -break; -case 339: this.pushState("TEXTARG"); return "PADDING"; -break; -case 340:return "OVERSET"; -break; -case 341: yy_.yytext = "\u00AF"; return "ACCENT"; -break; -case 342:return "OVERBRACE"; -break; -case 343:return "TEXOVER"; -break; -case 344: yy_.yytext = "\u2A34"; return "OP"; -break; -case 345: yy_.yytext = "\u2297"; return "OP"; -break; -case 346: yy_.yytext = "\u2298"; return "OP"; -break; -case 347:return "OPS"; -break; -case 348:return "OPP"; -break; -case 349:return "OPM"; -break; -case 350: yy_.yytext = "\u2A2D"; return "OP"; -break; -case 351: yy_.yytext = "\u2295"; return "OP"; -break; -case 352:return "OPFS"; -break; -case 353:return "OPF"; -break; -case 354: this.begin("TEXTARG"); return "OPERATORNAME"; -break; -case 355:return "OP"; -break; -case 356: yy_.yytext = "\u2296"; return "OP"; -break; -case 357: yy_.yytext = "\u2134"; return "A"; -break; -case 358: yy_.yytext = "\u03A9"; return "AIUG"; -break; -case 359: yy_.yytext = "\u03C9"; return "AILG"; -break; -case 360: yy_.yytext = "\u222E"; return "OP"; -break; -case 361: yy_.yytext = "\u222F"; return "OP"; -break; -case 362: yy_.yytext = "\u2230"; return "OP"; -break; -case 363: yy_.yytext = "\u2299"; return "OP"; -break; -case 364: yy_.yytext = "\u229D"; return "OP"; -break; -case 365: yy_.yytext = "\u29B8"; return "OP"; -break; -case 366: yy_.yytext = "\u2932"; return "OP"; -break; -case 367: yy_.yytext = "\u21D6"; return "OPS"; -break; -case 368: yy_.yytext = "\u2196"; return "OPS"; -break; -case 369: yy_.yytext = "\u21D6"; return "OPS"; -break; -case 370: yy_.yytext = "\u2196"; return "OPS"; -break; -case 371: yy_.yytext = "\u22AF"; return "OP"; -break; -case 372: yy_.yytext = "\u22AE"; return "OP"; -break; -case 373: yy_.yytext = "\u22AD"; return "OP"; -break; -case 374: yy_.yytext = "\u22AC"; return "OP"; -break; -case 375:return "NUM"; -break; -case 376: yy_.yytext = "\u039D"; return "AIUG"; -break; -case 377: yy_.yytext = "\u03BD"; return "AILG"; -break; -case 378: yy_.yytext = "\u22ED"; return "OP"; -break; -case 379: yy_.yytext = "\u22EB"; return "OP"; -break; -case 380: yy_.yytext = "\u22EC"; return "OP"; -break; -case 381: yy_.yytext = "\u22EA"; return "OP"; -break; -case 382: yy_.yytext = "\u2289"; return "OP"; -break; -case 383: yy_.yytext = "\u2285"; return "OP"; -break; -case 384: yy_.yytext = "\u227F\u0338"; return "OP"; -break; -case 385: yy_.yytext = "\u2AB0\u0338"; return "OP"; -break; -case 386: yy_.yytext = "\u2281"; return "OP"; -break; -case 387: yy_.yytext = "\u2288"; return "OP"; -break; -case 388: yy_.yytext = "\u2288"; return "OP"; -break; -case 389: yy_.yytext = "\u2284"; return "OP"; -break; -case 390: yy_.yytext = "\u2244"; return "OP"; -break; -case 391: yy_.yytext = "\u2241"; return "OP"; -break; -case 392: yy_.yytext = "\u2226"; return "OP"; -break; -case 393: yy_.yytext = "\u2224"; return "OP"; -break; -case 394: yy_.yytext = "\u21CF"; return "OP"; -break; -case 395: yy_.yytext = "\u219B"; return "OP"; -break; -case 396: yy_.yytext = "\u2AAF\u0338"; return "OP"; -break; -case 397: yy_.yytext = "\u2280"; return "OP"; -break; -case 398: yy_.yytext = "\u2226"; return "OP"; -break; -case 399: yy_.yytext = "\u220C"; return "OP"; -break; -case 400: yy_.yytext = "\u2209"; return "OP"; -break; -case 401: yy_.yytext = "\u00AC"; return "OP"; -break; -case 402: yy_.yytext = "\u2224"; return "OP"; -break; -case 403: yy_.yytext = "\u226E"; return "OP"; -break; -case 404: yy_.yytext = "\u2A7D\u0338"; return "OP"; -break; -case 405: yy_.yytext = "\u2A7D\u0338"; return "OP"; -break; -case 406: yy_.yytext = "\u2270"; return "OP"; -break; -case 407: yy_.yytext = "\u21CE"; return "OP"; -break; -case 408: yy_.yytext = "\u21AE"; return "OP"; -break; -case 409: yy_.yytext = "\u21CD"; return "OP"; -break; -case 410: yy_.yytext = "\u219A"; return "OP"; -break; -case 411: yy_.yytext = "\u220B"; return "OP"; -break; -case 412: yy_.yytext = "\u226F"; return "OP"; -break; -case 413: yy_.yytext = "\u2A7E\u0338"; return "OP"; -break; -case 414: yy_.yytext = "\u2A7E\u0338"; return "OP"; -break; -case 415: yy_.yytext = "\u2271"; return "OP"; -break; -case 416: yy_.yytext = "\u2204"; return "OP"; -break; -case 417: yy_.yytext = "\u2262"; return "OP"; -break; -case 418: yy_.yytext = "\u2242\u0338"; return "OP"; -break; -case 419: yy_.yytext = "\u2260"; return "OP"; -break; -case 420: yy_.yytext = "\u292E"; return "OP"; -break; -case 421: yy_.yytext = "\u2931"; return "OP"; -break; -case 422:return "NEGTHICKSPACE"; -break; -case 423:return "NEGSPACE"; -break; -case 424:return "NEGMEDSPACE"; -break; -case 425: yy_.yytext = "\u00AC"; return "OP"; -break; -case 426: yy_.yytext = "\u21D7"; return "OPS"; -break; -case 427: yy_.yytext = "\u2197"; return "OPS"; -break; -case 428: yy_.yytext = "\u21D7"; return "OPS"; -break; -case 429: yy_.yytext = "\u2197"; return "OPS"; -break; -case 430: yy_.yytext = "\u2260"; return "OP"; -break; -case 431: yy_.yytext = "\u2247"; return "OP"; -break; -case 432: yy_.yytext = "\u224E\u0338"; return "OP"; -break; -case 433: yy_.yytext = "\u224F\u0338"; return "OP"; -break; -case 434: yy_.yytext = "\u266E"; return "OP"; -break; -case 435: yy_.yytext = "\u2249"; return "OP"; -break; -case 436: yy_.yytext = "\u2207"; return "OP"; -break; -case 437:return "MULTI"; -break; -case 438: yy_.yytext = "\u22B8"; return "OP"; -break; -case 439: yy_.yytext = "\u039C"; return "AIUG"; -break; -case 440: yy_.yytext = "\u03BC"; return "AILG"; -break; -case 441: this.begin("TEXTARG"); return "MTEXT"; -break; -case 442: this.pushState("TEXTARG"); this.pushState("TEXTOPTARG"); this.pushState("TRYOPTARG"); this.pushState("TEXTOPTARG"); this.pushState("TRYOPTARG"); return "MS"; -break; -case 443: yy_.yytext = "\u2213"; return "OP"; -break; -case 444: yy_.yytext = "\u22A7"; return "OP"; -break; -case 445: yy_.yytext = "mod"; return "MO"; -break; -case 446: this.pushState("TEXTARG"); return "MO"; -break; -case 447: this.pushState("TEXTARG"); return "MN"; -break; -case 448: yy_.yytext = "\u2ADB"; return "OP"; -break; -case 449: yy_.yytext = "\u2A2A"; return "OP"; -break; -case 450: yy_.yytext = "\u229F"; return "OP"; -break; -case 451: yy_.yytext = "\u2212"; return "OP"; -break; -case 452: yy_.yytext = yy_.yytext.slice(1); return "FM"; -break; -case 453: yy_.yytext = "\u2223"; return "OP"; -break; -case 454: this.pushState("TEXTARG"); return "MI"; -break; -case 455: yy_.yytext = "\u2127"; return "A"; -break; -case 456: yy_.yytext = "\u2127"; return "A"; -break; -case 457:return "MEDSPACE"; -break; -case 458: yy_.yytext = "\u2221"; return "OP"; -break; -case 459:return "MATHTT"; -break; -case 460:return "MATHSF"; -break; -case 461:return "MATHSCR"; -break; -case 462:return "MATHRM"; -break; -case 463:return "MATHRLAP"; -break; -case 464: this.begin("TEXTARG"); return "MATHREL"; -break; -case 465: this.pushState("TEXTOPTARG"); this.pushState("TRYOPTARG"); this.pushState("TEXTOPTARG"); this.pushState("TRYOPTARG"); this.pushState("TEXTARG"); return "MATHRAISEBOX"; -break; -case 466: this.begin("TEXTARG"); return "MATHOP"; -break; -case 467:return "MATHIT"; -break; -case 468:return "MATHLLAP"; -break; -case 469:return "MATHIT"; -break; -case 470:return "MATHFRAK"; -break; -case 471:return "MATHFRAK"; -break; -case 472:return "MATHCLAP"; -break; -case 473:return "MATHSCR"; -break; -case 474:return "MATHBSCR"; -break; -case 475:return "MATHBIT"; -break; -case 476: this.begin("TEXTARG"); return "MATHBIN"; -break; -case 477:return "MATHBF"; -break; -case 478:return "MATHBSCR"; -break; -case 479:return "MATHBB"; -break; -case 480: yy_.yytext = "\u2907"; return "OP"; -break; -case 481: yy_.yytext = "\u21A6"; return "OPS"; -break; -case 482: yy_.yytext = "\u2906"; return "OP"; -break; -case 483: yy_.yytext = "\u21A6"; return "OPS"; -break; -case 484: yy_.yytext = "\u2268\uFE00"; return "OP"; -break; -case 485: yy_.yytext = "\u2268\uFE00"; return "OP"; -break; -case 486: yy_.yytext = "\u22C9"; return "OP"; -break; -case 487: yy_.yytext = "\u003C"; return "OP"; -break; -case 488: yy_.yytext = "\u21B0"; return "OPS"; -break; -case 489: yy_.yytext = "\u2018"; return "OPF"; -break; -case 490: yy_.yytext = "\u25CA"; return "OP"; -break; -case 491: yy_.yytext = "\u2A1C"; return "OP"; -break; -case 492: yy_.yytext = "\u21AC"; return "OPS"; -break; -case 493: yy_.yytext = "\u21AB"; return "OPS"; -break; -case 494: yy_.yytext = "\u27F9"; return "OPS"; -break; -case 495: yy_.yytext = "\u27F6"; return "OPS"; -break; -case 496: yy_.yytext = "\u27FC"; return "OPS"; -break; -case 497: yy_.yytext = "\u27FA"; return "OPS"; -break; -case 498: yy_.yytext = "\u27F7"; return "OPS"; -break; -case 499: yy_.yytext = "\u27F8"; return "OPS"; -break; -case 500: yy_.yytext = "\u27F5"; return "OPS"; -break; -case 501: yy_.yytext = "\u22E6"; return "OP"; -break; -case 502: yy_.yytext = "\u2268"; return "OP"; -break; -case 503: yy_.yytext = "\u2A87"; return "OP"; -break; -case 504: yy_.yytext = "\u2A89"; return "OP"; -break; -case 505: yy_.yytext = "\u23B0"; return "OP"; -break; -case 506: yy_.yytext = "\u22D8"; return "OP"; -break; -case 507: yy_.yytext = "\u21DA"; return "OPS"; -break; -case 508: yy_.yytext = "\u27EA"; return "OPFS"; -break; -case 509: yy_.yytext = "\u226A"; return "OP"; -break; -case 510: yy_.yytext = "\u22B2"; return "OP"; -break; -case 511: yy_.yytext = "\u230A"; return "OPFS"; -break; -case 512: yy_.yytext = "\u2272"; return "OP"; -break; -case 513: yy_.yytext = "\u2276"; return "OP"; -break; -case 514: yy_.yytext = "\u2A8B"; return "OP"; -break; -case 515: yy_.yytext = "\u22DA"; return "OP"; -break; -case 516: yy_.yytext = "\u22D6"; return "OP"; -break; -case 517: yy_.yytext = "\u2A85"; return "OP"; -break; -case 518: yy_.yytext = "\u003C"; return "OP"; -break; -case 519: yy_.yytext = "\u2A7D"; return "OP"; -break; -case 520: yy_.yytext = "\u2266"; return "OP"; -break; -case 521: yy_.yytext = "\u2264"; return "OP"; -break; -case 522: yy_.yytext = "\u27F3"; return "OP"; -break; -case 523: yy_.yytext = "\u22CB"; return "OP"; -break; -case 524: yy_.yytext = "\u219C"; return "OPS"; -break; -case 525: yy_.yytext = "\u21AD"; return "OPS"; -break; -case 526: yy_.yytext = "\u21CB"; return "OPS"; -break; -case 527: yy_.yytext = "\u21FF"; return "OPS"; -break; -case 528: yy_.yytext = "\u21C6"; return "OPS"; -break; -case 529: yy_.yytext = "\u21D4"; return "OPS"; -break; -case 530: yy_.yytext = "\u2194"; return "OPS"; -break; -case 531: yy_.yytext = "\u21C7"; return "OPS"; -break; -case 532: yy_.yytext = "\u21BC"; return "OPS"; -break; -case 533: yy_.yytext = "\u21BD"; return "OPS"; -break; -case 534: yy_.yytext = "\u21FD"; return "OPS"; -break; -case 535: yy_.yytext = "\u21A2"; return "OPS"; -break; -case 536: yy_.yytext = "\u21D0"; return "OPS"; -break; -case 537: yy_.yytext = "\u2190"; return "OPS"; -break; -case 538:return "LEFT"; -break; -case 539: yy_.yytext = "\u2264"; return "OP"; -break; -case 540: yy_.yytext = "\u2026"; return "OP"; -break; -case 541: yy_.yytext = "\u2308"; return "OPFS"; -break; -case 542: yy_.yytext = "\u005B"; return "OPFS"; -break; -case 543: yy_.yytext = "\u007B"; return "OPFS"; -break; -case 544: yy_.yytext = "\u27E8"; return "OPFS"; -break; -case 545: yy_.yytext = "\u27E8"; return "OPFS"; -break; -case 546: yy_.yytext = "\u039B"; return "AIUG"; -break; -case 547: yy_.yytext = "\u03BB"; return "AILG"; -break; -case 548: yy_.yytext = "\u223B"; return "OP"; -break; -case 549: yy_.yytext = "\u039A"; return "AIUG"; -break; -case 550: yy_.yytext = "\u03BA"; return "AILG"; -break; -case 551: yy_.yytext = "\u0237"; return "AILL"; -break; -case 552: this.pushState("TEXTARG"); return "MN"; -break; -case 553: yy_.yytext = "\u0399"; return "AIUG"; -break; -case 554: yy_.yytext = "\u03B9"; return "AILG"; -break; -case 555: yy_.yytext = "\u214B"; return "OP"; -break; -case 556: yy_.yytext = "\u2A18"; return "OP"; -break; -case 557: yy_.yytext = "\u2A3D"; return "OP"; -break; -case 558: yy_.yytext = "\u2A3C"; return "OP"; -break; -case 559: yy_.yytext = "\u22C2"; return "OPM"; -break; -case 560: yy_.yytext = "\u2229"; return "OP"; -break; -case 561: yy_.yytext = "\u2AF4"; return "OP"; -break; -case 562: yy_.yytext = "\u22BA"; return "OP"; -break; -case 563: yy_.yytext = "\u222B"; return "OP"; -break; -case 564: yy_.yytext = "\u2A1A"; return "OP"; -break; -case 565: yy_.yytext = "\u2A19"; return "OP"; -break; -case 566: yy_.yytext = "\u2A0E"; return "OP"; -break; -case 567: yy_.yytext = "\u2A0D"; return "OP"; -break; -case 568: yy_.yytext = "\u222B"; return "OP"; -break; -case 569: yy_.yytext = "\u221E"; return "NUM"; -break; -case 570: yy_.yytext = "\u221E"; return "NUM"; -break; -case 571: yy_.yytext = yy_.yytext.slice(1); return "FM"; -break; -case 572: yy_.yytext = "\u220A"; return "OP"; -break; -case 573: yy_.yytext = "\u21D2"; return "OPS"; -break; -case 574: yy_.yytext = "\u21D0"; return "OPS"; -break; -case 575: yy_.yytext = "\u0131"; return "AILL"; -break; -case 576: yy_.yytext = "\u2111"; return "A"; -break; -case 577: yy_.yytext = "\u222C"; return "OP"; -break; -case 578: yy_.yytext = "\u222D"; return "OP"; -break; -case 579: yy_.yytext = "\u2A0C"; return "OP"; -break; -case 580: yy_.yytext = "\u27FA"; return "OPS"; -break; -case 581: yy_.yytext = "\u210F"; return "A"; -break; -case 582: this.pushState("TEXTARG"); return "HREF"; -break; -case 583: yy_.yytext = "\u21AA"; return "OPS"; -break; -case 584: yy_.yytext = "\u21A9"; return "OPS"; -break; -case 585: yy_.yytext = "\u2926"; return "OP"; -break; -case 586: yy_.yytext = "\u2925"; return "OP"; -break; -case 587: yy_.yytext = "\u2661"; return "OP"; -break; -case 588: yy_.yytext = "\u210F"; return "A"; -break; -case 589: yy_.yytext = "\u005E"; return "ACCENTNS"; -break; -case 590: yy_.yytext = "\u2269\uFE00"; return "OP"; -break; -case 591: yy_.yytext = "\u2269\uFE00"; return "OP"; -break; -case 592: yy_.yytext = "\u2273"; return "OP"; -break; -case 593: yy_.yytext = "\u2277"; return "OP"; -break; -case 594: yy_.yytext = "\u2A8C"; return "OP"; -break; -case 595: yy_.yytext = "\u22DB"; return "OP"; -break; -case 596: yy_.yytext = "\u22D7"; return "OP"; -break; -case 597: yy_.yytext = "\u2A86"; return "OP"; -break; -case 598: yy_.yytext = "\u003E"; return "OP"; -break; -case 599: yy_.yytext = "\u003E"; return "OP"; -break; -case 600: yy_.yytext = "\u22E7"; return "OP"; -break; -case 601: yy_.yytext = "\u2269"; return "OP"; -break; -case 602: yy_.yytext = "\u2A88"; return "OP"; -break; -case 603: yy_.yytext = "\u2A8A"; return "OP"; -break; -case 604: yy_.yytext = "\u2137"; return "A"; -break; -case 605: yy_.yytext = "\u22D9"; return "OP"; -break; -case 606: yy_.yytext = "\u226B"; return "OP"; -break; -case 607: yy_.yytext = "\u2A7E"; return "OP"; -break; -case 608: yy_.yytext = "\u2267"; return "OP"; -break; -case 609: yy_.yytext = "\u2265"; return "OP"; -break; -case 610: yy_.yytext = "\u2265"; return "OP"; -break; -case 611: yy_.yytext = "\u0393"; return "AIUG"; -break; -case 612: yy_.yytext = "\u03B3"; return "AILG"; -break; -case 613: yy_.yytext = "\u2322"; return "OP"; -break; -case 614: this.pushState("TEXTARG"); return "FRAME"; -break; -case 615:return "FRAC"; -break; -case 616: yy_.yytext = "\u2ADD"; return "OP"; -break; -case 617: yy_.yytext = "\u2ADD\u0338"; return "OP"; -break; -case 618: yy_.yytext = "\u2200"; return "OP"; -break; -case 619: yy_.yytext = "\u266D"; return "OP"; -break; -case 620: yy_.yytext = "\u292C"; return "OP"; -break; -case 621: yy_.yytext = "\u292F"; return "OP"; -break; -case 622: yy_.yytext = "\u2252"; return "OP"; -break; -case 623: yy_.yytext = "\u2203"; return "OP"; -break; -case 624: yy_.yytext = "\u00F0"; return "A"; -break; -case 625: yy_.yytext = "\u00F0"; return "A"; -break; -case 626: yy_.yytext = "\u0397"; return "AIUG"; -break; -case 627: yy_.yytext = "\u03B7"; return "AILG"; -break; -case 628: yy_.yytext = "\u2261"; return "OP"; -break; -case 629: this.pushState("TEXTARG"); return "EQROWS"; -break; -case 630: this.pushState("TEXTARG"); return "EQCOLS"; -break; -case 631: yy_.yytext = "\u2A95"; return "OP"; -break; -case 632: yy_.yytext = "\u2A96"; return "OP"; -break; -case 633: yy_.yytext = "\u2242"; return "OP"; -break; -case 634: yy_.yytext = "\u003D\u2237"; return "OP"; -break; -case 635: yy_.yytext = "\u2255"; return "OP"; -break; -case 636: yy_.yytext = "\u2212\u2237"; return "OP"; -break; -case 637: yy_.yytext = "\u003D\u2237"; return "OP"; -break; -case 638: yy_.yytext = "\u003D\u2237"; return "OP"; -break; -case 639: yy_.yytext = "\u003D\u2237"; return "OP"; -break; -case 640: yy_.yytext = "\u2255"; return "OP"; -break; -case 641: yy_.yytext = "\u2256"; return "OP"; -break; -case 642: yy_.yytext = "\u03F5"; return "AILG"; -break; -case 643:return "EVVMATRIX"; -break; -case 644:return "EVMATRIX"; -break; -case 645: return "ETOGGLE"; -break; -case 646:return "EALIGNED"; -break; -case 647:return "ESMALLMATRIX"; -break; -case 648:return "EPMATRIX"; -break; -case 649:return "EMATRIX"; -break; -case 650:return "EGATHERED"; -break; -case 651:return "ECASES"; -break; -case 652:return "EBBMATRIX"; -break; -case 653:return "EBMATRIX"; -break; -case 654:return "EARRAY"; -break; -case 655:return "EALIGNED"; -break; -case 656: yy_.yytext = "\u2205"; return "A"; -break; -case 657: yy_.yytext = "\u2205"; return "A"; -break; -case 658: yy_.yytext = "\u21AA"; return "OPS"; -break; -case 659: yy_.yytext = "\u2113"; return "A"; -break; -case 660: yy_.yytext = "\u2195"; return "OPS"; -break; -case 661: yy_.yytext = "\u29DF"; return "OP"; -break; -case 662: yy_.yytext = "\u2910"; return "OPS"; -break; -case 663: yy_.yytext = "\u2195"; return "OPS"; -break; -case 664: yy_.yytext = "\u21C2"; return "OPS"; -break; -case 665: yy_.yytext = "\u21C3"; return "OPS"; -break; -case 666: yy_.yytext = "\u21CA"; return "OPS"; -break; -case 667: yy_.yytext = "\u21D3"; return "OPS"; -break; -case 668: yy_.yytext = "\u2193"; return "OPS"; -break; -case 669: yy_.yytext = "\u222C"; return "OP"; -break; -case 670: yy_.yytext = "\u2A5E"; return "OP"; -break; -case 671: yy_.yytext = "\u2306"; return "OP"; -break; -case 672: yy_.yytext = "\u2026"; return "OP"; -break; -case 673: yy_.yytext = "\u2214"; return "OP"; -break; -case 674: yy_.yytext = "\u2238"; return "OP"; -break; -case 675: yy_.yytext = "\u2251"; return "OP"; -break; -case 676: yy_.yytext = "\u2251"; return "OP"; -break; -case 677: yy_.yytext = "\u2250"; return "OP"; -break; -case 678: yy_.yytext = "\u02D9"; return "ACCENT"; -break; -case 679: yy_.yytext = "\u22C7"; return "OP"; -break; -case 680: yy_.yytext = "\u00F7"; return "OP"; -break; -case 681:return "DISPLAYSTYLE"; -break; -case 682: yy_.yytext = "\u2A08"; return "OPM"; -break; -case 683: yy_.yytext = "\u03DD"; return "A"; -break; -case 684: yy_.yytext = "\u2662"; return "OP"; -break; -case 685: yy_.yytext = "\u22C4"; return "OP"; -break; -case 686: yy_.yytext = "\u22C4"; return "OP"; -break; -case 687: yy_.yytext = yy_.yytext.slice(1); return "FM"; -break; -case 688: yy_.yytext = "\u0394"; return "AIUG"; -break; -case 689: yy_.yytext = "\u03B4"; return "AILG"; -break; -case 690: yy_.yytext = "\u2207"; return "OP"; -break; -case 691: yy_.yytext = "\u00B0"; return "OP"; -break; -case 692: yy_.yytext = "\u290B"; return "OPS"; -break; -case 693: yy_.yytext = "\u2A77"; return "OP"; -break; -case 694: yy_.yytext = "\u22F1"; return "OP"; -break; -case 695: yy_.yytext = "\u0308"; return "ACCENT"; -break; -case 696: yy_.yytext = "\u20DB"; return "OP"; -break; -case 697: yy_.yytext = "\u20DB"; return "ACCENT"; -break; -case 698: yy_.yytext = "\u20DC"; return "OP"; -break; -case 699: yy_.yytext = "\u20DC"; return "ACCENT"; -break; -case 700: yy_.yytext = "\u2021"; return "OP"; -break; -case 701: yy_.yytext = "\u2237"; return "OP"; -break; -case 702: yy_.yytext = "\u290F"; return "OPS"; -break; -case 703: yy_.yytext = "\u2AE4"; return "OP"; -break; -case 704: yy_.yytext = "\u2AE3"; return "OP"; -break; -case 705: yy_.yytext = "\u22A3"; return "OP"; -break; -case 706: yy_.yytext = "\u290F"; return "OPS"; -break; -case 707: yy_.yytext = "\u290E"; return "OPS"; -break; -case 708: yy_.yytext = "\u2193"; return "OPS"; -break; -case 709: yy_.yytext = "\u2138"; return "A"; -break; -case 710: yy_.yytext = "\u2020"; return "OP"; -break; -case 711: yy_.yytext = "\u21B7"; return "OP"; -break; -case 712: yy_.yytext = "\u21B6"; return "OP"; -break; -case 713: yy_.yytext = "\u293B"; return "OP"; -break; -case 714: yy_.yytext = "\u22CF"; return "OP"; -break; -case 715: yy_.yytext = "\u22CE"; return "OP"; -break; -case 716: yy_.yytext = "\u22DF"; return "OP"; -break; -case 717: yy_.yytext = "\u22DE"; return "OP"; -break; -case 718: yy_.yytext = "\u228D"; return "OP"; -break; -case 719: yy_.yytext = "\u22D3"; return "OP"; -break; -case 720: yy_.yytext = "\u222A"; return "OP"; -break; -case 721: yy_.yytext = "\u2210"; return "OPM"; -break; -case 722: yy_.yytext = "\u2210"; return "OPM"; -break; -case 723: yy_.yytext = "\u222E"; return "OP"; -break; -case 724: yy_.yytext = "\u2A07"; return "OPM"; -break; -case 725: yy_.yytext = "\u222E"; return "OP"; -break; -case 726: yy_.yytext = "\u2245"; return "OP"; -break; -case 727: yy_.yytext = "\u2201"; return "OP"; -break; -case 728: this.begin("TEXTARG"); return "COLSPAN"; -break; -case 729: this.pushState("TEXTARG"); return "COLOR"; -break; -case 730: yy_.yytext = "\u2237\u223C"; return "OP"; -break; -case 731: yy_.yytext = "\u2236\u223C"; return "OP"; -break; -case 732: yy_.yytext = "\u2A74"; return "OP"; -break; -case 733: yy_.yytext = "\u2254"; return "OP"; -break; -case 734: yy_.yytext = "\u2237\u2212"; return "OP"; -break; -case 735: yy_.yytext = "\u2254"; return "OP"; -break; -case 736: yy_.yytext = "\u2237\u2248"; return "OP"; -break; -case 737: yy_.yytext = "\u2236\u2248"; return "OP"; -break; -case 738: yy_.yytext = "\u2237"; return "OP"; -break; -case 739: yy_.yytext = "\u003A"; return "OP"; -break; -case 740: this.pushState("TEXTARG"); return "COLLINES"; -break; -case 741: this.pushState("TEXTARG"); return "COLLAYOUT"; -break; -case 742: this.begin("TEXTARG"); return "COLALIGN"; -break; -case 743: yy_.yytext = "\u2663"; return "OP"; -break; -case 744: yy_.yytext = "\u00AF"; return "ACCENT"; -break; -case 745: yy_.yytext = "\u229D"; return "OP"; -break; -case 746: yy_.yytext = "\u229A"; return "OP"; -break; -case 747: yy_.yytext = "\u229B"; return "OP"; -break; -case 748: yy_.yytext = "\u2941"; return "OP"; -break; -case 749: yy_.yytext = "\u2940"; return "OP"; -break; -case 750: yy_.yytext = "\u2257"; return "OP"; -break; -case 751: yy_.yytext = "\u2218"; return "OP"; -break; -case 752:return "TEXCHOOSE"; -break; -case 753: yy_.yytext = "\u03C7"; return "AILG"; -break; -case 754: yy_.yytext = "\u02C7"; return "ACCENTNS"; -break; -case 755:return "CELLOPTS"; -break; -case 756: yy_.yytext = "\u22EF"; return "OP"; -break; -case 757: yy_.yytext = "\u00B7"; return "OP"; -break; -case 758: yy_.yytext = "\u22C5"; return "OP"; -break; -case 759: yy_.yytext = "\u22D2"; return "OP"; -break; -case 760: yy_.yytext = "\u2229"; return "OP"; -break; -case 761: yy_.yytext = "\u2AAE"; return "OP"; -break; -case 762: yy_.yytext = "\u224E"; return "OP"; -break; -case 763: yy_.yytext = "\u224F"; return "OP"; -break; -case 764: yy_.yytext = "\u2022"; return "OP"; -break; -case 765: yy_.yytext = "\u2A32"; return "OP"; -break; -case 766: yy_.yytext = "\u22A0"; return "OP"; -break; -case 767: yy_.yytext = "\u229E"; return "OP"; -break; -case 768: yy_.yytext = "\u229F"; return "OP"; -break; -case 769:return "BOXED"; -break; -case 770: yy_.yytext = "\u22A1"; return "OP"; -break; -case 771: yy_.yytext = "\u29C4"; return "OP"; -break; -case 772: yy_.yytext = "\u29C7"; return "OP"; -break; -case 773: yy_.yytext = "\u29C5"; return "OP"; -break; -case 774: yy_.yytext = "\u29C6"; return "OP"; -break; -case 775: yy_.yytext = "\u25A1"; return "OP"; -break; -case 776: yy_.yytext = "\u22C8"; return "OP"; -break; -case 777: yy_.yytext = "\u22A5"; return "OP"; -break; -case 778: yy_.yytext = "\u22A5"; return "OP"; -break; -case 779:return "MATHBF"; -break; -case 780: yy_.yytext = "\u25B8"; return "OP"; -break; -case 781: yy_.yytext = "\u25C2"; return "OP"; -break; -case 782: yy_.yytext = "\u25BE"; return "OP"; -break; -case 783: yy_.yytext = "\u25B4"; return "OP"; -break; -case 784: yy_.yytext = "\u25A0"; return "OP"; -break; -case 785: yy_.yytext = "\u29EB"; return "OP"; -break; -case 786: yy_.yytext = "\u290D"; return "OPS"; -break; -case 787:return "BINOM"; -break; -case 788: yy_.yytext = "\u22C0"; return "OPM"; -break; -case 789: yy_.yytext = "\u22C1"; return "OPM"; -break; -case 790: yy_.yytext = "\u2A04"; return "OPM"; -break; -case 791: yy_.yytext = "\u25B3"; return "OP"; -break; -case 792: yy_.yytext = "\u25BD"; return "OP"; -break; -case 793: yy_.yytext = "\u2A09"; return "OPM"; -break; -case 794: yy_.yytext = "\u2605"; return "OP"; -break; -case 795: yy_.yytext = "\u2A06"; return "OPM"; -break; -case 796: yy_.yytext = "\u2A05"; return "OPM"; -break; -case 797:return "BBIG"; -break; -case 798:return "BIG"; -break; -case 799: yy_.yytext = "\u2A02"; return "OPM"; -break; -case 800: yy_.yytext = "\u2A01"; return "OPM"; -break; -case 801: yy_.yytext = "\u2A00"; return "OPM"; -break; -case 802:return "BBIGL"; -break; -case 803:return "BIGL"; -break; -case 804: yy_.yytext = "\u2AFC"; return "OPM"; -break; -case 805:return "BBIGG"; -break; -case 806:return "BIGG"; -break; -case 807:return "BBIGGL"; -break; -case 808:return "BIGGL"; -break; -case 809:return "BBIGG"; -break; -case 810:return "BIGG"; -break; -case 811: yy_.yytext = "\u2A03"; return "OPM"; -break; -case 812: yy_.yytext = "\u22C3"; return "OPM"; -break; -case 813: yy_.yytext = "\u25CB"; return "OP"; -break; -case 814: yy_.yytext = "\u22C2"; return "OPM"; -break; -case 815:return "BBIG"; -break; -case 816:return "BIG"; -break; -case 817: this.pushState("TEXTARG"); return "BGCOLOR"; -break; -case 818: yy_.yytext = "\u226C"; return "OP"; -break; -case 819: yy_.yytext = "\u2136"; return "A"; -break; -case 820: yy_.yytext = "\u0392"; return "AIUG"; -break; -case 821: yy_.yytext = "\u03B2"; return "AILG"; -break; -case 822:return "BVVMATRIX"; -break; -case 823:return "BVMATRIX"; -break; -case 824: return "BTOGGLE"; -break; -case 825:return "BALIGNED"; -break; -case 826:return "BSMALLMATRIX"; -break; -case 827:return "BPMATRIX"; -break; -case 828:return "BMATRIX"; -break; -case 829:return "BGATHERED"; -break; -case 830:return "BCASES"; -break; -case 831:return "BBBMATRIX"; -break; -case 832:return "BBMATRIX"; -break; -case 833: this.pushState("TEXTARG"); this.pushState("TEXTOPTARG"); this.pushState("TRYOPTARG"); return "BARRAY"; -break; -case 834:return "BALIGNED"; -break; -case 835: yy_.yytext = "\u2235"; return "OP"; -break; -case 836: yy_.yytext = "\u213F"; return "A"; -break; -case 837: yy_.yytext = "\u2305"; return "OP"; -break; -case 838: yy_.yytext = "\u00AF"; return "ACCENTNS"; -break; -case 839: yy_.yytext = "\u005C"; return "OP"; -break; -case 840: yy_.yytext = "\u22CD"; return "OP"; -break; -case 841: yy_.yytext = "\u223D"; return "OP"; -break; -case 842: yy_.yytext = "\u2035"; return "OPP"; -break; -case 843: yy_.yytext = "\u03F6"; return "OP"; -break; -case 844:return "TEXATOP"; -break; -case 845: yy_.yytext = "\u224D"; return "OP"; -break; -case 846: yy_.yytext = "\u2217"; return "OP"; -break; -case 847:return "ARRAYOPTS"; -break; -case 848:return "ARRAY"; -break; -case 849: yy_.yytext = yy_.yytext.slice(1); return "F"; -break; -case 850: yy_.yytext = "\u224A"; return "OP"; -break; -case 851: yy_.yytext = "\u2248"; return "OP"; -break; -case 852: yy_.yytext = "\u2220"; return "OP"; -break; -case 853: yy_.yytext = "\u2A3F"; return "OP"; -break; -case 854: yy_.yytext = "\u0391"; return "AIUG"; -break; -case 855: yy_.yytext = "\u03B1"; return "AILG"; -break; -case 856: this.pushState("TEXTARG"); return "ALIGN"; -break; -case 857: yy_.yytext = "\u2135"; return "A"; -break; -case 858:return "AIUL"; -break; -case 859:return "AIUG"; -break; -case 860:return "AILL"; -break; -case 861:return "AILG"; -break; -case 862: yy_.yytext = "\u22F0"; return "OP"; -break; -case 863: yy_.yytext = "\u212B"; return "A"; -break; -case 864:return "A"; -break; -case 865: yy_.yytext = "\u0024"; return "A"; -break; -case 866: yy_.yytext = "\u007D"; return "OPFS"; -break; -case 867: yy_.yytext = "\u2016"; return "OPFS"; -break; -case 868: yy_.yytext = "\u007B"; return "OPFS"; -break; -case 869:return "THICKSPACE"; -break; -case 870:return "MEDSPACE"; -break; -case 871:return "THINSPACE"; -break; -case 872: yy_.yytext = "\u0026"; return "A"; -break; -case 873: yy_.yytext = "\u0025"; return "A"; -break; -case 874: yy_.yytext = "\u0023"; return "OP"; -break; -case 875:return "NEGSPACE"; -break; -case 876: yy_.yytext = "\u2212"; return "OP"; -break; -case 877: yy_.yytext = "\u2057"; return "OPP"; -break; -case 878: yy_.yytext = "\u2034"; return "OPP"; -break; -case 879: yy_.yytext = "\u2033"; return "OPP"; -break; -case 880: yy_.yytext = "\u2032"; return "OPP"; -break; -case 881:return "HIGH_SURROGATE"; -break; -case 882:return "LOW_SURROGATE"; -break; -case 883:return "BMP_CHARACTER"; -break; -} -}, -rules: [/^(?:.)/,/^(?:\$\$|\\\[|\$|\\\()/,/^(?:$)/,/^(?:\\[$\\])/,/^(?:[<&>])/,/^(?:[^])/,/^(?:\s*\[)/,/^(?:.)/,/^(?:([^\\\]]|(\\[\\\]]))+)/,/^(?:\])/,/^(?:\s*\{)/,/^(?:([^\\\}]|(\\[\\\}]))+)/,/^(?:\})/,/^(?:\])/,/^(?:\s+)/,/^(?:\$\$|\\\]|\$|\\\))/,/^(?:\{)/,/^(?:\})/,/^(?:\^)/,/^(?:_)/,/^(?:\.)/,/^(?:&)/,/^(?:\\\\)/,/^(?:[0-9]+(?:\.[0-9]+)?|[\u0660-\u0669]+(?:\u066B[\u0660-\u0669]+)?|(?:\uD835[\uDFCE-\uDFD7])+|(?:\uD835[\uDFD8-\uDFE1])+|(?:\uD835[\uDFE2-\uDFEB])+|(?:\uD835[\uDFEC-\uDFF5])+|(?:\uD835[\uDFF6-\uDFFF])+)/,/^(?:[a-zA-Z]+)/,/^(?:\\Zeta)/,/^(?:\\zeta)/,/^(?:\\xrightleftharpoons)/,/^(?:\\xRightarrow)/,/^(?:\\xrightarrow)/,/^(?:\\xmapsto)/,/^(?:\\xleftrightharpoons)/,/^(?:\\xLeftrightarrow)/,/^(?:\\xleftrightarrow)/,/^(?:\\xLeftarrow)/,/^(?:\\xleftarrow)/,/^(?:\\Xi)/,/^(?:\\xi)/,/^(?:\\xhookrightarrow)/,/^(?:\\xhookleftarrow)/,/^(?:\\wr)/,/^(?:\\wp)/,/^(?:\\widevec)/,/^(?:\\widetilde)/,/^(?:\\widehat)/,/^(?:\\widecheck)/,/^(?:\\widebar)/,/^(?:\\wedgeq)/,/^(?:\\Wedge)/,/^(?:\\wedge)/,/^(?:\\Vvert)/,/^(?:\\Vvdash)/,/^(?:\\Vert)/,/^(?:\\vert)/,/^(?:\\veebar)/,/^(?:\\Vee)/,/^(?:\\vee)/,/^(?:\\vec)/,/^(?:\\vdots)/,/^(?:\\VDash)/,/^(?:\\Vdash)/,/^(?:\\vDash)/,/^(?:\\vdash)/,/^(?:\\Vbar)/,/^(?:\\vartriangleright)/,/^(?:\\vartriangleleft)/,/^(?:\\vartriangle)/,/^(?:\\vartheta)/,/^(?:\\varsupsetneqq)/,/^(?:\\varsupsetneq)/,/^(?:\\varsubsetneqq)/,/^(?:\\varsubsetneqq)/,/^(?:\\varsubsetneq)/,/^(?:\\varsigma)/,/^(?:\\varrho)/,/^(?:\\varpropto)/,/^(?:\\varpi)/,/^(?:\\varphi)/,/^(?:\\varnothing)/,/^(?:\\varkappa)/,/^(?:\\varepsilon)/,/^(?:\\Uuparrow)/,/^(?:\\upuparrows)/,/^(?:\\Upsilon)/,/^(?:\\upsilon)/,/^(?:\\Upsi)/,/^(?:\\uplus)/,/^(?:\\upint)/,/^(?:\\upharpoonright)/,/^(?:\\upharpoonleft)/,/^(?:\\Updownarrow)/,/^(?:\\updownarrow)/,/^(?:\\updarr)/,/^(?:\\Uparrow)/,/^(?:\\uparrow)/,/^(?:\\uparr)/,/^(?:\\unrhd)/,/^(?:\\unlhd)/,/^(?:\\Union)/,/^(?:\\union)/,/^(?:\\underset)/,/^(?:\\underoverset)/,/^(?:\\underline)/,/^(?:\\underbrace)/,/^(?:\\udots)/,/^(?:\u2ADD\u0338)/,/^(?:\u2ACC\uFE00)/,/^(?:\u2ACB\uFE00)/,/^(?:\u2AB0\u0338)/,/^(?:\u2AAF\u0338)/,/^(?:\u2AA2\u0338)/,/^(?:\u2AA1\u0338)/,/^(?:\u2A7E\u0338)/,/^(?:\u2A7D\u0338)/,/^(?:\u29D0\u0338)/,/^(?:\u29CF\u0338)/,/^(?:\u2290\u0338)/,/^(?:\u228F\u0338)/,/^(?:\u228B\uFE00)/,/^(?:\u228A\uFE00)/,/^(?:\u2283\u20D2)/,/^(?:\u2282\u20D2)/,/^(?:\u227F\u0338)/,/^(?:\u226B\u0338)/,/^(?:\u226A\u0338)/,/^(?:\u2269\uFE00)/,/^(?:\u2268\uFE00)/,/^(?:\u2266\u0338)/,/^(?:\u224F\u0338)/,/^(?:\u224E\u0338)/,/^(?:\u2242\u0338)/,/^(?:\u223D\u0331)/,/^(?:\u2237\u2248)/,/^(?:\u2237\u223C)/,/^(?:\u2237\u2212)/,/^(?:\u2236\u2248)/,/^(?:\u2236\u223C)/,/^(?:\u2212\u2237)/,/^(?:\u007C\u007C\u007C)/,/^(?:\u007C\u007C)/,/^(?:\u003E\u003D)/,/^(?:\u003D\u2237)/,/^(?:\u003D\u2237)/,/^(?:\u003D\u003D)/,/^(?:\u003C\u003E)/,/^(?:\u003C\u003D)/,/^(?:\u003A\u003D)/,/^(?:\u002F\u003D)/,/^(?:\u002F\u002F)/,/^(?:\u002E\u002E\u002E)/,/^(?:\u002E\u002E)/,/^(?:\u002D\u003E)/,/^(?:\u002D\u003D)/,/^(?:\u002D\u002D)/,/^(?:\u002B\u003D)/,/^(?:\u002B\u002B)/,/^(?:\u002A\u003D)/,/^(?:\u002A\u002A)/,/^(?:\u0026\u0026)/,/^(?:\u0021\u003D)/,/^(?:\u0021\u0021)/,/^(?:\\twoheadrightarrowtail)/,/^(?:\\twoheadrightarrow)/,/^(?:\\twoheadleftarrow)/,/^(?:\\tripleintegral)/,/^(?:\\trianglerighteq)/,/^(?:\\triangleright)/,/^(?:\\triangleq)/,/^(?:\\trianglelefteq)/,/^(?:\\triangleleft)/,/^(?:\\triangledown)/,/^(?:\\triangle)/,/^(?:\\towa)/,/^(?:\\tosa)/,/^(?:\\top)/,/^(?:\\tooltip)/,/^(?:\\tona)/,/^(?:\\toggle)/,/^(?:\\toea)/,/^(?:\\to)/,/^(?:\\timesb)/,/^(?:\\times)/,/^(?:\\tilde)/,/^(?:\\thinspace)/,/^(?:\\thickspace)/,/^(?:\\thicksim)/,/^(?:\\thickapprox)/,/^(?:\\Theta)/,/^(?:\\theta)/,/^(?:\\therefore)/,/^(?:\\tfrac)/,/^(?:\\textstyle)/,/^(?:\\textsize)/,/^(?:\\textquotedblright)/,/^(?:\\textquotedblleft)/,/^(?:\\textasciitilde)/,/^(?:\\textasciigrave)/,/^(?:\\textasciicircumflex)/,/^(?:\\textasciiacute)/,/^(?:\\text)/,/^(?:\\tensor)/,/^(?:\\tbinom)/,/^(?:\\Tau)/,/^(?:\\tau)/,/^(?:\\swArrow)/,/^(?:\\swarrow)/,/^(?:\\swArr)/,/^(?:\\swarr)/,/^(?:\\surd)/,/^(?:\\supsetneqq)/,/^(?:\\supsetneq)/,/^(?:\\supseteqq)/,/^(?:\\supseteq)/,/^(?:\\Supset)/,/^(?:\\supset)/,/^(?:\\sum)/,/^(?:\\succsim)/,/^(?:\\succnsim)/,/^(?:\\succneqq)/,/^(?:\\succnapprox)/,/^(?:\\succeq)/,/^(?:\\succcurlyeq)/,/^(?:\\succapprox)/,/^(?:\\succ)/,/^(?:\\substack)/,/^(?:\\subsetneqq)/,/^(?:\\subsetneq)/,/^(?:\\subseteqq)/,/^(?:\\subseteq)/,/^(?:\\Subset)/,/^(?:\\subset)/,/^(?:\\statusline)/,/^(?:\\star)/,/^(?:\\stackrel)/,/^(?:\\sslash)/,/^(?:\\square)/,/^(?:\\sqsupseteq)/,/^(?:\\sqsupset)/,/^(?:\\sqsubseteq)/,/^(?:\\sqsubset)/,/^(?:\\sqrt)/,/^(?:\\sqcup)/,/^(?:\\sqcap)/,/^(?:\\sphericalangle)/,/^(?:\\spadesuit)/,/^(?:\\space)/,/^(?:\\smile)/,/^(?:\\smallsmile)/,/^(?:\\smallsetminus)/,/^(?:\\smallfrown)/,/^(?:\\slash)/,/^(?:\\simeq)/,/^(?:\\sim)/,/^(?:\\Sigma)/,/^(?:\\sigma)/,/^(?:\\shuffle)/,/^(?:\\shortparallel)/,/^(?:\\shortmid)/,/^(?:\\sharp)/,/^(?:\\setminus)/,/^(?:\\seovnearrow)/,/^(?:\\seArrow)/,/^(?:\\searrow)/,/^(?:\\seArr)/,/^(?:\\searr)/,/^(?:\\scriptsize)/,/^(?:\\scriptscriptsize)/,/^(?:\\rtimes)/,/^(?:\\Rsh)/,/^(?:\\Rrightarrow)/,/^(?:\\rrangle)/,/^(?:\\rq)/,/^(?:\\rowspan)/,/^(?:\\rowopts)/,/^(?:\\rowlines)/,/^(?:\\rowalign)/,/^(?:\\root)/,/^(?:\\rmoustache)/,/^(?:\\risingdotseq)/,/^(?:\\righttoleftarrow)/,/^(?:\\rightthreetimes)/,/^(?:\\rightsquigarrow)/,/^(?:\\rightrightarrows)/,/^(?:\\rightleftharpoons)/,/^(?:\\rightleftarrows)/,/^(?:\\rightharpoonup)/,/^(?:\\rightharpoondown)/,/^(?:\\rightarrowtriangle)/,/^(?:\\rightarrowtail)/,/^(?:\\Rightarrow)/,/^(?:\\rightarrow)/,/^(?:\\right)/,/^(?:\\Rho)/,/^(?:\\rho)/,/^(?:\\rhd)/,/^(?:\\rfloor)/,/^(?:\\Re)/,/^(?:\\rdiagovsearrow)/,/^(?:\\rdiagovfdiag)/,/^(?:\\rceil)/,/^(?:\\rbrack)/,/^(?:\\rbrace)/,/^(?:\\rangle)/,/^(?:\\rang)/,/^(?:\\questeq)/,/^(?:\\quadrupleintegral)/,/^(?:\\quad)/,/^(?:\\qquad)/,/^(?:\\qed)/,/^(?:\\Psi)/,/^(?:\\psi)/,/^(?:\\propto)/,/^(?:\\product)/,/^(?:\\prod)/,/^(?:\\prime)/,/^(?:\\precsim)/,/^(?:\\precnsim)/,/^(?:\\precneqq)/,/^(?:\\precnapprox)/,/^(?:\\preceq)/,/^(?:\\preccurlyeq)/,/^(?:\\precapprox)/,/^(?:\\prec)/,/^(?:\\pmod)/,/^(?:\\pm)/,/^(?:\\plusdot)/,/^(?:\\plusb)/,/^(?:\\pitchfork)/,/^(?:\\Pi)/,/^(?:\\pi)/,/^(?:\\Phi)/,/^(?:\\phi)/,/^(?:\\phantom)/,/^(?:\\Perp)/,/^(?:\\perp)/,/^(?:\\partialmeetcontraction)/,/^(?:\\partial)/,/^(?:\\parr)/,/^(?:\\parallel)/,/^(?:\\padding)/,/^(?:\\overset)/,/^(?:\\overline)/,/^(?:\\overbrace)/,/^(?:\\over)/,/^(?:\\Otimes)/,/^(?:\\otimes)/,/^(?:\\oslash)/,/^(?:[\u007E\u00AF\u02C6\u02C7\u02C9\u02CD\u02DC\u02F7\u0302\u203E\u2044\u2190-\u2199\u219C-\u21AD\u21AF-\u21B5\u21B9\u21BC-\u21CC\u21D0-\u21DD\u21E0-\u21F0\u21F3\u21F5\u21F6\u21FD-\u21FF\u2215\u221A\u23B4\u23B5\u23DC-\u23E1\u27F0\u27F1\u27F5-\u27FF\u290A-\u2910\u2912\u2913\u2921\u2922\u294E-\u2961\u296E\u296F\u2B45\u2B46])/,/^(?:[\u2032-\u2035\u2057])/,/^(?:[\u220F-\u2211\u22C0-\u22C3\u2A00-\u2A0A\u2A10-\u2A14\u2AFC\u2AFF])/,/^(?:\\Oplus)/,/^(?:\\oplus)/,/^(?:[\u0028\u0029\u005B\u005D\u007C\u2016\u2308-\u230B\u2329\u232A\u2772\u2773\u27E6-\u27EF\u2980\u2983-\u2998\u29FC\u29FD])/,/^(?:[\u2018\u2019\u201C\u201D])/,/^(?:\\operatorname)/,/^(?:[\u0021-\u0023\u002A-\u002C\u002F\u003A-\u0040\u0060\u00A8\u00AA\u00AC\u00B0-\u00B4\u00B7-\u00BA\u00D7\u00F7\u02CA\u02CB\u02D8-\u02DA\u02DD\u0311\u03F6\u201A\u201B\u201E-\u2022\u2026\u2036\u2037\u2043\u2061-\u2064\u20DB\u20DC\u2145\u2146\u214B\u219A\u219B\u21AE\u21B6-\u21B8\u21BA\u21BB\u21CD-\u21CF\u21DE\u21DF\u21F1\u21F2\u21F4\u21F7-\u21FC\u2200-\u2204\u2206-\u220E\u2212-\u2214\u2216-\u2219\u221B-\u221D\u221F-\u22BF\u22C4-\u22FF\u2305\u2306\u2322\u2323\u23B0\u23B1\u25A0\u25A1\u25AA\u25AB\u25AD-\u25B9\u25BC-\u25CF\u25D6\u25D7\u25E6\u2605\u2660-\u2663\u266D-\u266F\u2758\u27F2\u27F3\u2900-\u2909\u2911\u2914-\u2920\u2923-\u294D\u2962-\u296D\u2970-\u297F\u2981\u2982\u2999-\u29D9\u29DB-\u29FB\u29FE\u29FF\u2A0B-\u2A0F\u2A15-\u2ADB\u2ADD-\u2AFB\u2AFD\u2AFE])/,/^(?:\\ominus)/,/^(?:\\omicron)/,/^(?:\\Omega)/,/^(?:\\omega)/,/^(?:\\oint)/,/^(?:\\oiint)/,/^(?:\\oiiint)/,/^(?:\\odot)/,/^(?:\\odash)/,/^(?:\\obslash)/,/^(?:\\nwovnearrow)/,/^(?:\\nwArrow)/,/^(?:\\nwarrow)/,/^(?:\\nwArr)/,/^(?:\\nwarr)/,/^(?:\\nVDash)/,/^(?:\\nVdash)/,/^(?:\\nvDash)/,/^(?:\\nvdash)/,/^(?:\u221E)/,/^(?:\\Nu)/,/^(?:\\nu)/,/^(?:\\ntrianglerighteq)/,/^(?:\\ntriangleright)/,/^(?:\\ntrianglelefteq)/,/^(?:\\ntriangleleft)/,/^(?:\\nsupseteq)/,/^(?:\\nsupset)/,/^(?:\\nsuccsim)/,/^(?:\\nsucceq)/,/^(?:\\nsucc)/,/^(?:\\nsubseteqq)/,/^(?:\\nsubseteq)/,/^(?:\\nsubset)/,/^(?:\\nsime)/,/^(?:\\nsim)/,/^(?:\\nshortparallel)/,/^(?:\\nshortmid)/,/^(?:\\nRightarrow)/,/^(?:\\nrightarrow)/,/^(?:\\npreceq)/,/^(?:\\nprec)/,/^(?:\\nparallel)/,/^(?:\\notni)/,/^(?:\\notin)/,/^(?:\\not)/,/^(?:\\nmid)/,/^(?:\\nless)/,/^(?:\\nleqslant)/,/^(?:\\nleqq)/,/^(?:\\nleq)/,/^(?:\\nLeftrightarrow)/,/^(?:\\nleftrightarrow)/,/^(?:\\nLeftarrow)/,/^(?:\\nleftarrow)/,/^(?:\\ni)/,/^(?:\\ngtr)/,/^(?:\\ngeqslant)/,/^(?:\\ngeqq)/,/^(?:\\ngeq)/,/^(?:\\nexists)/,/^(?:\\nequiv)/,/^(?:\\neqsim)/,/^(?:\\neq)/,/^(?:\\neovsearrow)/,/^(?:\\neovnwarrow)/,/^(?:\\negthickspace)/,/^(?:\\negspace)/,/^(?:\\negmedspace)/,/^(?:\\neg)/,/^(?:\\neArrow)/,/^(?:\\nearrow)/,/^(?:\\neArr)/,/^(?:\\nearr)/,/^(?:\\ne)/,/^(?:\\ncong)/,/^(?:\\nBumpeq)/,/^(?:\\nbumpeq)/,/^(?:\\natural)/,/^(?:\\napprox)/,/^(?:\\nabla)/,/^(?:\\multiscripts)/,/^(?:\\multimap)/,/^(?:\\Mu)/,/^(?:\\mu)/,/^(?:\\mtext)/,/^(?:\\ms)/,/^(?:\\mp)/,/^(?:\\models)/,/^(?:\\mod)/,/^(?:\\mo)/,/^(?:\\mn)/,/^(?:\\mlcp)/,/^(?:\\minusdot)/,/^(?:\\minusb)/,/^(?:\\minus)/,/^(?:\\min)/,/^(?:\\mid)/,/^(?:\\mi)/,/^(?:\\mho)/,/^(?:\\mho)/,/^(?:\\medspace)/,/^(?:\\measuredangle)/,/^(?:\\mathtt)/,/^(?:\\mathsf)/,/^(?:\\mathscr)/,/^(?:\\mathrm)/,/^(?:\\mathrlap)/,/^(?:\\mathrel)/,/^(?:\\mathraisebox)/,/^(?:\\mathop)/,/^(?:\\mathmit)/,/^(?:\\mathllap)/,/^(?:\\mathit)/,/^(?:\\mathfrak)/,/^(?:\\mathfr)/,/^(?:\\mathclap)/,/^(?:\\mathcal)/,/^(?:\\mathbscr)/,/^(?:\\mathbit)/,/^(?:\\mathbin)/,/^(?:\\mathbf)/,/^(?:\\mathbcal)/,/^(?:\\mathbb)/,/^(?:\\Mapsto)/,/^(?:\\mapsto)/,/^(?:\\Mapsfrom)/,/^(?:\\map)/,/^(?:\\lvertneqq)/,/^(?:\\lvertneqq)/,/^(?:\\ltimes)/,/^(?:\\lt)/,/^(?:\\Lsh)/,/^(?:\\lq)/,/^(?:\\lozenge)/,/^(?:\\lowint)/,/^(?:\\looparrowright)/,/^(?:\\looparrowleft)/,/^(?:\\Longrightarrow)/,/^(?:\\longrightarrow)/,/^(?:\\longmapsto)/,/^(?:\\Longleftrightarrow)/,/^(?:\\longleftrightarrow)/,/^(?:\\Longleftarrow)/,/^(?:\\longleftarrow)/,/^(?:\\lnsim)/,/^(?:\\lneqq)/,/^(?:\\lneq)/,/^(?:\\lnapprox)/,/^(?:\\lmoustache)/,/^(?:\\lll)/,/^(?:\\Lleftarrow)/,/^(?:\\llangle)/,/^(?:\\ll)/,/^(?:\\lhd)/,/^(?:\\lfloor)/,/^(?:\\lesssim)/,/^(?:\\lessgtr)/,/^(?:\\lesseqqgtr)/,/^(?:\\lesseqgtr)/,/^(?:\\lessdot)/,/^(?:\\lessapprox)/,/^(?:\\less)/,/^(?:\\leqslant)/,/^(?:\\leqq)/,/^(?:\\leq)/,/^(?:\\lefttorightarrow)/,/^(?:\\leftthreetimes)/,/^(?:\\leftsquigarrow)/,/^(?:\\leftrightsquigarrow)/,/^(?:\\leftrightharpoons)/,/^(?:\\leftrightarrowtria\*)/,/^(?:\\leftrightarrows)/,/^(?:\\Leftrightarrow)/,/^(?:\\leftrightarrow)/,/^(?:\\leftleftarrows)/,/^(?:\\leftharpoonup)/,/^(?:\\leftharpoondown)/,/^(?:\\leftarrowtriangle)/,/^(?:\\leftarrowtail)/,/^(?:\\Leftarrow)/,/^(?:\\leftarrow)/,/^(?:\\left)/,/^(?:\\le)/,/^(?:\\ldots)/,/^(?:\\lceil)/,/^(?:\\lbrack)/,/^(?:\\lbrace)/,/^(?:\\langle)/,/^(?:\\lang)/,/^(?:\\Lambda)/,/^(?:\\lambda)/,/^(?:\\kernelcontraction)/,/^(?:\\Kappa)/,/^(?:\\kappa)/,/^(?:\\jmath)/,/^(?:\\itexnum)/,/^(?:\\Iota)/,/^(?:\\iota)/,/^(?:\\invamp)/,/^(?:\\intx)/,/^(?:\\intprodr)/,/^(?:\\intprod)/,/^(?:\\Intersection)/,/^(?:\\intersection)/,/^(?:\\interleave)/,/^(?:\\intercal)/,/^(?:\\integral)/,/^(?:\\intcup)/,/^(?:\\intcap)/,/^(?:\\intBar)/,/^(?:\\intbar)/,/^(?:\\int)/,/^(?:\\infty)/,/^(?:\\infinity)/,/^(?:\\inf)/,/^(?:\\in)/,/^(?:\\implies)/,/^(?:\\impliedby)/,/^(?:\\imath)/,/^(?:\\Im)/,/^(?:\\iint)/,/^(?:\\iiint)/,/^(?:\\iiiint)/,/^(?:\\iff)/,/^(?:\\hslash)/,/^(?:\\href)/,/^(?:\\hookrightarrow)/,/^(?:\\hookleftarrow)/,/^(?:\\hkswarow)/,/^(?:\\hksearow)/,/^(?:\\heartsuit)/,/^(?:\\hbar)/,/^(?:\\hat)/,/^(?:\\gvertneqq)/,/^(?:\\gvertneqq)/,/^(?:\\gtrsim)/,/^(?:\\gtrless)/,/^(?:\\gtreqqless)/,/^(?:\\gtreqless)/,/^(?:\\gtrdot)/,/^(?:\\gtrapprox)/,/^(?:\\gt)/,/^(?:\\greater)/,/^(?:\\gnsim)/,/^(?:\\gneqq)/,/^(?:\\gneq)/,/^(?:\\gnapprox)/,/^(?:\\gimel)/,/^(?:\\ggg)/,/^(?:\\gg)/,/^(?:\\geqslant)/,/^(?:\\geqq)/,/^(?:\\geq)/,/^(?:\\ge)/,/^(?:\\Gamma)/,/^(?:\\gamma)/,/^(?:\\frown)/,/^(?:\\frame)/,/^(?:\\frac)/,/^(?:\\forksnot)/,/^(?:\\forks)/,/^(?:\\forall)/,/^(?:\\flat)/,/^(?:\\fdiagovrdiag)/,/^(?:\\fdiagovnearrow)/,/^(?:\\fallingdotseq)/,/^(?:\\exists)/,/^(?:\\eth)/,/^(?:\\eth)/,/^(?:\\Eta)/,/^(?:\\eta)/,/^(?:\\equiv)/,/^(?:\\equalrows)/,/^(?:\\equalcols)/,/^(?:\\eqslantless)/,/^(?:\\eqslantgtr)/,/^(?:\\eqsim)/,/^(?:\\Eqqcolon)/,/^(?:\\eqqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\eqcolon)/,/^(?:\\eqcirc)/,/^(?:\\epsilon)/,/^(?:\\end\{Vmatrix\})/,/^(?:\\end\{vmatrix\})/,/^(?:\\endtoggle)/,/^(?:\\end\{split\})/,/^(?:\\end\{smallmatrix\})/,/^(?:\\end\{pmatrix\})/,/^(?:\\end\{matrix\})/,/^(?:\\end\{gathered\})/,/^(?:\\end\{cases\})/,/^(?:\\end\{Bmatrix\})/,/^(?:\\end\{bmatrix\})/,/^(?:\\end\{array\})/,/^(?:\\end\{aligned\})/,/^(?:\\emptyset)/,/^(?:\\empty)/,/^(?:\\embedsin)/,/^(?:\\ell)/,/^(?:\\duparr)/,/^(?:\\dualmap)/,/^(?:\\drbkarrow)/,/^(?:\\downuparrow)/,/^(?:\\downharpoonright)/,/^(?:\\downharpoonleft)/,/^(?:\\downdownarrows)/,/^(?:\\Downarrow)/,/^(?:\\downarrow)/,/^(?:\\doubleintegral)/,/^(?:\\doublebarwedge)/,/^(?:\\doublebarwedge)/,/^(?:\\dots)/,/^(?:\\dotplus)/,/^(?:\\dotminus)/,/^(?:\\doteqdot)/,/^(?:\\Doteq)/,/^(?:\\doteq)/,/^(?:\\dot)/,/^(?:\\divideontimes)/,/^(?:\\div)/,/^(?:\\displaystyle)/,/^(?:\\disjquant)/,/^(?:\\digamma)/,/^(?:\\diamondsuit)/,/^(?:\\Diamond)/,/^(?:\\diamond)/,/^(?:\\det|\\gcd|\\liminf|\\limsup|\\lim|\\max|\\Pr|\\sup)/,/^(?:\\Delta)/,/^(?:\\delta)/,/^(?:\\Del)/,/^(?:\\degree)/,/^(?:\\Ddownarrow)/,/^(?:\\ddotseq)/,/^(?:\\ddots)/,/^(?:\\ddot)/,/^(?:\\dddot)/,/^(?:\\dddot)/,/^(?:\\ddddot)/,/^(?:\\ddddot)/,/^(?:\\ddagger)/,/^(?:\\dblcolon)/,/^(?:\\dbkarow)/,/^(?:\\Dashv)/,/^(?:\\dashV)/,/^(?:\\dashv)/,/^(?:\\dashrightarrow)/,/^(?:\\dashleftarrow)/,/^(?:\\darr)/,/^(?:\\daleth)/,/^(?:\\dagger)/,/^(?:\\curvearrowright)/,/^(?:\\curvearrowleft)/,/^(?:\\curvearrowbotright)/,/^(?:\\curlywedge)/,/^(?:\\curlyvee)/,/^(?:\\curlyeqsucc)/,/^(?:\\curlyeqprec)/,/^(?:\\cupdot)/,/^(?:\\Cup)/,/^(?:\\cup)/,/^(?:\\coproduct)/,/^(?:\\coprod)/,/^(?:\\contourintegral)/,/^(?:\\conjquant)/,/^(?:\\conint)/,/^(?:\\cong)/,/^(?:\\complement)/,/^(?:\\colspan)/,/^(?:\\color)/,/^(?:\\Colonsim)/,/^(?:\\colonsim)/,/^(?:\\Coloneqq)/,/^(?:\\coloneqq)/,/^(?:\\Coloneq)/,/^(?:\\coloneq)/,/^(?:\\Colonapprox)/,/^(?:\\colonapprox)/,/^(?:\\Colon)/,/^(?:\\colon)/,/^(?:\\collines)/,/^(?:\\collayout)/,/^(?:\\colalign)/,/^(?:\\clubsuit)/,/^(?:\\closure)/,/^(?:\\circleddash)/,/^(?:\\circledcirc)/,/^(?:\\circledast)/,/^(?:\\circlearrowright)/,/^(?:\\circlearrowleft)/,/^(?:\\circeq)/,/^(?:\\circ)/,/^(?:\\choose)/,/^(?:\\chi)/,/^(?:\\check)/,/^(?:\\cellopts)/,/^(?:\\cdots)/,/^(?:\\cdotp)/,/^(?:\\cdot)/,/^(?:\\Cap)/,/^(?:\\cap)/,/^(?:\\bumpeqq)/,/^(?:\\Bumpeq)/,/^(?:\\bumpeq)/,/^(?:\\bullet)/,/^(?:\\btimes)/,/^(?:\\boxtimes)/,/^(?:\\boxplus)/,/^(?:\\boxminus)/,/^(?:\\boxed)/,/^(?:\\boxdot)/,/^(?:\\boxdiag)/,/^(?:\\boxcircle)/,/^(?:\\boxbslash)/,/^(?:\\boxast)/,/^(?:\\Box)/,/^(?:\\bowtie)/,/^(?:\\bottom)/,/^(?:\\bot)/,/^(?:\\boldsymbol)/,/^(?:\\blacktriangleright)/,/^(?:\\blacktriangleleft)/,/^(?:\\blacktriangledown)/,/^(?:\\blacktriangle)/,/^(?:\\blacksquare)/,/^(?:\\blacklozenge)/,/^(?:\\bkarow)/,/^(?:\\binom)/,/^(?:\\bigwedge)/,/^(?:\\bigvee)/,/^(?:\\biguplus)/,/^(?:\\bigtriangleup)/,/^(?:\\bigtriangledown)/,/^(?:\\bigtimes)/,/^(?:\\bigstar)/,/^(?:\\bigsqcup)/,/^(?:\\bigsqcap)/,/^(?:\\Bigr)/,/^(?:\\bigr)/,/^(?:\\bigotimes)/,/^(?:\\bigoplus)/,/^(?:\\bigodot)/,/^(?:\\Bigl)/,/^(?:\\bigl)/,/^(?:\\biginterleave)/,/^(?:\\Biggr)/,/^(?:\\biggr)/,/^(?:\\Biggl)/,/^(?:\\biggl)/,/^(?:\\Bigg)/,/^(?:\\bigg)/,/^(?:\\bigcupdot)/,/^(?:\\bigcup)/,/^(?:\\bigcirc)/,/^(?:\\bigcap)/,/^(?:\\Big)/,/^(?:\\big)/,/^(?:\\bgcolor)/,/^(?:\\between)/,/^(?:\\beth)/,/^(?:\\Beta)/,/^(?:\\beta)/,/^(?:\\begin\{Vmatrix\})/,/^(?:\\begin\{vmatrix\})/,/^(?:\\begintoggle)/,/^(?:\\begin\{split\})/,/^(?:\\begin\{smallmatrix\})/,/^(?:\\begin\{pmatrix\})/,/^(?:\\begin\{matrix\})/,/^(?:\\begin\{gathered\})/,/^(?:\\begin\{cases\})/,/^(?:\\begin\{Bmatrix\})/,/^(?:\\begin\{bmatrix\})/,/^(?:\\begin\{array\})/,/^(?:\\begin\{aligned\})/,/^(?:\\because)/,/^(?:\\BbbPi)/,/^(?:\\barwedge)/,/^(?:\\bar)/,/^(?:\\backslash)/,/^(?:\\backsimeq)/,/^(?:\\backsim)/,/^(?:\\backprime)/,/^(?:\\backepsilon)/,/^(?:\\atop)/,/^(?:\\asymp)/,/^(?:\\ast)/,/^(?:\\arrayopts)/,/^(?:\\array)/,/^(?:\\arccos|\\arcsin|\\arctan|\\arg|\\cosh|\\cos|\\coth|\\cot|\\csc|\\deg|\\dim|\\exp|\\hom|\\ker|\\lg|\\ln|\\log|\\sec|\\sinh|\\sin|\\tanh|\\tan)/,/^(?:\\approxeq)/,/^(?:\\approx)/,/^(?:\\angle)/,/^(?:\\amalg)/,/^(?:\\Alpha)/,/^(?:\\alpha)/,/^(?:\\align)/,/^(?:\\aleph)/,/^(?:[\u0041-\u005A])/,/^(?:[\u0391-\u03A1\u03A3\u03A4\u03A6-\u03A9])/,/^(?:[\u0061-\u007A\u0131\u0237])/,/^(?:[\u03B1-\u03C1\u03C3-\u03C9\u03D1\u03D5\u03D6\u03F0\u03F1\u03F4\u03F5])/,/^(?:\\adots)/,/^(?:\\AA)/,/^(?:[\u00F0\u03C2\u03D0\u03D2\u03DA-\u03DD\u03E0\u03E1\u0428\u0608\u0627-\u063A\u2102\u210A-\u210D\u210F-\u2113\u2115\u2118-\u211D\u2124\u2127\u2128\u212B-\u212D\u212F-\u2131\u2133-\u2138\u213C\u213D\u213F\u2205]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB\uDEF0\uDEF1]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDFCB])/,/^(?:\\\$)/,/^(?:\\\})/,/^(?:\\\|)/,/^(?:\\\{)/,/^(?:\\;)/,/^(?:\\:)/,/^(?:\\,)/,/^(?:\\&)/,/^(?:\\%)/,/^(?:\\#)/,/^(?:\\!)/,/^(?:-)/,/^(?:'''')/,/^(?:''')/,/^(?:'')/,/^(?:')/,/^(?:[\uD800-\uDBFF])/,/^(?:[\uDC00-\uDFFF])/,/^(?:.)/], -conditions: {"MATH0":{"rules":[14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883],"inclusive":true},"MATH1":{"rules":[14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883],"inclusive":true},"OPTARG":{"rules":[13,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883],"inclusive":true},"DOCUMENT":{"rules":[1,2,3,4,5],"inclusive":false},"TRYOPTARG":{"rules":[6,7],"inclusive":false},"TEXTOPTARG":{"rules":[8,9],"inclusive":false},"TEXTARG":{"rules":[10,11,12],"inclusive":false},"INITIAL":{"rules":[0,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883],"inclusive":true}} -}); -return lexer; -})(); -parser.lexer = lexer; -function Parser () { - this.yy = {}; -} -Parser.prototype = parser;parser.Parser = Parser; -return new Parser; -})(); -//////////////////////////////////////////////////////////////////////////////// -// Export the public API to commonJS programs. -//////////////////////////////////////////////////////////////////////////////// -if (typeof require !== "undefined" && typeof exports !== "undefined") { - exports.setDOMParser = function (aDOMParser) { - TeXZilla.setDOMParser(aDOMParser); - }; - exports.setXMLSerializer = function (aXMLSerializer) { - TeXZilla.setXMLSerializer(aXMLSerializer); - }; - exports.setSafeMode = function (aEnable) { - TeXZilla.setSafeMode(aEnable); - }; - exports.setItexIdentifierMode = function (aEnable) { - TeXZilla.setItexIdentifierMode(aEnable); - }; - exports.getTeXSource = function () { - return TeXZilla.getTeXSource.apply(TeXZilla, arguments); - }; - exports.toMathMLString = function () { - return TeXZilla.toMathMLString.apply(TeXZilla, arguments); - }; - exports.toMathML = function () { - return TeXZilla.toMathML.apply(TeXZilla, arguments); - }; - exports.toImage = function () { - return TeXZilla.toImage.apply(TeXZilla, arguments); - }; - exports.filterString = function () { - return TeXZilla.filterString.apply(TeXZilla, arguments); - }; - exports.filterElement = function () { - return TeXZilla.filterElement.apply(TeXZilla, arguments); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// Export the command-line API to commonJS programs. -//////////////////////////////////////////////////////////////////////////////// -if (typeof require !== "undefined") { - - // FIXME: This tries to work with slimerjs, phantomjs and nodejs. Ideally, - // we should have a standard commonJS interface. - // https://github.com/fred-wang/TeXZilla/issues/6 - - var exitCommonJS = function (aStatus) { - if (typeof process !== "undefined") { - process.exit(aStatus); - } else if (typeof slimer !== "undefined") { - slimer.exit(aStatus); - } else if (typeof phantom !== "undefined") { - phantom.exit(aStatus); - } - }; - - var usage = function () { - // Display the usage information. - console.log("\nUsage:\n"); - console.log("commonjs TeXZilla.js [help]"); - console.log(" Print this help message.\n"); - console.log("commonjs TeXZilla.js parser aTeX [aDisplay] [aRTL] [aThrowExceptionOnError]"); - console.log(" Print TeXZilla.toMathMLString(aTeX, aDisplay, aRTL, aThrowExceptionOnError)"); - console.log(" The interpretation of arguments and the default values are the same.\n"); - console.log("commonjs TeXZilla.js webserver [port] [safe] [itexId]"); - console.log(" Start a Web server on the specified port (default:3141)"); - console.log(" See the TeXZilla wiki for details.\n"); - console.log("cat input | commonjs TeXZilla.js streamfilter [safe] [itexId] > output"); - console.log(" Make TeXZilla behaves as a stream filter. The TeX fragments are"); - console.log(" converted into MathML."); - console.log(" See the TeXZilla wiki for details.\n"); - console.log(" where commonjs is slimerjs, nodejs or phantomjs."); - }; - - var setParamValue = function (aParam, aKey, aString) { - // Set the param value from the string value. - if (aKey === "tex") { - aParam[aKey] = aString; - } else if (aKey === "display" || aKey === "rtl" || aKey === "exception" || - aKey === "safe" || aKey === "itexId") { - aParam[aKey] = (aString === "true"); - } - }; - - var getMathMLString = function (aParam) { - // Call the TeXZilla parser with the specified parameters and - // return the MathML output. - return TeXZilla.toMathMLString(aParam.tex, aParam.display, - aParam.rtl, aParam.exception); - }; - - var getParametersFromURL = function (aURL) { - // Get the param values from the GET URL. - var param, query, vars, i, pair, key, value; - param = {}; - query = aURL.split("?")[1]; - if (query) { - vars = query.split("&"); - for (i = 0; i < vars.length; i++) { - pair = vars[i].split("="); - key = decodeURIComponent(pair[0]).toLowerCase(); - value = decodeURIComponent(pair[1]); - setParamValue(param, key, value); - } - } - return param; - }; - - var getParametersFromPOSTData = function (aPOSTData) { - // Get the param values from the POST JSON data. - var param = {}, json = JSON.parse(aPOSTData), key; - for (key in json) { - setParamValue(param, key, json[key]); - } - return param; - }; - - var getServerResponseFromParam = function (aParam) { - // Get the JSON data to send back. - var data = { tex: aParam.tex }; - try { - data.mathml = getMathMLString(aParam); - data.exception = null; - } catch (e) { - data.exception = e.message; - } - return JSON.stringify(data); - }; - - var webserverListener = function (aRequest, aResponse) { - // Listener for the "webserver" module (phantomjs, slimerjs). - var param = {}, json = {}, response; - if (aRequest.method === "GET") { - param = getParametersFromURL(aRequest.url); - } else if (aRequest.method === "POST") { - param = getParametersFromPOSTData(aRequest.post); - } - if (param.tex !== undefined) { - json = getServerResponseFromParam(param); - } - response = JSON.stringify(json); - aResponse.statusCode = 200; - aResponse.setHeader("Content-Type", "application/json"); - aResponse.write(response); - aResponse.close(); - }; - - var httpListener = function (aRequest, aResponse) { - // Listener for the "http" module (nodejs). - var param = {}, json = {}, response, body = ""; - aRequest.setEncoding("utf8"); - aRequest.on("data", function (aChunk) { - body += aChunk; - }); - aRequest.on("end", function () { - aResponse.writeHead(200, {"Content-Type": ""}); - if (aRequest.method === "GET") { - param = getParametersFromURL(aRequest.url); - } else if (aRequest.method === "POST") { - param = getParametersFromPOSTData(body); - } - if (param.tex !== undefined) { - json = getServerResponseFromParam(param); - } - response = JSON.stringify(json); - aResponse.writeHead(200, { "Content-Type": "application/json" }); - aResponse.write(response); - aResponse.end(); - }); - }; - - var startWebServer = function (aPort) - { - try { - require("webserver").create().listen(aPort, webserverListener); - } catch (e) { - require("http").createServer(httpListener).listen(aPort); - } - console.log("Web server started on http://localhost:" + aPort); - } - - var main = function (aArgs, aStdinContent) { - // Main command line function. - var param = {}; - if (aArgs.length >= 3 && aArgs[1] === "parser") { - // Parse the string and print the output. - setParamValue(param, "tex", aArgs[2]); - setParamValue(param, "display", aArgs[3]); - setParamValue(param, "rtl", aArgs[4]); - setParamValue(param, "exception", aArgs[5]); - try { - console.log(getMathMLString(param)); - exitCommonJS(0); - } catch (e) { - console.log(e); - exitCommonJS(1); - } - } else if (aArgs.length >= 2 && aArgs[1] === "webserver") { - setParamValue(param, "safe", aArgs[2]); - TeXZilla.setSafeMode(param.safe); - setParamValue(param, "itexId", aArgs[3]); - TeXZilla.setItexIdentifierMode(param.itexId); - // Run a Web server. - try { - startWebServer(aArgs.length >= 3 ? parseInt(aArgs[2], 10) : 3141); - } catch (e) { - console.log(e); - exitCommonJS(1); - } - } else if (aArgs.length >= 2 && aArgs[1] === "streamfilter") { - setParamValue(param, "safe", aArgs[2]); - TeXZilla.setSafeMode(param.safe); - setParamValue(param, "itexId", aArgs[3]); - TeXZilla.setItexIdentifierMode(param.itexId); - if (typeof process !== "undefined") { - var stdinContent = ""; - process.stdin.resume(); - process.stdin.setEncoding("utf-8"); - process.stdin.on("data", function(aData) { stdinContent += aData; }); - process.stdin.on("end", function() { - console.log(TeXZilla.filterString(stdinContent, true)); - exitCommonJS(0); - }); - } else { - // FIXME: Slimerjs does not seem to support stdin. - console.log(TeXZilla. - filterString(require("system").stdin.read(), true)); - exitCommonJS(0); - } - } else { - usage(); - exitCommonJS(0); - } - }; - - if (typeof exports === "undefined" || - (typeof module !== "undefined" && require.main === module)) { - // Process the command line arguments, the stdin content and execute the - // main program. - if (typeof process !== "undefined") { - main(process.argv.slice(1)); - } else { - main(require("system").args); - } - } -} diff --git a/utils/buildDocs.js b/utils/buildDocs.js deleted file mode 100644 index 3c1d0b38..00000000 --- a/utils/buildDocs.js +++ /dev/null @@ -1,92 +0,0 @@ -const fs = require("fs") // Node.js file system -const hurmetMark = require("./hurmetMark.cjs") -const temml = require('./temml.cjs'); -const katex = require('./katex.min.js'); -const TeXZilla = require("./TeXZilla.js"); - -// Build supported.html. -let supported = fs.readFileSync('./docs/supported.md').toString('utf8') -// convert Markdown to HTML -supported = hurmetMark.hmd.md2html(supported, true) -fs.writeFileSync('./site/docs/en/supported.html', supported) - -let table = fs.readFileSync('./docs/support_table.md').toString('utf8') -// convert Markdown to HTML -table = hurmetMark.hmd.md2html(table, true) -table = table.replace(/\(Not supported\)/g, `Not supported`) -fs.writeFileSync('./site/docs/en/support_table.html', table) - -let admin = fs.readFileSync('./docs/administration.md').toString('utf8') -// convert Markdown to HTML -admin = hurmetMark.hmd.md2html(admin, true) -fs.writeFileSync('./site/docs/en/administration.html', admin) - -// helper function for comparison page. -const arrayOfRegExMatches = (regex, text) => { - if (regex.constructor !== RegExp) { throw new Error('not RegExp') } - const result = [] - let match = null - // eslint-disable-next-line no-cond-assign - while (match = regex.exec(text)) { - result.push({ - value: match[0], - index: match.index, - lastindex: match.index + match[0].length - }) - } - return result -} - -// Comparison page -const temmlRegEx = /₮{1,2}[^₮]+₮{1,2}/g -let comp = fs.readFileSync('./docs/comparison.html').toString('utf8') -let macros = {}; -let matches = arrayOfRegExMatches(temmlRegEx, comp) -for (let i = matches.length - 1; i >= 0; i--) { - const displayMode = matches[i].value.charAt(1) === "₮" - let tex = displayMode - ? matches[i].value.slice(2, -2).trim() - : matches[i].value.slice(1, -1).trim(); - tex = tex.replace(/</g, "<").replace(/>/g, ">") - let math = temml.renderToString(tex, { displayMode, trust: true, macros }); - if (math.indexOf("#b22222") > -1) { - math = 'Not supported' - } - comp = comp.slice(0, matches[i].index) + math + comp.slice(matches[i].lastindex); -} - -const katexRegEx = /₭{1,2}[^₭]+₭{1,2}/g -macros = {}; -matches = arrayOfRegExMatches(katexRegEx, comp) -for (let i = matches.length - 1; i >= 0; i--) { - const displayMode = matches[i].value.charAt(1) === "₭" - let tex = displayMode - ? matches[i].value.slice(2, -2).trim() - : matches[i].value.slice(1, -1).trim(); - tex = tex.replace(/</g, "<").replace(/>/g, ">") - let math = katex.renderToString( - tex, - { displayMode, output: "mathml", trust: true, strict: false, throwOnError: false, macros } - ); - if (math.indexOf("#cc0000") > -1) { - math = 'Not supported' - } - comp = comp.slice(0, matches[i].index) + math + comp.slice(matches[i].lastindex); -} - -const texzillaRegEx = /₸{1,2}[^₸]+₸{1,2}/g -matches = arrayOfRegExMatches(texzillaRegEx, comp) -for (let i = matches.length - 1; i >= 0; i--) { - const displayMode = matches[i].value.charAt(1) === "₸" - let tex = displayMode - ? matches[i].value.slice(2, -2).trim() - : matches[i].value.slice(1, -1).trim(); - tex = tex.replace(/</g, "<").replace(/>/g, ">") - let math = TeXZilla.toMathMLString(tex) - if (math.indexOf("error") > -1) { - math = 'Not supported' - } - comp = comp.slice(0, matches[i].index) + math + comp.slice(matches[i].lastindex); -} - -fs.writeFileSync('./site/docs/en/comparison.html', comp) diff --git a/utils/buildTests.js b/utils/buildTests.js deleted file mode 100644 index ade5f3e4..00000000 --- a/utils/buildTests.js +++ /dev/null @@ -1,23 +0,0 @@ -const fs = require("fs") // Node.js file system -const hurmetMark = require("./hurmetMark.cjs") - -let katexTests = fs.readFileSync('./test/katex-tests.md').toString('utf8') -// convert Markdown to HTML -katexTests = hurmetMark.hmd.md2html(katexTests, true) -fs.writeFileSync('./site/tests/katex-tests.html', katexTests) - -let mhchemTests = fs.readFileSync('./test/mhchem-tests.md').toString('utf8') -mhchemTests = hurmetMark.hmd.md2html(mhchemTests, true) -fs.writeFileSync('./site/tests/mhchem-tests.html', mhchemTests) - -let mozillaTests = fs.readFileSync('./test/mozilla-tests.md').toString('utf8') -mozillaTests = hurmetMark.hmd.md2html(mozillaTests, true) -fs.writeFileSync('./site/tests/mozilla-tests.html', mozillaTests) - -let wikiTests = fs.readFileSync('./test/wiki-tests.md').toString('utf8') -wikiTests = hurmetMark.hmd.md2html(wikiTests, true) -fs.writeFileSync('./site/tests/wiki-tests.html', wikiTests) - -let latexmlTests = fs.readFileSync('./test/LaTeXML-tests.md').toString('utf8') -latexmlTests = hurmetMark.hmd.md2html(latexmlTests, true) -fs.writeFileSync('./site/tests/LaTeXML-tests.html', latexmlTests) diff --git a/utils/copyfiles.js b/utils/copyfiles.js deleted file mode 100644 index e1b4b4c1..00000000 --- a/utils/copyfiles.js +++ /dev/null @@ -1,56 +0,0 @@ -const fs = require('fs'); - -// Populate the `dist` folder. - -fs.copyFile('site/assets/Temml-Local.css', 'dist/Temml-Local.css', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/Temml-Latin-Modern.css', 'dist/Temml-Latin-Modern.css', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/Temml-Asana.css', 'dist/Temml-Asana.css', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/Temml-STIX2.css', 'dist/Temml-STIX2.css', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/Temml-XITS.css', 'dist/Temml-XITS.css', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/temml.min.js', 'dist/temml.min.js', (err) => { - if (err) { throw err } -}) - -fs.copyFile('test/temml.js', 'dist/temml.js', (err) => { - if (err) { throw err } -}) - -fs.copyFile('utils/temml.cjs', 'dist/temml.cjs', (err) => { - if (err) { throw err } -}) - -fs.copyFile('utils/temml.mjs', 'dist/temml.mjs', (err) => { - if (err) { throw err } -}) - -fs.copyFile('test/temmlPostProcess.js', 'dist/temmlPostProcess.js', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/Temml.woff2', 'dist/Temml.woff2', (err) => { - if (err) { throw err } -}) - -fs.copyFile('site/assets/mhchem.min.js', 'contrib/mhchem/mhchem.min.js', (err) => { - if (err) { throw err } -}) - -fs.copyFile('contrib/auto-render/test/auto-render.js', 'contrib/auto-render/dist/auto-render.js', -(err) => { - if (err) { throw err } -}) diff --git a/utils/hurmetMark.cjs b/utils/hurmetMark.cjs deleted file mode 100644 index 06b67c89..00000000 --- a/utils/hurmetMark.cjs +++ /dev/null @@ -1,1160 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -/** - * # hurmetMark.js - * - * Hurmet.app uses a version of Markdown as a plain text file format. - * This version of Markdown is stricter in some ways than CommonMark or - * Gruber's original Markdown. So the parser can be considerably simplified. - * md2ast() returns an AST that matches the memory structure of a Hurmet.app document. - * - * ## Ways in which this syntax is more strict than Markdown. - * - * 1. Emphasis: _emphasis_ only. Asterisks do not create standard emphasis. - * 2. Strong emphasis: **strong emphasis** only. Underlines do not create strong emphasis. - * 3. Code blocks must be fenced by triple backticks. - * Indented text does not indicate a code block. - * 4. A blank line must precede the beginning of a list, even a nested list. - * 5. A hard line break is indicated when a line ends with "\". Double spaces do not count. - * 6. "Shortcut" reference links [ref] are not recognized. - * See below for implicit reference links. - * - * ## Extensions - * - * 1. Hurmet inline calculation is delimited ¢`…`. - * Hurmet display calculation is fenced ¢¢\n … \n¢¢. - * 2. LaTeX inline math is delimited $`…`. - * LaTeX display math is fenced $$\n … \n$$. - * 3. ~~strikethrough~~ - * 4. Pipe tables as per GFM. - * 5. Grid tables as per reStructuredText, with two exceptions: - * a. The top border contains ":" characters to indicate column justtification. - * b. Top & left borders contain "*" characters to indicate the location - * of a table column or rows boundary. - * 6. Implicit reference links [title][] and implicit reference images ![alt][] - * ⋮ - * [alt]: path - * Reference images can have captions and directives. Format is: - * ![alt text][ref]{caption} or [alt][]{caption} - * ⋮ - * [ref]: filepath - * {.class #id width=number} - * 7. Table directives. They are placed on the line after the table. The format is: - * {.class #id width=num widths="num1 num2 …"} - * 8. Lists that allow the user to pick list ordering. - * 1. → 1. 2. 3. etc. - * A. → A. B. C. etc. (future) - * a) → (a) (b) (c) etc. (future) - * 9. Definition lists, per Pandoc. (future) - * 10. Blurbs set an attribute on a block element, as in Markua. - * Blurbs are denoted by a symbol in the left margin. - * Subsequent indented text blocks are children of the blurb. - * Blurb symbols: - * i> indented block - * C> Centered block - * H> print header element,
- * I> Information admonition (future) - * W> Warning admonition (future) - * T> Tip admonition (future) - * c> Comment admonition (future) - * 11. [^1] is a reference to a footnote. (future) - * [^1]: The body of the footnote is deferred, similar to reference links. - * 12. [#1] is a reference to a citation. (future) - * [#1]: The body of the citation is deferred, similar to reference links. - * 13. Line blocks begin with "| ", as per Pandoc. (future) - * - * hurmetMark.js copyright (c) 2021 Ron Kok - * - * This file has been adapted (and heavily modified) from Simple-Markdown. - * Simple-Markdown copyright (c) 2014-2019 Khan Academy & Aria Buckles. - * - * Portions of Simple-Markdown were adapted from marked.js copyright (c) 2011-2014 - * Christopher Jeffrey (https://github.com/chjj/). - * - * LICENSE (MIT): - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -const CR_NEWLINE_R = /\r\n?/g; -const TAB_R = /\t/g; -const FORMFEED_R = /\f/g; -const CLASS_R = /(?:^| )\.([a-z-]+)(?: |$)/; -const WIDTH_R = /(?:^| )width="?([\d.a-z]+"?)(?: |$)/; -const COL_WIDTHS_R = /(?:^| )colWidths="([^"]*)"/; -const ID_R = /(?:^| )#([a-z-]+)(?: |$)/; - -// Turn various whitespace into easy-to-process whitespace -const preprocess = function(source) { - return source.replace(CR_NEWLINE_R, "\n").replace(FORMFEED_R, "").replace(TAB_R, " "); -}; - -// Creates a match function for an inline scoped element from a regex -const inlineRegex = function(regex) { - const match = function(source, state) { - return state.inline ? regex.exec(source) : null - }; - match.regex = regex; - return match; -}; - -// Creates a match function for a block scoped element from a regex -const blockRegex = function(regex) { - const match = function(source, state) { - return state.inline ? null : regex.exec(source) - }; - match.regex = regex; - return match; -}; - -// Creates a match function from a regex, ignoring block/inline scope -const anyScopeRegex = function(regex) { - const match = function(source, state) { - return regex.exec(source); - }; - match.regex = regex; - return match; -}; - -const UNESCAPE_URL_R = /\\([^0-9A-Za-z\s])/g; -const unescapeUrl = function(rawUrlString) { - return rawUrlString.replace(UNESCAPE_URL_R, "$1"); -}; - -const parseList = (str, state) => { - const items = str.replace(LIST_BLOCK_END_R, "\n").match(LIST_ITEM_R); - const isTight = state.inHtml && !/\n\n(?!$)/.test(str); - const itemContent = items.map(function(item, i) { - // We need to see how far indented this item is: - const prefixCapture = LIST_ITEM_PREFIX_R.exec(item); - const space = prefixCapture ? prefixCapture[0].length : 0; - // And then we construct a regex to "unindent" the subsequent - // lines of the items by that amount: - const spaceRegex = new RegExp("^ {1," + space + "}", "gm"); - - // Before processing the item, we need a couple things - const content = item - // remove indents on trailing lines: - .replace(spaceRegex, "") - // remove the bullet: - .replace(LIST_ITEM_PREFIX_R, ""); - - // backup our state for restoration afterwards. We're going to - // want to set state._list to true, and state.inline depending - // on our list's looseness. - const oldStateInline = state.inline; - const oldStateList = state._list; - state._list = true; - const oldStateTightness = state.isTight; - state.isTight = isTight; - - // Parse the list item - state.inline = isTight; - const adjustedContent = content.replace(LIST_ITEM_END_R, ""); - const result = isTight - ? { type: "list_item", content: parseInline(adjustedContent, state) } - : { type: "list_item", content: parse(adjustedContent, state) }; - - // Restore our state before returning - state.inline = oldStateInline; - state._list = oldStateList; - state.isTight = oldStateTightness; - return result; - }); - - return itemContent -}; - -const TABLES = (function() { - const TABLE_ROW_SEPARATOR_TRIM = /^ *\| *| *\| *$/g; - const TABLE_RIGHT_ALIGN = /^[-=]+:$/; - const TABLE_CENTER_ALIGN = /^:[-=]+:$/; - - const parseTableAlign = function(source) { - // Inspect ":" characters to set column justification. - // Return class names that specify center or right justification on specific columns. - source = source.replace(TABLE_ROW_SEPARATOR_TRIM, ""); - const alignArr = source.trim().split(/[|+*]/); - let alignStr = ""; - for (let i = 0; i < alignArr.length; i++) { - alignStr += TABLE_CENTER_ALIGN.test(alignArr[i]) - ? ` c${String(i + 1)}c` - : (TABLE_RIGHT_ALIGN.test(alignArr[i]) - ? ` c${String(i + 1)}r` - : ""); - } - return alignStr.trim() - }; - - const tableDirectives = (directives, align) => { - // Get CSS class, ID, and column widths, if any. - if (!directives && align === "") { return ["", "", null] } - const userDefClass = CLASS_R.exec(directives); - let myClass = (userDefClass) ? userDefClass[1] : ""; - if (align.length > 0) { myClass += (myClass.length > 0 ? " " : "") + align; } - const userDefId = ID_R.exec(directives); - const myID = (userDefId) ? userDefId[1] : ""; - const colWidthMatch = COL_WIDTHS_R.exec(directives); - const colWidths = (colWidthMatch) ? colWidthMatch[1].split(" ") : null; - return [myClass, myID, colWidths] - }; - - const parsePipeTableRow = function(source, parse, state, colWidths, inHeader) { - const prevInTable = state.inTable; - state.inTable = true; - const tableRow = parse(source.trim(), state); - consolidate(tableRow); - state.inTable = prevInTable; - - const row = { - type: "table_row", - content: [] - }; - let j = -1; - tableRow.forEach(function(node, i) { - if (node.type === "tableSeparator") { - if (i !== tableRow.length - 1) { // Filter out the row's last table separator - // Create a new cell - j += 1; - row.content.push({ - "type": inHeader ? "table_header" : "table_cell", - "attrs": { - "colspan": 1, - "rowspan": 1, - "colwidth": (colWidths) ? [Number(colWidths[j])] : null, - "background": null - }, - content: (state.inHtml ? [] : [{ "type": "paragraph", "content": [] }]) - }); - } - } else if (state.inHtml) { - // For direct to HTML, write the inline contents directly into the element. - // row cell content text - row.content[j].content.push(node); - } else { - // Hurmet.app table cells always contain a paragraph. - // row cell paragraph content text - row.content[j].content[0].content.push(node); - } - }); - - return row; - }; - - const parsePipeTable = function() { - return function(capture, state) { - state.inline = true; - const align = parseTableAlign(capture[2]); - const [myClass, myID, colWidths] = tableDirectives(capture[4], align); - const table = { - type: "table", - attrs: {}, - content: [] - }; - if (myID) { table.attrs.id = myID; } - if (myClass) { table.attrs.class = myClass; } - table.content.push(parsePipeTableRow(capture[1], parse, state, colWidths, true)); - const tableBody = capture[3].trim().split("\n"); - tableBody.forEach(row => { - table.content.push(parsePipeTableRow(row, parse, state, colWidths, false)); - }); - state.inline = false; - return table - }; - }; - - const headerRegEx = /^\+:?=/ - - const parseGridTable = function() { - return function(capture, state) { - const topBorder = capture[2]; - const align = parseTableAlign(topBorder.slice(1)); - const [myClass, myID, colWidths] = tableDirectives(capture[3], align); - const lines = capture[1].slice(0, -1).split("\n"); - - // Does the grid table contain a line separating header from table body? - let headerExists = false; - let headerSepLine = lines.length + 10; - for (let i = 0; i < lines.length; i++) { - if (headerRegEx.test(lines[i])) { - headerExists = true; - headerSepLine = i; - break - } - } - - // Read the top & left borders to find the locations of the cell corners. - const xCorners = [0]; - for (let j = 1; j < topBorder.length; j++) { - const ch = topBorder.charAt(j); - // A "*" character indicates a column border, but the top row - // contains a merged cell, so the column border does not extend - // all the way to the top of the table. - if (ch === "+" || ch === "*") { xCorners.push(j); } - } - const yCorners = [0]; - for (let i = 1; i < lines.length; i++) { - const ch = lines[i].charAt(0); - if (ch === "+" || ch === "*") { yCorners.push(i); } - } - - const numCols = xCorners.length - 1; - const numRows = yCorners.length - 1; - const gridTable = []; - - // Create default rows and cells. They may be merged later. - for (let i = 0; i < numRows; i++) { - const row = new Array(numCols); - for (let j = 0; j < numCols; j++) { row[j] = { rowspan: 1 }; } - gridTable.push(row); - } - - for (let i = 0; i < numRows; i++) { - const row = gridTable[i]; - // Determine the actual rowspan and colspan of each cell. - for (let j = 0; j < numCols; j++) { - const cell = row[j]; - if (cell.rowspan === 0) { continue } - cell.colspan = 1; - const lastTextRow = lines[yCorners[i + 1] - 1]; - for (let k = j + 1; k < xCorners.length; k++) { - if (lastTextRow.charAt(xCorners[k]) === "|") { break } - cell.colspan += 1; - row[k].rowspan = 0; - } - for (let k = i + 1; k < yCorners.length; k++) { - const ch = lines[yCorners[k]].charAt(xCorners[j] + 1); - if (ch === "-" || ch === "=") { break } - cell.rowspan += 1; - for (let jj = 0; jj < cell.colspan; jj++) { - gridTable[k][j + jj].rowspan = 0; - } - } - // Now that we know the cell extents, get the cell contents. - const xStart = xCorners[j] + 2; - const xEnd = xCorners[j + cell.colspan] - 1; - const yStart = yCorners[i] + 1; - const yEnd = yCorners[i + cell.rowspan]; - let str = ""; - for (let ii = yStart; ii < yEnd; ii++) { - str += lines[ii].slice(xStart, xEnd).replace(/ +$/, "") + "\n"; - } - cell.blob = str.slice(0, -1).replace(/^\n+/, ""); - - cell.inHeader = (headerExists && yStart < headerSepLine); - - if (colWidths) { - // Set an attribute used by ProseMirror. - let cellWidth = 0; - for (let k = 0; k < cell.colspan; k++) { - cellWidth += Number(colWidths[j + k]); - } - cell.width = cellWidth; - } - } - } - - const table = { - type: "table", - attrs: {}, - content: [] - }; - if (myID) { table.attrs.id = myID; } - if (myClass) { table.attrs.class = myClass; } - for (let i = 0; i < numRows; i++) { - table.content.push({ type: "table_row", content: [] } ); - for (let j = 0; j < numCols; j++) { - if (gridTable[i][j].rowspan === 0) { continue } - const cell = gridTable[i][j]; - state.inline = false; - let content = state.inHtml && cell.blob.indexOf("```") === -1 && !/\n\n/.test(cell.blob.replace(/\n+$/g, "")) - ? parseInline(cell.blob, state) // Write inline content directly into each - : parse(cell.blob, state); // Hurmet.app has a paragraph in each cell. - if (content.length === 1 && content[0].type === "null") { - content = state.inHtml - ? [{ type: "text", text: "" }] - : [{ type: "paragraph", content: [] }]; - } - table.content[i].content.push({ - "type": cell.inHeader ? "table_header" : "table_cell", - "attrs": { - "colspan": cell.colspan, - "rowspan": cell.rowspan, - "colwidth": (colWidths) ? [cell.width] : null, - "background": null - }, - content: content - }); - } - } - state.inline = false; - return table - }; - }; - - return { - parsePipeTable: parsePipeTable(), - PIPE_TABLE_REGEX: /^(\|.+)\n\|([-:]+[-| :]*)\n((?:\|.*(?:\n|$))*)(?:\{([^\n}]+)\}\n)?\n*/, - parseGridTable: parseGridTable(), - GRID_TABLE_REGEX: /^((\+(?:[-:*=]+\+)+)\n(?:[+|*][^\n]+[+|]\n)+)(?:\{([^\n}]+)\}\n)?\n*/ - }; -})(); - -const LINK_INSIDE = "(?:\\[[^\\]]*\\]|[^\\[\\]]|\\](?=[^\\[]*\\]))*"; -const LINK_HREF_AND_TITLE = - "\\s*?(?:\\s+['\"]([\\s\\S]*?)['\"])?\\s*"; - -const linkIndex = marks => { - for (let i = 0; i < marks.length; i++) { - if (marks[i].type === "link") { return i } - } -}; - -const parseRef = function(capture, state, refNode) { - let ref = capture[2] ? capture[2] : capture[1]; - ref = ref.replace(/\s+/g, " "); - - // We store information about previously seen defs on - // state._defs (_ to deconflict with client-defined - // state). If the def for this reflink/refimage has - // already been seen, we can use its target/source - // and title here: - if (state._defs && state._defs[ref]) { - const def = state._defs[ref]; - if (refNode.type === "image") { - refNode.attrs.src = def.target; - refNode.attrs.width = null; - } else { - // refNode is a link - refNode.attrs.href = def.target; - } - } - - // In case we haven't seen our def yet (or if someone - // overwrites that def later on), we add this node - // to the list of ref nodes for that def. Then, when - // we find the def, we can modify this link/image AST - // node :). - state._refs = state._refs || {}; - state._refs[ref] = state._refs[ref] || []; - state._refs[ref].push(refNode); - - return refNode; -}; - -const parseTextMark = (capture, state, mark) => { - const text = parseInline(capture, state); - if (Array.isArray(text) && text.length === 0) { return text } - consolidate(text); - if (text[0].marks) { - text[0].marks.push({ type: mark }); - } else { - text[0].marks = [{ type: mark }]; - } - return text -}; - -const BLOCK_HTML = /^ *(?:<(head|h[1-6]|p|pre|script|style|table)[\s>][\s\S]*?(?:<\/\1>[^\n]*\n)|[^\n]*\n|<\/?(?:body|details|(div|input|label)(?: [^>]+)?|!DOCTYPE[a-z ]*|html[a-z ="]*|br|dl(?: class="[a-z-]+")?|li|main[a-z\- ="]*|nav|ol|ul(?: [^>]+)?)\/?>[^\n]*?(?:\n|$))/ -const divType = { C: "centered_div", H: "header", "i": "indented_div" }; - -// Rules must be applied in a specific order, so use a Map instead of an object. -const rules = new Map(); -rules.set("html", { - isLeaf: true, - match: blockRegex(BLOCK_HTML), - parse: function(capture, state) { - if (!state.inHtml) { return null } - return { type: "html", text: capture[0] } - } -}); -rules.set("heading", { - isLeaf: false, - match: blockRegex(/^ *(#{1,6})([^\n]+?)#* *(?:\n *)+\n/), - parse: function(capture, state) { - return { - attrs: { level: capture[1].length }, - content: parseInline(capture[2].trim(), state) - }; - } -}); -rules.set("dt", { // description term - isLeaf: false, - match: blockRegex(/^(([^\n]*)\n)(?=
|\n:)/), - parse: function(capture, state) { - return { content: parseInline(capture[2].trim(), state) } - } -}); -rules.set("horizontal_rule", { - isLeaf: true, - match: blockRegex(/^( *[-*_]){3,} *(?:\n *)+\n/), - parse: function(capture, parse, state) { - return { type: "horizontal_rule" }; - } -}); -rules.set("lheading", { - isLeaf: false, - match: blockRegex(/^([^\n]+)\n *(=|-){3,} *(?:\n *)+\n/), - parse: function(capture, parse, state) { - return { - type: "heading", - level: capture[2] === '=' ? 1 : 2, - content: parseInline(parse, capture[1]) - }; - } -}); -rules.set("fence", { - isLeaf: true, - match: blockRegex(/^(`{3,}) *(?:(\S+) *)?\n([\s\S]+?)\n?\1 *(?:\n *)+\n/), - parse: function(capture, state) { - return { - type: "code_block", -// lang: capture[2] || undefined, - content: [{ type: "text", text: capture[3] }] - }; - } -}); -rules.set("blockquote", { - isLeaf: false, - match: blockRegex(/^( *>[^\n]+(\n[^\n]+)*\n*)+\n{2,}/), - parse: function(capture, state) { - const content = capture[0].replace(/^ *> ?/gm, ""); - return { content: parse(content, state) }; - } -}); -rules.set("ordered_list", { - isLeaf: false, - match: blockRegex(/^( {0,3})(\d{1,9}\.) [\s\S]+?(?:\n{2,}(?! )(?!\1(?:\d{1,9}\.) )\n*|\s*$)/), - parse: function(capture, state) { - const start = Number(capture[2].trim()); - return { attrs: { order: start }, content: parseList(capture[0], state, capture[1]) } - } -}); -rules.set("bullet_list", { - isLeaf: false, - match: blockRegex(/^( {0,3})([*+-]) [\s\S]+?(?:\n{2,}(?! )(?!\1(?:[*+-]) )\n*|\s*$)/), - parse: function(capture, state) { - return { content: parseList(capture[0], state, capture[1]) } - } -}); -rules.set("dd", { // description details - isLeaf: false, - match: blockRegex(/^:( +)[\s\S]+?(?:\n{2,}(?! |:)(?!\1)\n*|\s*$)/), - parse: function(capture, state) { - let div = " " + capture[0].slice(1); - const indent = 1 + capture[1].length; - const spaceRegex = new RegExp("^ {" + indent + "," + indent + "}", "gm"); - div = div.replace(spaceRegex, ""); // remove indents on trailing lines: - return { content: parse(div, state) }; - } -}); -rules.set("special_div", { - isLeaf: false, - match: blockRegex(/^(C|H|i)>( {1,})[\s\S]+?(?:\n{2,}(?! {2,2}\2)\n*|\s*$)/), - parse: function(capture, state) { - const type = divType[capture[1]]; - let div = " " + capture[0].slice(2); - const indent = 2 + capture[2].length; - const spaceRegex = new RegExp("^ {" + indent + "," + indent + "}", "gm"); - div = div.replace(spaceRegex, ""); // remove indents on trailing lines: - return { type, content: parse(div, state) }; - } -}); -rules.set("def", { - // TODO(aria): This will match without a blank line before the next - // block element, which is inconsistent with most of the rest of - // simple-markdown. - isLeaf: true, - match: blockRegex(/^\[([^\]]+)\]: *]*)>? *\n(?:\{([^\n}]*)\}\n)?/), - parse: function(capture, state) { - const def = capture[1].replace(/\s+/g, " "); - const target = capture[2]; - const directives = capture[3] || ""; - const attrs = {}; - - // Look for previous links/images using this def - // If any links/images using this def have already been declared, - // they will have added themselves to the state._refs[def] list - // (_ to deconflict with client-defined state). We look through - // that list of reflinks for this def, and modify those AST nodes - // with our newly found information now. - // Sorry :(. - if (state._refs && state._refs[def]) { - // `refNode` can be a link or an image - state._refs[def].forEach(function(refNode) { - if (refNode.type === "image") { - refNode.attrs.src = target; - if (directives) { - const matchClass = CLASS_R.exec(directives); - if (matchClass) { - refNode.attrs.class = matchClass[1]; - attrs.class = matchClass[1]; - } - const matchWidth = WIDTH_R.exec(directives); - if (matchWidth) { - refNode.attrs.width = matchWidth[1]; - attrs.width = matchWidth[1]; - } - const matchID = ID_R.exec(directives); - if (matchID) { - refNode.attrs.id = matchID[1]; - attrs.id = matchID[1]; - } - } - } else { - refNode.attrs.href = target; - } - }); - } - - // Add this def to our map of defs for any future links/images - // In case we haven't found any or all of the refs referring to - // this def yet, we add our def to the table of known defs, so - // that future reflinks can modify themselves appropriately with - // this information. - state._defs = state._defs || {}; - state._defs[def] = { target, attrs }; - - // return the relevant parsed information - // for debugging only. - return { - def: def, - target: target, - directives: directives - }; - } -}); -rules.set("pipeTable", { - isLeaf: false, - match: blockRegex(TABLES.PIPE_TABLE_REGEX), - parse: TABLES.parsePipeTable -}); -rules.set("gridTable", { - isLeaf: false, - match: blockRegex(TABLES.GRID_TABLE_REGEX), - parse: TABLES.parseGridTable -}); -rules.set("newline", { - isLeaf: true, - match: blockRegex(/^(?:\n *)*\n/), - parse: function() { return { type: "null" } } -}); -rules.set("paragraph", { - isLeaf: false, - match: blockRegex(/^((?:[^\n]|\n(?! *\n))+)(?:\n *)+\n/), - parse: function(capture, state) { - return { content: parseInline(capture[1], state) }; - } -}); -rules.set("escape", { - // We don't allow escaping numbers, letters, or spaces here so that - // backslashes used in plain text still get rendered. But allowing - // escaping anything else provides a very flexible escape mechanism, - // regardless of how this grammar is extended. - isLeaf: true, - match: inlineRegex(/^\\([^0-9A-Za-z\s])/), - parse: function(capture, state) { - return { - type: "text", - text: capture[1] - }; - } -}); -rules.set("tableSeparator", { - isLeaf: true, - match: function(source, state) { - if (!state.inTable) { - return null; - } - return /^ *\| */.exec(source); - }, - parse: function() { - return { type: "tableSeparator" }; - } -}); -rules.set("calculation", { - isLeaf: true, - match: anyScopeRegex(/^(?:¢(`+)([\s\S]*?[^`])\1(?!`)|¢¢\n((?:\\[\s\S]|[^\\])+?)\n¢¢)/), - parse: function(capture, state) { - if (capture[2]) { - let entry = capture[2].trim(); - if (!/^function/.test(entry) && entry.indexOf("``") === -1) { - entry = entry.replace(/\n/g, " "); - } - return { content: "", attrs: { entry } } - } else { - const entry = capture[3].trim(); - return { content: "", attrs: { entry, displayMode: true } } - } - } -}); -rules.set("tex", { - isLeaf: true, - match: anyScopeRegex(/^(?:\$(`+)([\s\S]*?[^`])\1(?!`)|\$\$\n?((?:\\[\s\S]|[^\\])+?)\n?\$\$)/), - parse: function(capture, state) { - if (capture[2]) { - const tex = capture[2].trim().replace(/\n/g, " "); - return { content: "", attrs: { tex } } - } else { - return { content: "", attrs: { tex: capture[3].trim(), displayMode: true } } - } - } -}); -rules.set("link", { - isLeaf: true, - match: inlineRegex( - new RegExp("^\\[(" + LINK_INSIDE + ")\\]\\(" + LINK_HREF_AND_TITLE + "\\)") - ), - parse: function(capture, state) { - const textNode = parseTextMark(capture[1], state, "link" )[0]; - const i = linkIndex(textNode.marks); - textNode.marks[i].attrs = { href: unescapeUrl(capture[2]) }; - return textNode - } -}); -rules.set("image", { - isLeaf: true, - match: inlineRegex( - new RegExp("^!\\[(" + LINK_INSIDE + ")\\]\\(" + LINK_HREF_AND_TITLE + "\\)") - ), - parse: function(capture, state) { - return { attrs: { alt: capture[1], src: unescapeUrl(capture[2]) } } - } -}); -rules.set("reflink", { - isLeaf: true, - match: inlineRegex(/^\[((?:(?:\\[\s\S]|[^\\])+?)?)\]\[([^\]]*)\]/), - parse: function(capture, state) { - const textNode = parseTextMark(capture[1], state, "link" )[0]; - const i = linkIndex(textNode.marks); - textNode.marks[i].attrs = { href: null }; - if (capture[2]) { - textNode.marks[i].attrs.title = capture[2]; - } - parseRef(capture, state, textNode.marks[i]); - return textNode - } -}); -rules.set("refimage", { - isLeaf: true, - match: inlineRegex(/^!\[((?:(?:\\[\s\S]|[^\\])+?)?)\]\[([^\]]*)\]/), - parse: function(capture, state) { - return parseRef(capture, state, { - type: "image", - attrs: { alt: capture[1] } - }); - } -}); -rules.set("code", { - isLeaf: true, - match: inlineRegex(/^(`+)([\s\S]*?[^`])\1(?!`)/), - parse: function(capture, state) { - const text = capture[2].trim(); - return [{ type: "text", text, marks: [{ type: "code" }] }] -/* state.inCode = true; - const code = parseTextMark(text, state, "code" ); - state.inCode = false; - console.log(code) - return code */ - } -}); -rules.set("em", { - isLeaf: true, - match: inlineRegex(/^_((?:\\[\s\S]|[^\\])+?)_/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "em" ) - } -}); -rules.set("strong", { - isLeaf: true, - match: inlineRegex(/^\*\*(?=\S)((?:\\[\s\S]|\*(?!\*)|[^\s*\\]|\s(?!\*\*))+?)\*\*/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "strong" ) - } -}); -rules.set("strikethru", { - isLeaf: true, - match: inlineRegex(/^~~(?=\S)((?:\\[\s\S]|~(?!~)|[^\s~\\]|\s(?!~~))+?)~~/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "strikethru" ) - } -}); -rules.set("superscript", { - isLeaf: true, - match: inlineRegex(/^([\s\S]*?)<\/sup>/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "superscript" ) - } -}); -rules.set("subscript", { - isLeaf: true, - match: inlineRegex(/^([\s\S]*?)<\/sub>/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "subscript" ) - } -}); -rules.set("underline", { - isLeaf: true, - match: inlineRegex(/^([\s\S]*?)<\/u>/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "underline" ) - } -}); -rules.set("highlight", { - isLeaf: true, - match: inlineRegex(/^([\s\S]*?)<\/mark>/), - parse: function(capture, state) { - return parseTextMark(capture[1], state, "highlight" ) - } -}); -rules.set("hard_break", { - isLeaf: true, - match: anyScopeRegex(/^\\\n/), - parse: function() { return { text: "\n" } } -}); -rules.set("inline_break", { - isLeaf: true, - match: anyScopeRegex(/^
/), - parse: function() { return { type: "hard_break", text: "\n" } } -}); -rules.set("span", { - isLeaf: true, - match: inlineRegex(/^ { - if (!state.inline) { source += "\n\n"; } - source = preprocess(source); - const result = []; - while (source) { - // store the best match and its rule: - let capture = null; - let ruleName = null; - let rule = null; - for (const [currRuleName, currRule] of rules) { - if (state.inCode && doNotEscape.includes(currRuleName)) { continue } - capture = currRule.match(source, state); - if (capture) { - rule = currRule; - ruleName = currRuleName; - break - } - } - const parsed = rule.parse(capture, state); - if (Array.isArray(parsed)) { - Array.prototype.push.apply(result, parsed); - } else { - if (parsed.type == null) { parsed.type = ruleName; } - result.push(parsed); - } - source = source.substring(capture[0].length); - } - return result -}; - - - -/** - * Parse some content with the parser `parse`, with state.inline - * set to true. Useful for block elements; not generally necessary - * to be used by inline elements (where state.inline is already true. - */ -const parseInline = function(content, state) { - const isCurrentlyInline = state.inline || false; - state.inline = true; - const result = parse(content, state); - state.inline = isCurrentlyInline; - return result; -}; - - -// recognize a `*` `-`, `+`, `1.`, `2.`... list bullet -const LIST_BULLET = "(?:[*+-]|\\d+\\.)"; -// recognize the start of a list item: -// leading space plus a bullet plus a space (` * `) -const LIST_ITEM_PREFIX = "( *)(" + LIST_BULLET + ") +"; -const LIST_ITEM_PREFIX_R = new RegExp("^" + LIST_ITEM_PREFIX); -// recognize an individual list item: -// * hi -// this is part of the same item -// -// as is this, which is a new paragraph in the same item -// -// * but this is not part of the same item -const LIST_ITEM_R = new RegExp( - LIST_ITEM_PREFIX + "[^\\n]*(?:\\n" + "(?!\\1" + LIST_BULLET + " )[^\\n]*)*(\n|$)", - "gm" -); -const BLOCK_END_R = /\n{2,}$/; -// recognize the end of a paragraph block inside a list item: -// two or more newlines at end end of the item -const LIST_BLOCK_END_R = BLOCK_END_R; -const LIST_ITEM_END_R = / *\n+$/; - -const ignore = ["def", "newline", "null"]; - -const consolidate = arr => { - if (Array.isArray(arr) && arr.length > 0) { - // Group any text nodes together into a single string output. - for (let i = arr.length - 1; i > 0; i--) { - const node = arr[i]; - const prevNode = arr[i - 1]; - if (node.type === 'text' && prevNode.type === 'text' && - !node.marks && !prevNode.marks) { - prevNode.text += node.text; - arr.splice(i, 1); - } else if (ignore.includes(node.type)) { - arr.splice(i, 1); - } else if (!rules.has(node.type) || !rules.get(node.type).isLeaf) { - consolidate(node.content); - } - } - - if (!rules.has(arr[0].type) || !rules.get(arr[0].type).isLeaf) { - consolidate(arr[0].content); - } - } -}; - -const md2ast = (md, inHtml = false) => { - const ast = parse(md, { inline: false, inHtml }); - consolidate(ast); - return ast -}; - -// const hurmet = require("./hurmet.js"); -const temml = require('./temml.cjs'); - -const sanitizeUrl = function(url) { - if (url == null) { - return null; - } - try { - const prot = decodeURIComponent(url) - .replace(/[^A-Za-z0-9/:]/g, "") - .toLowerCase(); - if ( - prot.indexOf("javascript:") === 0 || - prot.indexOf("vbscript:") === 0 || - prot.indexOf("data:") === 0 - ) { - return null; - } - } catch (e) { - // decodeURIComponent sometimes throws a URIError - // See `decodeURIComponent('a%AFc');` - // http://stackoverflow.com/questions/9064536/javascript-decodeuricomponent-malformed-uri-exception - return null; - } - return url; -}; - -const SANITIZE_TEXT_R = /[<>&"']/g; -const SANITIZE_TEXT_CODES = { - "<": "<", - ">": ">", - "&": "&", - '"': """, - "'": "'", - "/": "/", - "`": "`" -}; -const sanitizeText = function(text /* : Attr */) { - return String(text).replace(SANITIZE_TEXT_R, function(chr) { - return SANITIZE_TEXT_CODES[chr]; - }); -}; - -const htmlTag = (tagName, content, attributes = {}, isClosed = true) => { - let attributeString = ""; - for (const attr in attributes) { - if (Object.prototype.hasOwnProperty.call(attributes, attr)) { - const attribute = attributes[attr]; - // Removes falsey attributes - if (attribute) { - attributeString += " " + sanitizeText(attr) + '="' + sanitizeText(attribute) + '"'; - } - } - } - - const unclosedTag = "<" + tagName + attributeString + ">"; - - if (isClosed) { - return unclosedTag + content + ""; - } else { - return unclosedTag; - } -}; - -const tagName = { - em: "em", - strong: "strong", - code: "code", - strikethru: "del", - subscript: "sub", - superscript: "sup", - underline: "u", - highlight: "mark" -}; - -const nodes = { - html(node) { return node.text }, - heading(node) { - const text = output(node.content); - let tag = "h" + node.attrs.level; - tag = htmlTag(tag, text); - // Add id so others can link to it. - tag = tag.slice(0, 3) + " id='" + text.toLowerCase().replace(/,/g, "").replace(/\s+/g, '-') + "'" + tag.slice(3); - return tag + "\n" - }, - paragraph(node) { return htmlTag("p", output(node.content)) + "\n" }, - blockquote(node) {return htmlTag("blockquote", output(node.content)) }, - code_block(node) { - return htmlTag("pre", htmlTag("code", sanitizeText(node.content[0].text))) - }, - hard_break(node) { return "
" }, - def(node) { return "" }, - newline(node) { return "\n" }, - horizontal_rule(node) { return "
\n" }, - ordered_list(node) { - const attributes = node.attrs.order !== 1 ? { start: node.attrs.order } : undefined; - return htmlTag("ol", output(node.content), attributes) + "\n" - }, - bullet_list(node) { return htmlTag("ul", output(node.content)) + "\n" }, - list_item(node) { return htmlTag("li", output(node.content)) + "\n" }, - table(node) { return htmlTag("table", output(node.content), node.attrs) + "\n" }, - table_row(node) { return htmlTag("tr", output(node.content)) + "\n" }, - table_header(node) { - const attributes = {}; - if (node.attrs.colspan !== 1) { attributes.colspan = node.attrs.colspan; } - if (node.attrs.rowspan !== 1) { attributes.rowspan = node.attrs.rowspan; } - if (node.attrs.colwidth !== null && !isNaN(node.attrs.colwidth) ) { - attributes.style = `width: ${node.attrs.colwidth}px` - } - return htmlTag("th", output(node.content), attributes) + "\n" - }, - table_cell(node) { - const attributes = {}; - if (node.attrs.colspan !== 1) { attributes.colspan = node.attrs.colspan; } - if (node.attrs.rowspan !== 1) { attributes.rowspan = node.attrs.rowspan; } - if (node.attrs.colwidth !== null && !isNaN(node.attrs.colwidth) ) { - attributes.style = `width: ${node.attrs.colwidth}px` - } - return htmlTag("td", output(node.content), attributes) - }, - link(node) { - const attributes = { href: sanitizeUrl(node.attrs.href), title: node.attrs.title }; - return htmlTag("a", output(node.content), attributes); - }, - image(node) { - const attributes = { src: sanitizeUrl(node.attrs.src), alt: node.attrs.alt }; - if (node.attrs.class) { attributes.class = node.attrs.class; } - if (node.attrs.id) { attributes.id = node.attrs.id; } - if (node.attrs.width) { attributes.width = node.attrs.width; } - return htmlTag("img", "", attributes, false); - }, -/* calculation(node) { - const tex = hurmet.parse(node.attrs.entry); - return htmlTag("span", "", { class: "tex", "data-tex": tex }) - },*/ - tex(node) { - return temml.renderToString( - node.attrs.tex, - { trust: true, displayMode: (node.attrs.displayMode || false) } - ) - }, - indented_div(node) { return htmlTag("div", output(node.content), { class: 'indented' }) }, - centered_div(node) { - return htmlTag("div", output(node.content), { class: 'centered' } ) - }, - dt(node) { - let text = output(node.content); - let tag = htmlTag("dt", text); - // Add id so others can link to it. - const pos = text.indexOf("("); - if (pos > -1) { text = text.slice(0, pos).replace("_", "-"); } - tag = tag.slice(0, 3) + " id='" + text.toLowerCase().replace(/\s+/g, '-') + "'" + tag.slice(3); - return tag + "\n" - }, - dd(node) { return htmlTag("dd", output(node.content)) + "\n" }, - text(node) { - const text = sanitizeText(node.text); - if (!node.marks) { - return text - } else { - let span = text; - for (const mark of node.marks) { - if (mark.type === "link") { - let tag = `" + span + ""; - } else { - const tag = tagName[mark.type]; - span = `<${tag}>${span}`; - } - } - return span - } - } -}; - -const output = (ast) => { - // Return HTML. - let html = ""; - if (Array.isArray(ast)) { - for (let i = 0; i < ast.length; i++) { - html += output(ast[i]); - } - } else if (ast.type !== "null") { - html += nodes[ast.type](ast); - } - return html -}; - -const md2html = (md, inHtml = false) => { - const ast = md2ast(md, inHtml); - return output(ast) -}; - -const hmd = { - md2ast, - md2html -}; - -exports.hmd = hmd; diff --git a/utils/insertPlugins.js b/utils/insertPlugins.js deleted file mode 100644 index 423016e7..00000000 --- a/utils/insertPlugins.js +++ /dev/null @@ -1,22 +0,0 @@ -// Embed extensions into the cjs and mjs version of Temml. - -const fs = require("fs") // Node.js file system - -// Get the temml.cjs and mjs code -let cjs = fs.readFileSync('./utils/temml.cjs').toString('utf8') -let mjs = fs.readFileSync('./utils/temml.mjs').toString('utf8') - -// Get the extension macros -const regex = /temml\.__/g; -const mhchem = fs.readFileSync('./contrib/mhchem/mhchem.js').toString('utf8').replace(regex, "") -const texvc = fs.readFileSync('./contrib/texvc/texvc.js').toString('utf8').replace(regex, "") -const physics = fs.readFileSync('./contrib/physics/physics.js').toString('utf8').replace(regex, "") - -// Insert the extension macros into temml.cjs and temml.mjs -let pos = cjs.indexOf("⦵") + 6 -cjs = cjs.slice(0, pos) + "\n" + mhchem + "\n" + texvc + "\n" + physics + "\n" + cjs.slice(pos + 1) -fs.writeFileSync('./utils/temml.cjs', cjs) - -pos = mjs.indexOf("⦵") + 6 -mjs = mjs.slice(0, pos) + "\n" + mhchem + "\n" + texvc + "\n" + physics + "\n" + mjs.slice(pos + 1) -fs.writeFileSync('./utils/temml.mjs', mjs) diff --git a/utils/katex.min.js b/utils/katex.min.js deleted file mode 100644 index dec14608..00000000 --- a/utils/katex.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.katex=t():e.katex=t()}("undefined"!=typeof self?self:this,(function(){return function(){"use strict";var e={d:function(t,r){for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},t={};e.d(t,{default:function(){return Zn}});var r=function e(t,r){this.position=void 0;var n,a="KaTeX parse error: "+t,i=r&&r.loc;if(i&&i.start<=i.end){var o=i.lexer.input;n=i.start;var s=i.end;n===o.length?a+=" at end of input: ":a+=" at position "+(n+1)+": ";var l=o.slice(n,s).replace(/[^]/g,"$&\u0332");a+=(n>15?"\u2026"+o.slice(n-15,n):o.slice(0,n))+l+(s+15":">","<":"<",'"':""","'":"'"},o=/[&><"']/g;var s=function e(t){return"ordgroup"===t.type||"color"===t.type?1===t.body.length?e(t.body[0]):t:"font"===t.type?e(t.body):t},l={contains:function(e,t){return-1!==e.indexOf(t)},deflt:function(e,t){return void 0===e?t:e},escape:function(e){return String(e).replace(o,(function(e){return i[e]}))},hyphenate:function(e){return e.replace(a,"-$1").toLowerCase()},getBaseElem:s,isCharacterBox:function(e){var t=s(e);return"mathord"===t.type||"textord"===t.type||"atom"===t.type},protocolFromUrl:function(e){var t=/^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(e);return null!=t?t[1]:"_relative"}},h=function(){function e(e){this.displayMode=void 0,this.output=void 0,this.leqno=void 0,this.fleqn=void 0,this.throwOnError=void 0,this.errorColor=void 0,this.macros=void 0,this.minRuleThickness=void 0,this.colorIsTextColor=void 0,this.strict=void 0,this.trust=void 0,this.maxSize=void 0,this.maxExpand=void 0,this.globalGroup=void 0,e=e||{},this.displayMode=l.deflt(e.displayMode,!1),this.output=l.deflt(e.output,"htmlAndMathml"),this.leqno=l.deflt(e.leqno,!1),this.fleqn=l.deflt(e.fleqn,!1),this.throwOnError=l.deflt(e.throwOnError,!0),this.errorColor=l.deflt(e.errorColor,"#cc0000"),this.macros=e.macros||{},this.minRuleThickness=Math.max(0,l.deflt(e.minRuleThickness,0)),this.colorIsTextColor=l.deflt(e.colorIsTextColor,!1),this.strict=l.deflt(e.strict,"warn"),this.trust=l.deflt(e.trust,!1),this.maxSize=Math.max(0,l.deflt(e.maxSize,1/0)),this.maxExpand=Math.max(0,l.deflt(e.maxExpand,1e3)),this.globalGroup=l.deflt(e.globalGroup,!1)}var t=e.prototype;return t.reportNonstrict=function(e,t,r){var a=this.strict;if("function"==typeof a&&(a=a(e,t,r)),a&&"ignore"!==a){if(!0===a||"error"===a)throw new n("LaTeX-incompatible input and strict mode is set to 'error': "+t+" ["+e+"]",r);"warn"===a?"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+t+" ["+e+"]"):"undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+a+"': "+t+" ["+e+"]")}},t.useStrictBehavior=function(e,t,r){var n=this.strict;if("function"==typeof n)try{n=n(e,t,r)}catch(e){n="error"}return!(!n||"ignore"===n)&&(!0===n||"error"===n||("warn"===n?("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+t+" ["+e+"]"),!1):("undefined"!=typeof console&&console.warn("LaTeX-incompatible input and strict mode is set to unrecognized '"+n+"': "+t+" ["+e+"]"),!1)))},t.isTrusted=function(e){e.url&&!e.protocol&&(e.protocol=l.protocolFromUrl(e.url));var t="function"==typeof this.trust?this.trust(e):this.trust;return Boolean(t)},e}(),m=function(){function e(e,t,r){this.id=void 0,this.size=void 0,this.cramped=void 0,this.id=e,this.size=t,this.cramped=r}var t=e.prototype;return t.sup=function(){return c[u[this.id]]},t.sub=function(){return c[p[this.id]]},t.fracNum=function(){return c[d[this.id]]},t.fracDen=function(){return c[f[this.id]]},t.cramp=function(){return c[g[this.id]]},t.text=function(){return c[v[this.id]]},t.isTight=function(){return this.size>=2},e}(),c=[new m(0,0,!1),new m(1,0,!0),new m(2,1,!1),new m(3,1,!0),new m(4,2,!1),new m(5,2,!0),new m(6,3,!1),new m(7,3,!0)],u=[4,5,4,5,6,7,6,7],p=[5,5,5,5,7,7,7,7],d=[2,3,4,5,6,7,6,7],f=[3,3,5,5,7,7,7,7],g=[1,1,3,3,5,5,7,7],v=[0,1,2,3,2,3,2,3],b={DISPLAY:c[0],TEXT:c[2],SCRIPT:c[4],SCRIPTSCRIPT:c[6]},y=[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"armenian",blocks:[[1328,1423]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}];var x=[];function w(e){for(var t=0;t=x[t]&&e<=x[t+1])return!0;return!1}y.forEach((function(e){return e.blocks.forEach((function(e){return x.push.apply(x,e)}))}));var k=80,S={doubleleftarrow:"M262 157\nl10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3\n 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28\n 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5\nc2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5\n 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87\n-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7\n-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z\nm8 0v40h399730v-40zm0 194v40h399730v-40z",doublerightarrow:"M399738 392l\n-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5\n 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88\n-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68\n-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18\n-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782\nc-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3\n-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z",leftarrow:"M400000 241H110l3-3c68.7-52.7 113.7-120\n 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8\n-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247\nc-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208\n 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3\n 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202\n l-3-3h399890zM100 241v40h399900v-40z",leftbrace:"M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117\n-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7\n 5-6 9-10 13-.7 1-7.3 1-20 1H6z",leftbraceunder:"M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13\n 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688\n 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7\n-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z",leftgroup:"M400000 80\nH435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0\n 435 0h399565z",leftgroupunder:"M400000 262\nH435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219\n 435 219h399565z",leftharpoon:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3\n-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5\n-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7\n-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z",leftharpoonplus:"M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5\n 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3\n-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7\n-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z\nm0 0v40h400000v-40z",leftharpoondown:"M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333\n 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5\n 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667\n-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z",leftharpoondownplus:"M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12\n 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7\n-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0\nv40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z",lefthook:"M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5\n-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3\n-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21\n 71.5 23h399859zM103 281v-40h399897v40z",leftlinesegment:"M40 281 V428 H0 V94 H40 V241 H400000 v40z\nM40 281 V428 H0 V94 H40 V241 H400000 v40z",leftmapsto:"M40 281 V448H0V74H40V241H400000v40z\nM40 281 V448H0V74H40V241H400000v40z",leftToFrom:"M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23\n-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8\nc28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3\n 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z",longequal:"M0 50 h400000 v40H0z m0 194h40000v40H0z\nM0 50 h400000 v40H0z m0 194h40000v40H0z",midbrace:"M200428 334\nc-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14\n-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7\n 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11\n 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z",midbraceunder:"M199572 214\nc100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14\n 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3\n 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0\n-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z",oiintSize1:"M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6\n-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z\nm368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8\n60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z",oiintSize2:"M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8\n-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z\nm502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2\nc0 110 84 276 504 276s502.4-166 502.4-276z",oiiintSize1:"M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6\n-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z\nm525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0\n85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z",oiiintSize2:"M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8\n-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z\nm770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1\nc0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z",rightarrow:"M0 241v40h399891c-47.3 35.3-84 78-110 128\n-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20\n 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7\n 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85\n-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n 151.7 139 205zm0 0v40h399900v-40z",rightbrace:"M400000 542l\n-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5\ns-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1\nc124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z",rightbraceunder:"M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3\n 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237\n-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z",rightgroup:"M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0\n 3-1 3-3v-38c-76-158-257-219-435-219H0z",rightgroupunder:"M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18\n 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z",rightharpoon:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3\n-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2\n-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58\n 69.2 92 94.5zm0 0v40h399900v-40z",rightharpoonplus:"M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11\n-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7\n 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z\nm0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z",rightharpoondown:"M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8\n 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5\n-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95\n-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z",rightharpoondownplus:"M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8\n 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3\n 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3\n-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z\nm0-194v40h400000v-40zm0 0v40h400000v-40z",righthook:"M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3\n 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0\n-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21\n 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z",rightlinesegment:"M399960 241 V94 h40 V428 h-40 V281 H0 v-40z\nM399960 241 V94 h40 V428 h-40 V281 H0 v-40z",rightToFrom:"M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23\n 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32\n-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142\n-167z M100 147v40h399900v-40zM0 341v40h399900v-40z",twoheadleftarrow:"M0 167c68 40\n 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69\n-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3\n-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19\n-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101\n 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z",twoheadrightarrow:"M400000 167\nc-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3\n 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42\n 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333\n-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70\n 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z",tilde1:"M200 55.538c-77 0-168 73.953-177 73.953-3 0-7\n-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0\n 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0\n 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128\n-68.267.847-113-73.952-191-73.952z",tilde2:"M344 55.266c-142 0-300.638 81.316-311.5 86.418\n-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9\n 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114\nc1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751\n 181.476 676 181.476c-149 0-189-126.21-332-126.21z",tilde3:"M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457\n-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0\n 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697\n 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696\n -338 0-409-156.573-744-156.573z",tilde4:"M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345\n-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409\n 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9\n 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409\n -175.236-744-175.236z",vec:"M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5\n3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11\n10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63\n-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1\n-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59\nH213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359\nc-16-25.333-24-45-24-59z",widehat1:"M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22\nc-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z",widehat2:"M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat3:"M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widehat4:"M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10\n-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z",widecheck1:"M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1,\n-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z",widecheck2:"M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck3:"M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",widecheck4:"M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10,\n-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z",baraboveleftarrow:"M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202\nc4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5\nc-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130\ns-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47\n121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6\ns2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11\nc0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z\nM100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z",rightarrowabovebar:"M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32\n-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0\n13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39\n-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5\n-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5\n-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67\n151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z",baraboveshortleftharpoon:"M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17\nc2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21\nc-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40\nc-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z\nM0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z",rightharpoonaboveshortbar:"M0,241 l0,40c399126,0,399993,0,399993,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z",shortbaraboveleftharpoon:"M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11\nc1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9,\n1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7,\n-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z\nM93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z",shortrightharpoonabovebar:"M53,241l0,40c398570,0,399437,0,399437,0\nc4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,\n-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6\nc-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z\nM500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z"},M=function(){function e(e){this.children=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.children=e,this.classes=[],this.height=0,this.depth=0,this.maxFontSize=0,this.style={}}var t=e.prototype;return t.hasClass=function(e){return l.contains(this.classes,e)},t.toNode=function(){for(var e=document.createDocumentFragment(),t=0;t"},q=function(){function e(e,t,r,n){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.width=void 0,this.maxFontSize=void 0,this.style=void 0,A.call(this,e,r,n),this.children=t||[]}var t=e.prototype;return t.setAttribute=function(e,t){this.attributes[e]=t},t.hasClass=function(e){return l.contains(this.classes,e)},t.toNode=function(){return T.call(this,"span")},t.toMarkup=function(){return B.call(this,"span")},e}(),N=function(){function e(e,t,r,n){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,A.call(this,t,n),this.children=r||[],this.setAttribute("href",e)}var t=e.prototype;return t.setAttribute=function(e,t){this.attributes[e]=t},t.hasClass=function(e){return l.contains(this.classes,e)},t.toNode=function(){return T.call(this,"a")},t.toMarkup=function(){return B.call(this,"a")},e}(),C=function(){function e(e,t,r){this.src=void 0,this.alt=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.alt=t,this.src=e,this.classes=["mord"],this.style=r}var t=e.prototype;return t.hasClass=function(e){return l.contains(this.classes,e)},t.toNode=function(){var e=document.createElement("img");for(var t in e.src=this.src,e.alt=this.alt,e.className="mord",this.style)this.style.hasOwnProperty(t)&&(e.style[t]=this.style[t]);return e},t.toMarkup=function(){var e=""+this.alt+"=a[0]&&e<=a[1])return r.name}return null}(this.text.charCodeAt(0));l&&this.classes.push(l+"_fallback"),/[\xee\xef\xed\xec]/.test(this.text)&&(this.text=I[this.text])}var t=e.prototype;return t.hasClass=function(e){return l.contains(this.classes,e)},t.toNode=function(){var e=document.createTextNode(this.text),t=null;for(var r in this.italic>0&&((t=document.createElement("span")).style.marginRight=this.italic+"em"),this.classes.length>0&&((t=t||document.createElement("span")).className=z(this.classes)),this.style)this.style.hasOwnProperty(r)&&((t=t||document.createElement("span")).style[r]=this.style[r]);return t?(t.appendChild(e),t):e},t.toMarkup=function(){var e=!1,t="0&&(r+="margin-right:"+this.italic+"em;"),this.style)this.style.hasOwnProperty(n)&&(r+=l.hyphenate(n)+":"+this.style[n]+";");r&&(e=!0,t+=' style="'+l.escape(r)+'"');var a=l.escape(this.text);return e?(t+=">",t+=a,t+="
"):a},e}(),O=function(){function e(e,t){this.children=void 0,this.attributes=void 0,this.children=e||[],this.attributes=t||{}}var t=e.prototype;return t.toNode=function(){var e=document.createElementNS("http://www.w3.org/2000/svg","svg");for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);for(var r=0;r":""},e}(),H=function(){function e(e){this.attributes=void 0,this.attributes=e||{}}var t=e.prototype;return t.toNode=function(){var e=document.createElementNS("http://www.w3.org/2000/svg","line");for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);return e},t.toMarkup=function(){var e="","\\gt",!0),_(j,Z,oe,"\u2208","\\in",!0),_(j,Z,oe,"\ue020","\\@not"),_(j,Z,oe,"\u2282","\\subset",!0),_(j,Z,oe,"\u2283","\\supset",!0),_(j,Z,oe,"\u2286","\\subseteq",!0),_(j,Z,oe,"\u2287","\\supseteq",!0),_(j,K,oe,"\u2288","\\nsubseteq",!0),_(j,K,oe,"\u2289","\\nsupseteq",!0),_(j,Z,oe,"\u22a8","\\models"),_(j,Z,oe,"\u2190","\\leftarrow",!0),_(j,Z,oe,"\u2264","\\le"),_(j,Z,oe,"\u2264","\\leq",!0),_(j,Z,oe,"<","\\lt",!0),_(j,Z,oe,"\u2192","\\rightarrow",!0),_(j,Z,oe,"\u2192","\\to"),_(j,K,oe,"\u2271","\\ngeq",!0),_(j,K,oe,"\u2270","\\nleq",!0),_(j,Z,se,"\xa0","\\ "),_(j,Z,se,"\xa0","\\space"),_(j,Z,se,"\xa0","\\nobreakspace"),_($,Z,se,"\xa0","\\ "),_($,Z,se,"\xa0"," "),_($,Z,se,"\xa0","\\space"),_($,Z,se,"\xa0","\\nobreakspace"),_(j,Z,se,null,"\\nobreak"),_(j,Z,se,null,"\\allowbreak"),_(j,Z,ie,",",","),_(j,Z,ie,";",";"),_(j,K,Q,"\u22bc","\\barwedge",!0),_(j,K,Q,"\u22bb","\\veebar",!0),_(j,Z,Q,"\u2299","\\odot",!0),_(j,Z,Q,"\u2295","\\oplus",!0),_(j,Z,Q,"\u2297","\\otimes",!0),_(j,Z,le,"\u2202","\\partial",!0),_(j,Z,Q,"\u2298","\\oslash",!0),_(j,K,Q,"\u229a","\\circledcirc",!0),_(j,K,Q,"\u22a1","\\boxdot",!0),_(j,Z,Q,"\u25b3","\\bigtriangleup"),_(j,Z,Q,"\u25bd","\\bigtriangledown"),_(j,Z,Q,"\u2020","\\dagger"),_(j,Z,Q,"\u22c4","\\diamond"),_(j,Z,Q,"\u22c6","\\star"),_(j,Z,Q,"\u25c3","\\triangleleft"),_(j,Z,Q,"\u25b9","\\triangleright"),_(j,Z,ae,"{","\\{"),_($,Z,le,"{","\\{"),_($,Z,le,"{","\\textbraceleft"),_(j,Z,ee,"}","\\}"),_($,Z,le,"}","\\}"),_($,Z,le,"}","\\textbraceright"),_(j,Z,ae,"{","\\lbrace"),_(j,Z,ee,"}","\\rbrace"),_(j,Z,ae,"[","\\lbrack",!0),_($,Z,le,"[","\\lbrack",!0),_(j,Z,ee,"]","\\rbrack",!0),_($,Z,le,"]","\\rbrack",!0),_(j,Z,ae,"(","\\lparen",!0),_(j,Z,ee,")","\\rparen",!0),_($,Z,le,"<","\\textless",!0),_($,Z,le,">","\\textgreater",!0),_(j,Z,ae,"\u230a","\\lfloor",!0),_(j,Z,ee,"\u230b","\\rfloor",!0),_(j,Z,ae,"\u2308","\\lceil",!0),_(j,Z,ee,"\u2309","\\rceil",!0),_(j,Z,le,"\\","\\backslash"),_(j,Z,le,"\u2223","|"),_(j,Z,le,"\u2223","\\vert"),_($,Z,le,"|","\\textbar",!0),_(j,Z,le,"\u2225","\\|"),_(j,Z,le,"\u2225","\\Vert"),_($,Z,le,"\u2225","\\textbardbl"),_($,Z,le,"~","\\textasciitilde"),_($,Z,le,"\\","\\textbackslash"),_($,Z,le,"^","\\textasciicircum"),_(j,Z,oe,"\u2191","\\uparrow",!0),_(j,Z,oe,"\u21d1","\\Uparrow",!0),_(j,Z,oe,"\u2193","\\downarrow",!0),_(j,Z,oe,"\u21d3","\\Downarrow",!0),_(j,Z,oe,"\u2195","\\updownarrow",!0),_(j,Z,oe,"\u21d5","\\Updownarrow",!0),_(j,Z,ne,"\u2210","\\coprod"),_(j,Z,ne,"\u22c1","\\bigvee"),_(j,Z,ne,"\u22c0","\\bigwedge"),_(j,Z,ne,"\u2a04","\\biguplus"),_(j,Z,ne,"\u22c2","\\bigcap"),_(j,Z,ne,"\u22c3","\\bigcup"),_(j,Z,ne,"\u222b","\\int"),_(j,Z,ne,"\u222b","\\intop"),_(j,Z,ne,"\u222c","\\iint"),_(j,Z,ne,"\u222d","\\iiint"),_(j,Z,ne,"\u220f","\\prod"),_(j,Z,ne,"\u2211","\\sum"),_(j,Z,ne,"\u2a02","\\bigotimes"),_(j,Z,ne,"\u2a01","\\bigoplus"),_(j,Z,ne,"\u2a00","\\bigodot"),_(j,Z,ne,"\u222e","\\oint"),_(j,Z,ne,"\u222f","\\oiint"),_(j,Z,ne,"\u2230","\\oiiint"),_(j,Z,ne,"\u2a06","\\bigsqcup"),_(j,Z,ne,"\u222b","\\smallint"),_($,Z,te,"\u2026","\\textellipsis"),_(j,Z,te,"\u2026","\\mathellipsis"),_($,Z,te,"\u2026","\\ldots",!0),_(j,Z,te,"\u2026","\\ldots",!0),_(j,Z,te,"\u22ef","\\@cdots",!0),_(j,Z,te,"\u22f1","\\ddots",!0),_(j,Z,le,"\u22ee","\\varvdots"),_(j,Z,J,"\u02ca","\\acute"),_(j,Z,J,"\u02cb","\\grave"),_(j,Z,J,"\xa8","\\ddot"),_(j,Z,J,"~","\\tilde"),_(j,Z,J,"\u02c9","\\bar"),_(j,Z,J,"\u02d8","\\breve"),_(j,Z,J,"\u02c7","\\check"),_(j,Z,J,"^","\\hat"),_(j,Z,J,"\u20d7","\\vec"),_(j,Z,J,"\u02d9","\\dot"),_(j,Z,J,"\u02da","\\mathring"),_(j,Z,re,"\ue131","\\@imath"),_(j,Z,re,"\ue237","\\@jmath"),_(j,Z,le,"\u0131","\u0131"),_(j,Z,le,"\u0237","\u0237"),_($,Z,le,"\u0131","\\i",!0),_($,Z,le,"\u0237","\\j",!0),_($,Z,le,"\xdf","\\ss",!0),_($,Z,le,"\xe6","\\ae",!0),_($,Z,le,"\u0153","\\oe",!0),_($,Z,le,"\xf8","\\o",!0),_($,Z,le,"\xc6","\\AE",!0),_($,Z,le,"\u0152","\\OE",!0),_($,Z,le,"\xd8","\\O",!0),_($,Z,J,"\u02ca","\\'"),_($,Z,J,"\u02cb","\\`"),_($,Z,J,"\u02c6","\\^"),_($,Z,J,"\u02dc","\\~"),_($,Z,J,"\u02c9","\\="),_($,Z,J,"\u02d8","\\u"),_($,Z,J,"\u02d9","\\."),_($,Z,J,"\u02da","\\r"),_($,Z,J,"\u02c7","\\v"),_($,Z,J,"\xa8",'\\"'),_($,Z,J,"\u02dd","\\H"),_($,Z,J,"\u25ef","\\textcircled");var he={"--":!0,"---":!0,"``":!0,"''":!0};_($,Z,le,"\u2013","--",!0),_($,Z,le,"\u2013","\\textendash"),_($,Z,le,"\u2014","---",!0),_($,Z,le,"\u2014","\\textemdash"),_($,Z,le,"\u2018","`",!0),_($,Z,le,"\u2018","\\textquoteleft"),_($,Z,le,"\u2019","'",!0),_($,Z,le,"\u2019","\\textquoteright"),_($,Z,le,"\u201c","``",!0),_($,Z,le,"\u201c","\\textquotedblleft"),_($,Z,le,"\u201d","''",!0),_($,Z,le,"\u201d","\\textquotedblright"),_(j,Z,le,"\xb0","\\degree",!0),_($,Z,le,"\xb0","\\degree"),_($,Z,le,"\xb0","\\textdegree",!0),_(j,Z,le,"\xa3","\\pounds"),_(j,Z,le,"\xa3","\\mathsterling",!0),_($,Z,le,"\xa3","\\pounds"),_($,Z,le,"\xa3","\\textsterling",!0),_(j,K,le,"\u2720","\\maltese"),_($,K,le,"\u2720","\\maltese");for(var me='0123456789/@."',ce=0;ce=5?0:e>=3?1:2]){var r=G[t]={cssEmPerMu:P.quad[t]/18};for(var n in P)P.hasOwnProperty(n)&&(r[n]=P[n][t])}return G[t]}(this.size)),this._fontMetrics},t.getColor=function(){return this.phantom?"transparent":this.color},e}();Ie.BASESIZE=6;var Re=Ie,Oe={pt:1,mm:7227/2540,cm:7227/254,in:72.27,bp:1.00375,pc:12,dd:1238/1157,cc:14856/1157,nd:685/642,nc:1370/107,sp:1/65536,px:1.00375},Ee={ex:!0,em:!0,mu:!0},He=function(e){return"string"!=typeof e&&(e=e.unit),e in Oe||e in Ee||"ex"===e},Le=function(e,t){var r;if(e.unit in Oe)r=Oe[e.unit]/t.fontMetrics().ptPerEm/t.sizeMultiplier;else if("mu"===e.unit)r=t.fontMetrics().cssEmPerMu;else{var a;if(a=t.style.isTight()?t.havingStyle(t.style.text()):t,"ex"===e.unit)r=a.fontMetrics().xHeight;else{if("em"!==e.unit)throw new n("Invalid unit: '"+e.unit+"'");r=a.fontMetrics().quad}a!==t&&(r*=a.sizeMultiplier/t.sizeMultiplier)}return Math.min(e.number*r,t.maxSize)},De=function(e,t,r){return X[r][e]&&X[r][e].replace&&(e=X[r][e].replace),{value:e,metrics:V(e,t,r)}},Pe=function(e,t,r,n,a){var i,o=De(e,t,r),s=o.metrics;if(e=o.value,s){var l=s.italic;("text"===r||n&&"mathit"===n.font)&&(l=0),i=new R(e,s.height,s.depth,l,s.skew,s.width,a)}else"undefined"!=typeof console&&console.warn("No character metrics for '"+e+"' in style '"+t+"' and mode '"+r+"'"),i=new R(e,0,0,0,0,0,a);if(n){i.maxFontSize=n.sizeMultiplier,n.style.isTight()&&i.classes.push("mtight");var h=n.getColor();h&&(i.style.color=h)}return i},Fe=function(e,t){if(z(e.classes)!==z(t.classes)||e.skew!==t.skew||e.maxFontSize!==t.maxFontSize)return!1;if(1===e.classes.length){var r=e.classes[0];if("mbin"===r||"mord"===r)return!1}for(var n in e.style)if(e.style.hasOwnProperty(n)&&e.style[n]!==t.style[n])return!1;for(var a in t.style)if(t.style.hasOwnProperty(a)&&e.style[a]!==t.style[a])return!1;return!0},Ve=function(e){for(var t=0,r=0,n=0,a=0;at&&(t=i.height),i.depth>r&&(r=i.depth),i.maxFontSize>n&&(n=i.maxFontSize)}e.height=t,e.depth=r,e.maxFontSize=n},Ge=function(e,t,r,n){var a=new q(e,t,r,n);return Ve(a),a},Ue=function(e,t,r,n){return new q(e,t,r,n)},Ye=function(e){var t=new M(e);return Ve(t),t},We=function(e,t,r){var n="";switch(e){case"amsrm":n="AMS";break;case"textrm":n="Main";break;case"textsf":n="SansSerif";break;case"texttt":n="Typewriter";break;default:n=e}return n+"-"+("textbf"===t&&"textit"===r?"BoldItalic":"textbf"===t?"Bold":"textit"===t?"Italic":"Regular")},Xe={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathit:{variant:"italic",fontName:"Main-Italic"},mathnormal:{variant:"italic",fontName:"Math-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}},_e={vec:["vec",.471,.714],oiintSize1:["oiintSize1",.957,.499],oiintSize2:["oiintSize2",1.472,.659],oiiintSize1:["oiiintSize1",1.304,.499],oiiintSize2:["oiiintSize2",1.98,.659]},je={fontMap:Xe,makeSymbol:Pe,mathsym:function(e,t,r,n){return void 0===n&&(n=[]),"boldsymbol"===r.font&&De(e,"Main-Bold",t).metrics?Pe(e,"Main-Bold",t,r,n.concat(["mathbf"])):"\\"===e||"main"===X[t][e].font?Pe(e,"Main-Regular",t,r,n):Pe(e,"AMS-Regular",t,r,n.concat(["amsrm"]))},makeSpan:Ge,makeSvgSpan:Ue,makeLineSpan:function(e,t,r){var n=Ge([e],[],t);return n.height=Math.max(r||t.fontMetrics().defaultRuleThickness,t.minRuleThickness),n.style.borderBottomWidth=n.height+"em",n.maxFontSize=1,n},makeAnchor:function(e,t,r,n){var a=new N(e,t,r,n);return Ve(a),a},makeFragment:Ye,wrapFragment:function(e,t){return e instanceof M?Ge([],[e],t):e},makeVList:function(e,t){for(var r=function(e){if("individualShift"===e.positionType){for(var t=e.children,r=[t[0]],n=-t[0].shift-t[0].elem.depth,a=n,i=1;i0&&(o.push(yt(s,t)),s=[]),o.push(a[l]));s.length>0&&o.push(yt(s,t)),r?((i=yt(ut(r,t,!0))).classes=["tag"],o.push(i)):n&&o.push(n);var m=st(["katex-html"],o);if(m.setAttribute("aria-hidden","true"),i){var c=i.children[0];c.style.height=m.height+m.depth+"em",c.style.verticalAlign=-m.depth+"em"}return m}function wt(e){return new M(e)}var kt=function(){function e(e,t,r){this.type=void 0,this.attributes=void 0,this.children=void 0,this.classes=void 0,this.type=e,this.attributes={},this.children=t||[],this.classes=r||[]}var t=e.prototype;return t.setAttribute=function(e,t){this.attributes[e]=t},t.getAttribute=function(e){return this.attributes[e]},t.toNode=function(){var e=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);this.classes.length>0&&(e.className=z(this.classes));for(var r=0;r0&&(e+=' class ="'+l.escape(z(this.classes))+'"'),e+=">";for(var r=0;r"},t.toText=function(){return this.children.map((function(e){return e.toText()})).join("")},e}(),St=function(){function e(e){this.text=void 0,this.text=e}var t=e.prototype;return t.toNode=function(){return document.createTextNode(this.text)},t.toMarkup=function(){return l.escape(this.toText())},t.toText=function(){return this.text},e}(),Mt={MathNode:kt,TextNode:St,SpaceNode:function(){function e(e){this.width=void 0,this.character=void 0,this.width=e,this.character=e>=.05555&&e<=.05556?"\u200a":e>=.1666&&e<=.1667?"\u2009":e>=.2222&&e<=.2223?"\u2005":e>=.2777&&e<=.2778?"\u2005\u200a":e>=-.05556&&e<=-.05555?"\u200a\u2063":e>=-.1667&&e<=-.1666?"\u2009\u2063":e>=-.2223&&e<=-.2222?"\u205f\u2063":e>=-.2778&&e<=-.2777?"\u2005\u2063":null}var t=e.prototype;return t.toNode=function(){if(this.character)return document.createTextNode(this.character);var e=document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");return e.setAttribute("width",this.width+"em"),e},t.toMarkup=function(){return this.character?""+this.character+"":''},t.toText=function(){return this.character?this.character:" "},e}(),newDocumentFragment:wt},zt=function(e,t,r){return!X[t][e]||!X[t][e].replace||55349===e.charCodeAt(0)||he.hasOwnProperty(e)&&r&&(r.fontFamily&&"tt"===r.fontFamily.substr(4,2)||r.font&&"tt"===r.font.substr(4,2))||(e=X[t][e].replace),new Mt.TextNode(e)},At=function(e){return 1===e.length?e[0]:new Mt.MathNode("mrow",e)},Tt=function(e,t){if("texttt"===t.fontFamily)return"monospace";if("textsf"===t.fontFamily)return"textit"===t.fontShape&&"textbf"===t.fontWeight?"sans-serif-bold-italic":"textit"===t.fontShape?"sans-serif-italic":"textbf"===t.fontWeight?"bold-sans-serif":"sans-serif";if("textit"===t.fontShape&&"textbf"===t.fontWeight)return"bold-italic";if("textit"===t.fontShape)return"italic";if("textbf"===t.fontWeight)return"bold";var r=t.font;if(!r||"mathnormal"===r)return null;var n=e.mode;if("mathit"===r)return"italic";if("boldsymbol"===r)return"textord"===e.type?"bold":"bold-italic";if("mathbf"===r)return"bold";if("mathbb"===r)return"double-struck";if("mathfrak"===r)return"fraktur";if("mathscr"===r||"mathcal"===r)return"script";if("mathsf"===r)return"sans-serif";if("mathtt"===r)return"monospace";var a=e.text;return l.contains(["\\imath","\\jmath"],a)?null:(X[n][a]&&X[n][a].replace&&(a=X[n][a].replace),V(a,je.fontMap[r].fontName,n)?je.fontMap[r].variant:null)},Bt=function(e,t,r){if(1===e.length){var n=Nt(e[0],t);return r&&n instanceof kt&&"mo"===n.type&&(n.setAttribute("lspace","0em"),n.setAttribute("rspace","0em")),[n]}for(var a,i=[],o=0;o0&&(p.text=p.text.slice(0,1)+"\u0338"+p.text.slice(1),i.pop())}}}i.push(s),a=s}return i},qt=function(e,t,r){return At(Bt(e,t,r))},Nt=function(e,t){if(!e)return new Mt.MathNode("mrow");if(rt[e.type])return rt[e.type](e,t);throw new n("Got group of unknown type: '"+e.type+"'")};function Ct(e,t,r,n,a){var i,o=Bt(e,r);i=1===o.length&&o[0]instanceof kt&&l.contains(["mrow","mtable"],o[0].type)?o[0]:new Mt.MathNode("mrow",o);var s=new Mt.MathNode("annotation",[new Mt.TextNode(t)]);s.setAttribute("encoding","application/x-tex");var h=new Mt.MathNode("semantics",[i,s]),m=new Mt.MathNode("math",[h]);m.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML"),n&&m.setAttribute("display","block");var c=a?"katex":"katex-mathml";return je.makeSpan([c],[m])}var It=function(e){return new Re({style:e.displayMode?b.DISPLAY:b.TEXT,maxSize:e.maxSize,minRuleThickness:e.minRuleThickness})},Rt=function(e,t){if(t.displayMode){var r=["katex-display"];t.leqno&&r.push("leqno"),t.fleqn&&r.push("fleqn"),e=je.makeSpan(r,[e])}return e},Ot=function(e,t,r){var n,a=It(r);if("mathml"===r.output)return Ct(e,t,a,r.displayMode,!0);if("html"===r.output){var i=xt(e,a);n=je.makeSpan(["katex"],[i])}else{var o=Ct(e,t,a,r.displayMode,!1),s=xt(e,a);n=je.makeSpan(["katex"],[o,s])}return Rt(n,r)},Et={widehat:"^",widecheck:"\u02c7",widetilde:"~",utilde:"~",overleftarrow:"\u2190",underleftarrow:"\u2190",xleftarrow:"\u2190",overrightarrow:"\u2192",underrightarrow:"\u2192",xrightarrow:"\u2192",underbrace:"\u23df",overbrace:"\u23de",overgroup:"\u23e0",undergroup:"\u23e1",overleftrightarrow:"\u2194",underleftrightarrow:"\u2194",xleftrightarrow:"\u2194",Overrightarrow:"\u21d2",xRightarrow:"\u21d2",overleftharpoon:"\u21bc",xleftharpoonup:"\u21bc",overrightharpoon:"\u21c0",xrightharpoonup:"\u21c0",xLeftarrow:"\u21d0",xLeftrightarrow:"\u21d4",xhookleftarrow:"\u21a9",xhookrightarrow:"\u21aa",xmapsto:"\u21a6",xrightharpoondown:"\u21c1",xleftharpoondown:"\u21bd",xrightleftharpoons:"\u21cc",xleftrightharpoons:"\u21cb",xtwoheadleftarrow:"\u219e",xtwoheadrightarrow:"\u21a0",xlongequal:"=",xtofrom:"\u21c4",xrightleftarrows:"\u21c4",xrightequilibrium:"\u21cc",xleftequilibrium:"\u21cb","\\cdrightarrow":"\u2192","\\cdleftarrow":"\u2190","\\cdlongequal":"="},Ht={overrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],overleftarrow:[["leftarrow"],.888,522,"xMinYMin"],underrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],underleftarrow:[["leftarrow"],.888,522,"xMinYMin"],xrightarrow:[["rightarrow"],1.469,522,"xMaxYMin"],"\\cdrightarrow":[["rightarrow"],3,522,"xMaxYMin"],xleftarrow:[["leftarrow"],1.469,522,"xMinYMin"],"\\cdleftarrow":[["leftarrow"],3,522,"xMinYMin"],Overrightarrow:[["doublerightarrow"],.888,560,"xMaxYMin"],xRightarrow:[["doublerightarrow"],1.526,560,"xMaxYMin"],xLeftarrow:[["doubleleftarrow"],1.526,560,"xMinYMin"],overleftharpoon:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoonup:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoondown:[["leftharpoondown"],.888,522,"xMinYMin"],overrightharpoon:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoonup:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoondown:[["rightharpoondown"],.888,522,"xMaxYMin"],xlongequal:[["longequal"],.888,334,"xMinYMin"],"\\cdlongequal":[["longequal"],3,334,"xMinYMin"],xtwoheadleftarrow:[["twoheadleftarrow"],.888,334,"xMinYMin"],xtwoheadrightarrow:[["twoheadrightarrow"],.888,334,"xMaxYMin"],overleftrightarrow:[["leftarrow","rightarrow"],.888,522],overbrace:[["leftbrace","midbrace","rightbrace"],1.6,548],underbrace:[["leftbraceunder","midbraceunder","rightbraceunder"],1.6,548],underleftrightarrow:[["leftarrow","rightarrow"],.888,522],xleftrightarrow:[["leftarrow","rightarrow"],1.75,522],xLeftrightarrow:[["doubleleftarrow","doublerightarrow"],1.75,560],xrightleftharpoons:[["leftharpoondownplus","rightharpoonplus"],1.75,716],xleftrightharpoons:[["leftharpoonplus","rightharpoondownplus"],1.75,716],xhookleftarrow:[["leftarrow","righthook"],1.08,522],xhookrightarrow:[["lefthook","rightarrow"],1.08,522],overlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],underlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],overgroup:[["leftgroup","rightgroup"],.888,342],undergroup:[["leftgroupunder","rightgroupunder"],.888,342],xmapsto:[["leftmapsto","rightarrow"],1.5,522],xtofrom:[["leftToFrom","rightToFrom"],1.75,528],xrightleftarrows:[["baraboveleftarrow","rightarrowabovebar"],1.75,901],xrightequilibrium:[["baraboveshortleftharpoon","rightharpoonaboveshortbar"],1.75,716],xleftequilibrium:[["shortbaraboveleftharpoon","shortrightharpoonabovebar"],1.75,716]},Lt=function(e,t,r,n,a){var i,o=e.height+e.depth+r+n;if(/fbox|color|angl/.test(t)){if(i=je.makeSpan(["stretchy",t],[],a),"fbox"===t){var s=a.color&&a.getColor();s&&(i.style.borderColor=s)}}else{var l=[];/^[bx]cancel$/.test(t)&&l.push(new H({x1:"0",y1:"0",x2:"100%",y2:"100%","stroke-width":"0.046em"})),/^x?cancel$/.test(t)&&l.push(new H({x1:"0",y1:"100%",x2:"100%",y2:"0","stroke-width":"0.046em"}));var h=new O(l,{width:"100%",height:o+"em"});i=je.makeSvgSpan([],[h],a)}return i.height=o,i.style.height=o+"em",i},Dt=function(e){var t=new Mt.MathNode("mo",[new Mt.TextNode(Et[e.replace(/^\\/,"")])]);return t.setAttribute("stretchy","true"),t},Pt=function(e,t){var r=function(){var r=4e5,n=e.label.substr(1);if(l.contains(["widehat","widecheck","widetilde","utilde"],n)){var a,i,o,s="ordgroup"===(d=e.base).type?d.body.length:1;if(s>5)"widehat"===n||"widecheck"===n?(a=420,r=2364,o=.42,i=n+"4"):(a=312,r=2340,o=.34,i="tilde4");else{var h=[1,1,2,2,3,3][s];"widehat"===n||"widecheck"===n?(r=[0,1062,2364,2364,2364][h],a=[0,239,300,360,420][h],o=[0,.24,.3,.3,.36,.42][h],i=n+h):(r=[0,600,1033,2339,2340][h],a=[0,260,286,306,312][h],o=[0,.26,.286,.3,.306,.34][h],i="tilde"+h)}var m=new E(i),c=new O([m],{width:"100%",height:o+"em",viewBox:"0 0 "+r+" "+a,preserveAspectRatio:"none"});return{span:je.makeSvgSpan([],[c],t),minWidth:0,height:o}}var u,p,d,f=[],g=Ht[n],v=g[0],b=g[1],y=g[2],x=y/1e3,w=v.length;if(1===w)u=["hide-tail"],p=[g[3]];else if(2===w)u=["halfarrow-left","halfarrow-right"],p=["xMinYMin","xMaxYMin"];else{if(3!==w)throw new Error("Correct katexImagesData or update code here to support\n "+w+" children.");u=["brace-left","brace-center","brace-right"],p=["xMinYMin","xMidYMin","xMaxYMin"]}for(var k=0;k0&&(n.style.minWidth=a+"em"),n};function Ft(e,t){if(!e||e.type!==t)throw new Error("Expected node of type "+t+", but got "+(e?"node of type "+e.type:String(e)));return e}function Vt(e){var t=Gt(e);if(!t)throw new Error("Expected node of symbol group type, but got "+(e?"node of type "+e.type:String(e)));return t}function Gt(e){return e&&("atom"===e.type||Y.hasOwnProperty(e.type))?e:null}var Ut=function(e,t){var r,n,a;e&&"supsub"===e.type?(r=(n=Ft(e.base,"accent")).base,e.base=r,a=function(e){if(e instanceof q)return e;throw new Error("Expected span but got "+String(e)+".")}(bt(e,t)),e.base=n):r=(n=Ft(e,"accent")).base;var i=bt(r,t.havingCrampedStyle()),o=0;if(n.isShifty&&l.isCharacterBox(r)){var s=l.getBaseElem(r);o=L(bt(s,t.havingCrampedStyle())).skew}var h,m=Math.min(i.height,t.fontMetrics().xHeight);if(n.isStretchy)h=Pt(n,t),h=je.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:i},{type:"elem",elem:h,wrapperClasses:["svg-align"],wrapperStyle:o>0?{width:"calc(100% - "+2*o+"em)",marginLeft:2*o+"em"}:void 0}]},t);else{var c,u;"\\vec"===n.label?(c=je.staticSvg("vec",t),u=je.svgData.vec[1]):((c=L(c=je.makeOrd({mode:n.mode,text:n.label},t,"textord"))).italic=0,u=c.width),h=je.makeSpan(["accent-body"],[c]);var p="\\textcircled"===n.label;p&&(h.classes.push("accent-full"),m=i.height);var d=o;p||(d-=u/2),h.style.left=d+"em","\\textcircled"===n.label&&(h.style.top=".2em"),h=je.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:i},{type:"kern",size:-m},{type:"elem",elem:h}]},t)}var f=je.makeSpan(["mord","accent"],[h],t);return a?(a.children[0]=f,a.height=Math.max(f.height,a.height),a.classes[0]="mord",a):f},Yt=function(e,t){var r=e.isStretchy?Dt(e.label):new Mt.MathNode("mo",[zt(e.label,e.mode)]),n=new Mt.MathNode("mover",[Nt(e.base,t),r]);return n.setAttribute("accent","true"),n},Wt=new RegExp(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map((function(e){return"\\"+e})).join("|"));nt({type:"accent",names:["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\widecheck","\\widehat","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overlinesegment","\\overleftharpoon","\\overrightharpoon"],props:{numArgs:1},handler:function(e,t){var r=it(t[0]),n=!Wt.test(e.funcName),a=!n||"\\widehat"===e.funcName||"\\widetilde"===e.funcName||"\\widecheck"===e.funcName;return{type:"accent",mode:e.parser.mode,label:e.funcName,isStretchy:n,isShifty:a,base:r}},htmlBuilder:Ut,mathmlBuilder:Yt}),nt({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\u","\\.",'\\"',"\\r","\\H","\\v","\\textcircled"],props:{numArgs:1,allowedInText:!0,allowedInMath:!1,argTypes:["primitive"]},handler:function(e,t){var r=t[0];return{type:"accent",mode:e.parser.mode,label:e.funcName,isStretchy:!1,isShifty:!0,base:r}},htmlBuilder:Ut,mathmlBuilder:Yt}),nt({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underlinesegment","\\utilde"],props:{numArgs:1},handler:function(e,t){var r=e.parser,n=e.funcName,a=t[0];return{type:"accentUnder",mode:r.mode,label:n,base:a}},htmlBuilder:function(e,t){var r=bt(e.base,t),n=Pt(e,t),a="\\utilde"===e.label?.12:0,i=je.makeVList({positionType:"top",positionData:r.height,children:[{type:"elem",elem:n,wrapperClasses:["svg-align"]},{type:"kern",size:a},{type:"elem",elem:r}]},t);return je.makeSpan(["mord","accentunder"],[i],t)},mathmlBuilder:function(e,t){var r=Dt(e.label),n=new Mt.MathNode("munder",[Nt(e.base,t),r]);return n.setAttribute("accentunder","true"),n}});var Xt=function(e){var t=new Mt.MathNode("mpadded",e?[e]:[]);return t.setAttribute("width","+0.6em"),t.setAttribute("lspace","0.3em"),t};nt({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xrightleftharpoons","\\xleftrightharpoons","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\xtofrom","\\xrightleftarrows","\\xrightequilibrium","\\xleftequilibrium","\\\\cdrightarrow","\\\\cdleftarrow","\\\\cdlongequal"],props:{numArgs:1,numOptionalArgs:1},handler:function(e,t,r){var n=e.parser,a=e.funcName;return{type:"xArrow",mode:n.mode,label:a,body:t[0],below:r[0]}},htmlBuilder:function(e,t){var r,n=t.style,a=t.havingStyle(n.sup()),i=je.wrapFragment(bt(e.body,a,t),t),o="\\x"===e.label.slice(0,2)?"x":"cd";i.classes.push(o+"-arrow-pad"),e.below&&(a=t.havingStyle(n.sub()),(r=je.wrapFragment(bt(e.below,a,t),t)).classes.push(o+"-arrow-pad"));var s,l=Pt(e,t),h=-t.fontMetrics().axisHeight+.5*l.height,m=-t.fontMetrics().axisHeight-.5*l.height-.111;if((i.depth>.25||"\\xleftequilibrium"===e.label)&&(m-=i.depth),r){var c=-t.fontMetrics().axisHeight+r.height+.5*l.height+.111;s=je.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:m},{type:"elem",elem:l,shift:h},{type:"elem",elem:r,shift:c}]},t)}else s=je.makeVList({positionType:"individualShift",children:[{type:"elem",elem:i,shift:m},{type:"elem",elem:l,shift:h}]},t);return s.children[0].children[0].children[1].classes.push("svg-align"),je.makeSpan(["mrel","x-arrow"],[s],t)},mathmlBuilder:function(e,t){var r,n=Dt(e.label);if(n.setAttribute("minsize","x"===e.label.charAt(0)?"1.75em":"3.0em"),e.body){var a=Xt(Nt(e.body,t));if(e.below){var i=Xt(Nt(e.below,t));r=new Mt.MathNode("munderover",[n,i,a])}else r=new Mt.MathNode("mover",[n,a])}else if(e.below){var o=Xt(Nt(e.below,t));r=new Mt.MathNode("munder",[n,o])}else r=Xt(),r=new Mt.MathNode("mover",[n,r]);return r}});var _t={">":"\\\\cdrightarrow","<":"\\\\cdleftarrow","=":"\\\\cdlongequal",A:"\\uparrow",V:"\\downarrow","|":"\\Vert",".":"no arrow"},jt=function(e){return"textord"===e.type&&"@"===e.text};function $t(e,t,r){var n=_t[e];switch(n){case"\\\\cdrightarrow":case"\\\\cdleftarrow":return r.callFunction(n,[t[0]],[t[1]]);case"\\uparrow":case"\\downarrow":var a={type:"atom",text:n,mode:"math",family:"rel"},i={type:"ordgroup",mode:"math",body:[r.callFunction("\\\\cdleft",[t[0]],[]),r.callFunction("\\Big",[a],[]),r.callFunction("\\\\cdright",[t[1]],[])]};return r.callFunction("\\\\cdparent",[i],[]);case"\\\\cdlongequal":return r.callFunction("\\\\cdlongequal",[],[]);case"\\Vert":return r.callFunction("\\Big",[{type:"textord",text:"\\Vert",mode:"math"}],[]);default:return{type:"textord",text:" ",mode:"math"}}}nt({type:"cdlabel",names:["\\\\cdleft","\\\\cdright"],props:{numArgs:1},handler:function(e,t){var r=e.parser,n=e.funcName;return{type:"cdlabel",mode:r.mode,side:n.slice(4),label:t[0]}},htmlBuilder:function(e,t){var r=t.havingStyle(t.style.sup()),n=je.wrapFragment(bt(e.label,r,t),t);return n.classes.push("cd-label-"+e.side),n.style.bottom=.8-n.depth+"em",n.height=0,n.depth=0,n},mathmlBuilder:function(e,t){var r=new Mt.MathNode("mrow",[Nt(e.label,t)]);return(r=new Mt.MathNode("mpadded",[r])).setAttribute("width","0"),"left"===e.side&&r.setAttribute("lspace","-1width"),r.setAttribute("voffset","0.7em"),(r=new Mt.MathNode("mstyle",[r])).setAttribute("displaystyle","false"),r.setAttribute("scriptlevel","1"),r}}),nt({type:"cdlabelparent",names:["\\\\cdparent"],props:{numArgs:1},handler:function(e,t){return{type:"cdlabelparent",mode:e.parser.mode,fragment:t[0]}},htmlBuilder:function(e,t){var r=je.wrapFragment(bt(e.fragment,t),t);return r.classes.push("cd-vert-arrow"),r},mathmlBuilder:function(e,t){return new Mt.MathNode("mrow",[Nt(e.fragment,t)])}}),nt({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler:function(e,t){for(var r=e.parser,a=Ft(t[0],"ordgroup").body,i="",o=0;o","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"],gr=[0,1.2,1.8,2.4,3],vr=[{type:"small",style:b.SCRIPTSCRIPT},{type:"small",style:b.SCRIPT},{type:"small",style:b.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}],br=[{type:"small",style:b.SCRIPTSCRIPT},{type:"small",style:b.SCRIPT},{type:"small",style:b.TEXT},{type:"stack"}],yr=[{type:"small",style:b.SCRIPTSCRIPT},{type:"small",style:b.SCRIPT},{type:"small",style:b.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}],xr=function(e){if("small"===e.type)return"Main-Regular";if("large"===e.type)return"Size"+e.size+"-Regular";if("stack"===e.type)return"Size4-Regular";throw new Error("Add support for delim type '"+e.type+"' here.")},wr=function(e,t,r,n){for(var a=Math.min(2,3-n.style.size);at)return r[a]}return r[r.length-1]},kr=function(e,t,r,n,a,i){var o;"<"===e||"\\lt"===e||"\u27e8"===e?e="\\langle":">"!==e&&"\\gt"!==e&&"\u27e9"!==e||(e="\\rangle"),o=l.contains(fr,e)?vr:l.contains(pr,e)?yr:br;var s=wr(e,t,o,n);return"small"===s.type?function(e,t,r,n,a,i){var o=je.makeSymbol(e,"Main-Regular",a,n),s=rr(o,t,n,i);return r&&nr(s,n,t),s}(e,s.style,r,n,a,i):"large"===s.type?ar(e,s.size,r,n,a,i):mr(e,t,r,n,a,i)},Sr=function(e,t){var r,n,a=t.havingBaseSizing(),i=wr("\\surd",e*a.sizeMultiplier,yr,a),o=a.sizeMultiplier,s=Math.max(0,t.minRuleThickness-t.fontMetrics().sqrtRuleThickness),l=0,h=0,m=0;return"small"===i.type?(e<1?o=1:e<1.4&&(o=.7),h=(1+s)/o,(r=ur("sqrtMain",l=(1+s+cr)/o,m=1e3+1e3*s+80,s,t)).style.minWidth="0.853em",n=.833/o):"large"===i.type?(m=1080*gr[i.size],h=(gr[i.size]+s)/o,l=(gr[i.size]+s+cr)/o,(r=ur("sqrtSize"+i.size,l,m,s,t)).style.minWidth="1.02em",n=1/o):(l=e+s+cr,h=e+s,m=Math.floor(1e3*e+s)+80,(r=ur("sqrtTall",l,m,s,t)).style.minWidth="0.742em",n=1.056),r.height=h,r.style.height=l+"em",{span:r,advanceWidth:n,ruleWidth:(t.fontMetrics().sqrtRuleThickness+s)*o}},Mr=function(e,t,r,a,i){if("<"===e||"\\lt"===e||"\u27e8"===e?e="\\langle":">"!==e&&"\\gt"!==e&&"\u27e9"!==e||(e="\\rangle"),l.contains(pr,e)||l.contains(fr,e))return ar(e,t,!1,r,a,i);if(l.contains(dr,e))return mr(e,gr[t],!1,r,a,i);throw new n("Illegal delimiter: '"+e+"'")},zr=gr,Ar=kr,Tr=function(e,t,r,n,a,i){var o=n.fontMetrics().axisHeight*n.sizeMultiplier,s=5/n.fontMetrics().ptPerEm,l=Math.max(t-o,r+o),h=Math.max(l/500*901,2*l-s);return kr(e,h,!0,n,a,i)},Br={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},qr=["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","\u230a","\u230b","\\lceil","\\rceil","\u2308","\u2309","<",">","\\langle","\u27e8","\\rangle","\u27e9","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","\u27ee","\u27ef","\\lmoustache","\\rmoustache","\u23b0","\u23b1","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."];function Nr(e,t){var r=Gt(e);if(r&&l.contains(qr,r.text))return r;throw new n(r?"Invalid delimiter '"+r.text+"' after '"+t.funcName+"'":"Invalid delimiter type '"+e.type+"'",e)}function Cr(e){if(!e.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}nt({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],props:{numArgs:1,argTypes:["primitive"]},handler:function(e,t){var r=Nr(t[0],e);return{type:"delimsizing",mode:e.parser.mode,size:Br[e.funcName].size,mclass:Br[e.funcName].mclass,delim:r.text}},htmlBuilder:function(e,t){return"."===e.delim?je.makeSpan([e.mclass]):Mr(e.delim,e.size,t,e.mode,[e.mclass])},mathmlBuilder:function(e){var t=[];"."!==e.delim&&t.push(zt(e.delim,e.mode));var r=new Mt.MathNode("mo",t);return"mopen"===e.mclass||"mclose"===e.mclass?r.setAttribute("fence","true"):r.setAttribute("fence","false"),r.setAttribute("stretchy","true"),r.setAttribute("minsize",zr[e.size]+"em"),r.setAttribute("maxsize",zr[e.size]+"em"),r}}),nt({type:"leftright-right",names:["\\right"],props:{numArgs:1,primitive:!0},handler:function(e,t){var r=e.parser.gullet.macros.get("\\current@color");if(r&&"string"!=typeof r)throw new n("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:e.parser.mode,delim:Nr(t[0],e).text,color:r}}}),nt({type:"leftright",names:["\\left"],props:{numArgs:1,primitive:!0},handler:function(e,t){var r=Nr(t[0],e),n=e.parser;++n.leftrightDepth;var a=n.parseExpression(!1);--n.leftrightDepth,n.expect("\\right",!1);var i=Ft(n.parseFunction(),"leftright-right");return{type:"leftright",mode:n.mode,body:a,left:r.text,right:i.delim,rightColor:i.color}},htmlBuilder:function(e,t){Cr(e);for(var r,n,a=ut(e.body,t,!0,["mopen","mclose"]),i=0,o=0,s=!1,l=0;l-1?"mpadded":"menclose",[Nt(e.body,t)]);switch(e.label){case"\\cancel":n.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":n.setAttribute("notation","downdiagonalstrike");break;case"\\phase":n.setAttribute("notation","phasorangle");break;case"\\sout":n.setAttribute("notation","horizontalstrike");break;case"\\fbox":n.setAttribute("notation","box");break;case"\\angl":n.setAttribute("notation","actuarial");break;case"\\fcolorbox":case"\\colorbox":if(r=t.fontMetrics().fboxsep*t.fontMetrics().ptPerEm,n.setAttribute("width","+"+2*r+"pt"),n.setAttribute("height","+"+2*r+"pt"),n.setAttribute("lspace",r+"pt"),n.setAttribute("voffset",r+"pt"),"\\fcolorbox"===e.label){var a=Math.max(t.fontMetrics().fboxrule,t.minRuleThickness);n.setAttribute("style","border: "+a+"em solid "+String(e.borderColor))}break;case"\\xcancel":n.setAttribute("notation","updiagonalstrike downdiagonalstrike")}return e.backgroundColor&&n.setAttribute("mathbackground",e.backgroundColor),n};nt({type:"enclose",names:["\\colorbox"],props:{numArgs:2,allowedInText:!0,argTypes:["color","text"]},handler:function(e,t,r){var n=e.parser,a=e.funcName,i=Ft(t[0],"color-token").color,o=t[1];return{type:"enclose",mode:n.mode,label:a,backgroundColor:i,body:o}},htmlBuilder:Ir,mathmlBuilder:Rr}),nt({type:"enclose",names:["\\fcolorbox"],props:{numArgs:3,allowedInText:!0,argTypes:["color","color","text"]},handler:function(e,t,r){var n=e.parser,a=e.funcName,i=Ft(t[0],"color-token").color,o=Ft(t[1],"color-token").color,s=t[2];return{type:"enclose",mode:n.mode,label:a,backgroundColor:o,borderColor:i,body:s}},htmlBuilder:Ir,mathmlBuilder:Rr}),nt({type:"enclose",names:["\\fbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler:function(e,t){return{type:"enclose",mode:e.parser.mode,label:"\\fbox",body:t[0]}}}),nt({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\sout","\\phase"],props:{numArgs:1},handler:function(e,t){var r=e.parser,n=e.funcName,a=t[0];return{type:"enclose",mode:r.mode,label:n,body:a}},htmlBuilder:Ir,mathmlBuilder:Rr}),nt({type:"enclose",names:["\\angl"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!1},handler:function(e,t){return{type:"enclose",mode:e.parser.mode,label:"\\angl",body:t[0]}}});var Or={};function Er(e){for(var t=e.type,r=e.names,n=e.props,a=e.handler,i=e.htmlBuilder,o=e.mathmlBuilder,s={type:t,numArgs:n.numArgs||0,allowedInText:!1,numOptionalArgs:0,handler:a},l=0;l1||!c)&&g.pop(),b.length0&&(x+=.25),m.push({pos:x,isDashed:e[t]})}for(w(o[0]),r=0;r0&&(M<(B+=y)&&(M=B),B=0),e.addJot&&(M+=f),z.height=S,z.depth=M,x+=S,z.pos=x,x+=M+B,h[r]=z,w(o[r+1])}var q,N,C=x/2+t.fontMetrics().axisHeight,I=e.cols||[],R=[],O=[];if(e.addEqnNum)for(r=0;r=s)){var G=void 0;(a>0||e.hskipBeforeAndAfter)&&0!==(G=l.deflt(D.pregap,p))&&((q=je.makeSpan(["arraycolsep"],[])).style.width=G+"em",R.push(q));var U=[];for(r=0;r0){for(var _=je.makeLineSpan("hline",t,c),j=je.makeLineSpan("hdashline",t,c),$=[{type:"elem",elem:h,shift:0}];m.length>0;){var Z=m.pop(),K=Z.pos-C;Z.isDashed?$.push({type:"elem",elem:j,shift:K}):$.push({type:"elem",elem:_,shift:K})}h=je.makeVList({positionType:"individualShift",children:$},t)}if(e.addEqnNum){var J=je.makeVList({positionType:"individualShift",children:O},t);return J=je.makeSpan(["tag"],[J],t),je.makeFragment([h,J])}return je.makeSpan(["mord"],[h],t)},Vr={c:"center ",l:"left ",r:"right "},Gr=function(e,t){for(var r=[],n=new Mt.MathNode("mtd",[],["mtr-glue"]),a=new Mt.MathNode("mtd",[],["mml-eqn-num"]),i=0;i0){var p=e.cols,d="",f=!1,g=0,v=p.length;"separator"===p[0].type&&(c+="top ",g=1),"separator"===p[p.length-1].type&&(c+="bottom ",v-=1);for(var b=g;b0?"left ":"",c+=S[S.length-1].length>0?"right ":"";for(var M=1;M-1?"alignat":"align",o=Dr(e.parser,{cols:a,addJot:!0,addEqnNum:"align"===e.envName||"alignat"===e.envName,emptySingleRow:!0,colSeparationType:i,maxNumCols:"split"===e.envName?2:void 0,leqno:e.parser.settings.leqno},"display"),s=0,l={type:"ordgroup",mode:e.mode,body:[]};if(t[0]&&"ordgroup"===t[0].type){for(var h="",m=0;m0&&c&&(d=1),a[u]={type:"align",align:p,pregap:d,postgap:0}}return o.colSeparationType=c?"align":"alignat",o};Er({type:"array",names:["array","darray"],props:{numArgs:1},handler:function(e,t){var r=(Gt(t[0])?[t[0]]:Ft(t[0],"ordgroup").body).map((function(e){var t=Vt(e).text;if(-1!=="lcr".indexOf(t))return{type:"align",align:t};if("|"===t)return{type:"separator",separator:"|"};if(":"===t)return{type:"separator",separator:":"};throw new n("Unknown column alignment: "+t,e)})),a={cols:r,hskipBeforeAndAfter:!0,maxNumCols:r.length};return Dr(e.parser,a,Pr(e.envName))},htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix","matrix*","pmatrix*","bmatrix*","Bmatrix*","vmatrix*","Vmatrix*"],props:{numArgs:0},handler:function(e){var t={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[e.envName.replace("*","")],r="c",a={hskipBeforeAndAfter:!1,cols:[{type:"align",align:r}]};if("*"===e.envName.charAt(e.envName.length-1)){var i=e.parser;if(i.consumeSpaces(),"["===i.fetch().text){if(i.consume(),i.consumeSpaces(),r=i.fetch().text,-1==="lcr".indexOf(r))throw new n("Expected l or c or r",i.nextToken);i.consume(),i.consumeSpaces(),i.expect("]"),i.consume(),a.cols=[{type:"align",align:r}]}}var o=Dr(e.parser,a,Pr(e.envName));return o.cols=new Array(o.body[0].length).fill({type:"align",align:r}),t?{type:"leftright",mode:e.mode,body:[o],left:t[0],right:t[1],rightColor:void 0}:o},htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["smallmatrix"],props:{numArgs:0},handler:function(e){var t=Dr(e.parser,{arraystretch:.5},"script");return t.colSeparationType="small",t},htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["subarray"],props:{numArgs:1},handler:function(e,t){var r=(Gt(t[0])?[t[0]]:Ft(t[0],"ordgroup").body).map((function(e){var t=Vt(e).text;if(-1!=="lc".indexOf(t))return{type:"align",align:t};throw new n("Unknown column alignment: "+t,e)}));if(r.length>1)throw new n("{subarray} can contain only one column");var a={cols:r,hskipBeforeAndAfter:!1,arraystretch:.5};if((a=Dr(e.parser,a,"script")).body.length>0&&a.body[0].length>1)throw new n("{subarray} can contain only one column");return a},htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["cases","dcases","rcases","drcases"],props:{numArgs:0},handler:function(e){var t=Dr(e.parser,{arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:1},{type:"align",align:"l",pregap:0,postgap:0}]},Pr(e.envName));return{type:"leftright",mode:e.mode,body:[t],left:e.envName.indexOf("r")>-1?".":"\\{",right:e.envName.indexOf("r")>-1?"\\}":".",rightColor:void 0}},htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["align","align*","aligned","split"],props:{numArgs:0},handler:Ur,htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["gathered","gather","gather*"],props:{numArgs:0},handler:function(e){l.contains(["gather","gather*"],e.envName)&&Lr(e);var t={cols:[{type:"align",align:"c"}],addJot:!0,colSeparationType:"gather",addEqnNum:"gather"===e.envName,emptySingleRow:!0,leqno:e.parser.settings.leqno};return Dr(e.parser,t,"display")},htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["alignat","alignat*","alignedat"],props:{numArgs:1},handler:Ur,htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["equation","equation*"],props:{numArgs:0},handler:function(e){Lr(e);var t={addEqnNum:"equation"===e.envName,emptySingleRow:!0,singleRow:!0,maxNumCols:1,leqno:e.parser.settings.leqno};return Dr(e.parser,t,"display")},htmlBuilder:Fr,mathmlBuilder:Gr}),Er({type:"array",names:["CD"],props:{numArgs:0},handler:function(e){return Lr(e),function(e){var t=[];for(e.gullet.beginGroup(),e.gullet.macros.set("\\cr","\\\\\\relax"),e.gullet.beginGroup();;){t.push(e.parseExpression(!1,"\\\\")),e.gullet.endGroup(),e.gullet.beginGroup();var r=e.fetch().text;if("&"!==r&&"\\\\"!==r){if("\\end"===r){0===t[t.length-1].length&&t.pop();break}throw new n("Expected \\\\ or \\cr or \\end",e.nextToken)}e.consume()}for(var a,i,o=[],s=[o],l=0;l-1);else{if(!("<>AV".indexOf(u)>-1))throw new n('Expected one of "<>AV=|." after @',h[c]);for(var d=0;d<2;d++){for(var f=!0,g=c+1;g=b.SCRIPT.id?r.text():b.DISPLAY:"text"===e&&r.size===b.DISPLAY.size?r=b.TEXT:"script"===e?r=b.SCRIPT:"scriptscript"===e&&(r=b.SCRIPTSCRIPT),r},Qr=function(e,t){var r,n=Jr(e.size,t.style),a=n.fracNum(),i=n.fracDen();r=t.havingStyle(a);var o=bt(e.numer,r,t);if(e.continued){var s=8.5/t.fontMetrics().ptPerEm,l=3.5/t.fontMetrics().ptPerEm;o.height=o.height0?3*c:7*c,d=t.fontMetrics().denom1):(m>0?(u=t.fontMetrics().num2,p=c):(u=t.fontMetrics().num3,p=3*c),d=t.fontMetrics().denom2),h){var w=t.fontMetrics().axisHeight;u-o.depth-(w+.5*m)0&&(t="."===(t=e)?null:t),t};nt({type:"genfrac",names:["\\genfrac"],props:{numArgs:6,allowedInArgument:!0,argTypes:["math","math","size","text","math","math"]},handler:function(e,t){var r,n=e.parser,a=t[4],i=t[5],o=it(t[0]),s="atom"===o.type&&"open"===o.family?rn(o.text):null,l=it(t[1]),h="atom"===l.type&&"close"===l.family?rn(l.text):null,m=Ft(t[2],"size"),c=null;r=!!m.isBlank||(c=m.value).number>0;var u="auto",p=t[3];if("ordgroup"===p.type){if(p.body.length>0){var d=Ft(p.body[0],"textord");u=tn[Number(d.text)]}}else p=Ft(p,"textord"),u=tn[Number(p.text)];return{type:"genfrac",mode:n.mode,numer:a,denom:i,continued:!1,hasBarLine:r,barSize:c,leftDelim:s,rightDelim:h,size:u}},htmlBuilder:Qr,mathmlBuilder:en}),nt({type:"infix",names:["\\above"],props:{numArgs:1,argTypes:["size"],infix:!0},handler:function(e,t){var r=e.parser,n=(e.funcName,e.token);return{type:"infix",mode:r.mode,replaceWith:"\\\\abovefrac",size:Ft(t[0],"size").value,token:n}}}),nt({type:"genfrac",names:["\\\\abovefrac"],props:{numArgs:3,argTypes:["math","size","math"]},handler:function(e,t){var r=e.parser,n=(e.funcName,t[0]),a=function(e){if(!e)throw new Error("Expected non-null, but got "+String(e));return e}(Ft(t[1],"infix").size),i=t[2],o=a.number>0;return{type:"genfrac",mode:r.mode,numer:n,denom:i,continued:!1,hasBarLine:o,barSize:a,leftDelim:null,rightDelim:null,size:"auto"}},htmlBuilder:Qr,mathmlBuilder:en});var nn=function(e,t){var r,n,a=t.style;"supsub"===e.type?(r=e.sup?bt(e.sup,t.havingStyle(a.sup()),t):bt(e.sub,t.havingStyle(a.sub()),t),n=Ft(e.base,"horizBrace")):n=Ft(e,"horizBrace");var i,o=bt(n.base,t.havingBaseStyle(b.DISPLAY)),s=Pt(n,t);if(n.isOver?(i=je.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:o},{type:"kern",size:.1},{type:"elem",elem:s}]},t)).children[0].children[0].children[1].classes.push("svg-align"):(i=je.makeVList({positionType:"bottom",positionData:o.depth+.1+s.height,children:[{type:"elem",elem:s},{type:"kern",size:.1},{type:"elem",elem:o}]},t)).children[0].children[0].children[0].classes.push("svg-align"),r){var l=je.makeSpan(["mord",n.isOver?"mover":"munder"],[i],t);i=n.isOver?je.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:l},{type:"kern",size:.2},{type:"elem",elem:r}]},t):je.makeVList({positionType:"bottom",positionData:l.depth+.2+r.height+r.depth,children:[{type:"elem",elem:r},{type:"kern",size:.2},{type:"elem",elem:l}]},t)}return je.makeSpan(["mord",n.isOver?"mover":"munder"],[i],t)};nt({type:"horizBrace",names:["\\overbrace","\\underbrace"],props:{numArgs:1},handler:function(e,t){var r=e.parser,n=e.funcName;return{type:"horizBrace",mode:r.mode,label:n,isOver:/^\\over/.test(n),base:t[0]}},htmlBuilder:nn,mathmlBuilder:function(e,t){var r=Dt(e.label);return new Mt.MathNode(e.isOver?"mover":"munder",[Nt(e.base,t),r])}}),nt({type:"href",names:["\\href"],props:{numArgs:2,argTypes:["url","original"],allowedInText:!0},handler:function(e,t){var r=e.parser,n=t[1],a=Ft(t[0],"url").url;return r.settings.isTrusted({command:"\\href",url:a})?{type:"href",mode:r.mode,href:a,body:ot(n)}:r.formatUnsupportedCmd("\\href")},htmlBuilder:function(e,t){var r=ut(e.body,t,!1);return je.makeAnchor(e.href,[],r,t)},mathmlBuilder:function(e,t){var r=qt(e.body,t);return r instanceof kt||(r=new kt("mrow",[r])),r.setAttribute("href",e.href),r}}),nt({type:"href",names:["\\url"],props:{numArgs:1,argTypes:["url"],allowedInText:!0},handler:function(e,t){var r=e.parser,n=Ft(t[0],"url").url;if(!r.settings.isTrusted({command:"\\url",url:n}))return r.formatUnsupportedCmd("\\url");for(var a=[],i=0;i0&&(n=Le(e.totalheight,t)-r,n=Number(n.toFixed(2)));var a=0;e.width.number>0&&(a=Le(e.width,t));var i={height:r+n+"em"};a>0&&(i.width=a+"em"),n>0&&(i.verticalAlign=-n+"em");var o=new C(e.src,e.alt,i);return o.height=r,o.depth=n,o},mathmlBuilder:function(e,t){var r=new Mt.MathNode("mglyph",[]);r.setAttribute("alt",e.alt);var n=Le(e.height,t),a=0;if(e.totalheight.number>0&&(a=(a=Le(e.totalheight,t)-n).toFixed(2),r.setAttribute("valign","-"+a+"em")),r.setAttribute("height",n+a+"em"),e.width.number>0){var i=Le(e.width,t);r.setAttribute("width",i+"em")}return r.setAttribute("src",e.src),r}}),nt({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],props:{numArgs:1,argTypes:["size"],primitive:!0,allowedInText:!0},handler:function(e,t){var r=e.parser,n=e.funcName,a=Ft(t[0],"size");if(r.settings.strict){var i="m"===n[1],o="mu"===a.value.unit;i?(o||r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+n+" supports only mu units, not "+a.value.unit+" units"),"math"!==r.mode&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+n+" works only in math mode")):o&&r.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+n+" doesn't support mu units")}return{type:"kern",mode:r.mode,dimension:a.value}},htmlBuilder:function(e,t){return je.makeGlue(e.dimension,t)},mathmlBuilder:function(e,t){var r=Le(e.dimension,t);return new Mt.SpaceNode(r)}}),nt({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap"],props:{numArgs:1,allowedInText:!0},handler:function(e,t){var r=e.parser,n=e.funcName,a=t[0];return{type:"lap",mode:r.mode,alignment:n.slice(5),body:a}},htmlBuilder:function(e,t){var r;"clap"===e.alignment?(r=je.makeSpan([],[bt(e.body,t)]),r=je.makeSpan(["inner"],[r],t)):r=je.makeSpan(["inner"],[bt(e.body,t)]);var n=je.makeSpan(["fix"],[]),a=je.makeSpan([e.alignment],[r,n],t),i=je.makeSpan(["strut"]);return i.style.height=a.height+a.depth+"em",i.style.verticalAlign=-a.depth+"em",a.children.unshift(i),a=je.makeSpan(["thinbox"],[a],t),je.makeSpan(["mord","vbox"],[a],t)},mathmlBuilder:function(e,t){var r=new Mt.MathNode("mpadded",[Nt(e.body,t)]);if("rlap"!==e.alignment){var n="llap"===e.alignment?"-1":"-0.5";r.setAttribute("lspace",n+"width")}return r.setAttribute("width","0px"),r}}),nt({type:"styling",names:["\\(","$"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler:function(e,t){var r=e.funcName,n=e.parser,a=n.mode;n.switchMode("math");var i="\\("===r?"\\)":"$",o=n.parseExpression(!1,i);return n.expect(i),n.switchMode(a),{type:"styling",mode:n.mode,style:"text",body:o}}}),nt({type:"text",names:["\\)","\\]"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler:function(e,t){throw new n("Mismatched "+e.funcName)}});var on=function(e,t){switch(t.style.size){case b.DISPLAY.size:return e.display;case b.TEXT.size:return e.text;case b.SCRIPT.size:return e.script;case b.SCRIPTSCRIPT.size:return e.scriptscript;default:return e.text}};nt({type:"mathchoice",names:["\\mathchoice"],props:{numArgs:4,primitive:!0},handler:function(e,t){return{type:"mathchoice",mode:e.parser.mode,display:ot(t[0]),text:ot(t[1]),script:ot(t[2]),scriptscript:ot(t[3])}},htmlBuilder:function(e,t){var r=on(e,t),n=ut(r,t,!1);return je.makeFragment(n)},mathmlBuilder:function(e,t){var r=on(e,t);return qt(r,t)}});var sn=function(e,t,r,n,a,i,o){var s,l,h;if(e=je.makeSpan([],[e]),t){var m=bt(t,n.havingStyle(a.sup()),n);l={elem:m,kern:Math.max(n.fontMetrics().bigOpSpacing1,n.fontMetrics().bigOpSpacing3-m.depth)}}if(r){var c=bt(r,n.havingStyle(a.sub()),n);s={elem:c,kern:Math.max(n.fontMetrics().bigOpSpacing2,n.fontMetrics().bigOpSpacing4-c.height)}}if(l&&s){var u=n.fontMetrics().bigOpSpacing5+s.elem.height+s.elem.depth+s.kern+e.depth+o;h=je.makeVList({positionType:"bottom",positionData:u,children:[{type:"kern",size:n.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:-i+"em"},{type:"kern",size:s.kern},{type:"elem",elem:e},{type:"kern",size:l.kern},{type:"elem",elem:l.elem,marginLeft:i+"em"},{type:"kern",size:n.fontMetrics().bigOpSpacing5}]},n)}else if(s){var p=e.height-o;h=je.makeVList({positionType:"top",positionData:p,children:[{type:"kern",size:n.fontMetrics().bigOpSpacing5},{type:"elem",elem:s.elem,marginLeft:-i+"em"},{type:"kern",size:s.kern},{type:"elem",elem:e}]},n)}else{if(!l)return e;var d=e.depth+o;h=je.makeVList({positionType:"bottom",positionData:d,children:[{type:"elem",elem:e},{type:"kern",size:l.kern},{type:"elem",elem:l.elem,marginLeft:i+"em"},{type:"kern",size:n.fontMetrics().bigOpSpacing5}]},n)}return je.makeSpan(["mop","op-limits"],[h],n)},ln=["\\smallint"],hn=function(e,t){var r,n,a,i=!1;"supsub"===e.type?(r=e.sup,n=e.sub,a=Ft(e.base,"op"),i=!0):a=Ft(e,"op");var o,s=t.style,h=!1;if(s.size===b.DISPLAY.size&&a.symbol&&!l.contains(ln,a.name)&&(h=!0),a.symbol){var m=h?"Size2-Regular":"Size1-Regular",c="";if("\\oiint"!==a.name&&"\\oiiint"!==a.name||(c=a.name.substr(1),a.name="oiint"===c?"\\iint":"\\iiint"),o=je.makeSymbol(a.name,m,"math",t,["mop","op-symbol",h?"large-op":"small-op"]),c.length>0){var u=o.italic,p=je.staticSvg(c+"Size"+(h?"2":"1"),t);o=je.makeVList({positionType:"individualShift",children:[{type:"elem",elem:o,shift:0},{type:"elem",elem:p,shift:h?.08:0}]},t),a.name="\\"+c,o.classes.unshift("mop"),o.italic=u}}else if(a.body){var d=ut(a.body,t,!0);1===d.length&&d[0]instanceof R?(o=d[0]).classes[0]="mop":o=je.makeSpan(["mop"],d,t)}else{for(var f=[],g=1;g=t)throw new n("Invalid base-"+t+" digit "+r.text);for(var i;null!=(i=gn[e.future().text])&&i":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"};fn("\\dots",(function(e){var t="\\dotso",r=e.expandAfterFuture().text;return r in bn?t=bn[r]:("\\not"===r.substr(0,4)||r in X.math&&l.contains(["bin","rel"],X.math[r].group))&&(t="\\dotsb"),t}));var yn={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};fn("\\dotso",(function(e){return e.future().text in yn?"\\ldots\\,":"\\ldots"})),fn("\\dotsc",(function(e){var t=e.future().text;return t in yn&&","!==t?"\\ldots\\,":"\\ldots"})),fn("\\cdots",(function(e){return e.future().text in yn?"\\@cdots\\,":"\\@cdots"})),fn("\\dotsb","\\cdots"),fn("\\dotsm","\\cdots"),fn("\\dotsi","\\!\\cdots"),fn("\\dotsx","\\ldots\\,"),fn("\\DOTSI","\\relax"),fn("\\DOTSB","\\relax"),fn("\\DOTSX","\\relax"),fn("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"),fn("\\,","\\tmspace+{3mu}{.1667em}"),fn("\\thinspace","\\,"),fn("\\>","\\mskip{4mu}"),fn("\\:","\\tmspace+{4mu}{.2222em}"),fn("\\medspace","\\:"),fn("\\;","\\tmspace+{5mu}{.2777em}"),fn("\\thickspace","\\;"),fn("\\!","\\tmspace-{3mu}{.1667em}"),fn("\\negthinspace","\\!"),fn("\\negmedspace","\\tmspace-{4mu}{.2222em}"),fn("\\negthickspace","\\tmspace-{5mu}{.277em}"),fn("\\enspace","\\kern.5em "),fn("\\enskip","\\hskip.5em\\relax"),fn("\\quad","\\hskip1em\\relax"),fn("\\qquad","\\hskip2em\\relax"),fn("\\tag","\\@ifstar\\tag@literal\\tag@paren"),fn("\\tag@paren","\\tag@literal{({#1})}"),fn("\\tag@literal",(function(e){if(e.macros.get("\\df@tag"))throw new n("Multiple \\tag");return"\\gdef\\df@tag{\\text{#1}}"})),fn("\\bmod","\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}"),fn("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)"),fn("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}"),fn("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1"),fn("\\pmb","\\html@mathml{\\@binrel{#1}{\\mathrlap{#1}\\kern0.5px#1}}{\\mathbf{#1}}"),fn("\\newline","\\\\\\relax"),fn("\\TeX","\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}");var xn=D["Main-Regular"]["T".charCodeAt(0)][1]-.7*D["Main-Regular"]["A".charCodeAt(0)][1]+"em";fn("\\LaTeX","\\textrm{\\html@mathml{L\\kern-.36em\\raisebox{"+xn+"}{\\scriptstyle A}\\kern-.15em\\TeX}{LaTeX}}"),fn("\\KaTeX","\\textrm{\\html@mathml{K\\kern-.17em\\raisebox{"+xn+"}{\\scriptstyle A}\\kern-.15em\\TeX}{KaTeX}}"),fn("\\hspace","\\@ifstar\\@hspacer\\@hspace"),fn("\\@hspace","\\hskip #1\\relax"),fn("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax"),fn("\\ordinarycolon",":"),fn("\\vcentcolon","\\mathrel{\\mathop\\ordinarycolon}"),fn("\\dblcolon",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char"2237}}'),fn("\\coloneqq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2254}}'),fn("\\Coloneqq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2237\\char"3d}}'),fn("\\coloneq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"3a\\char"2212}}'),fn("\\Coloneq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"2237\\char"2212}}'),fn("\\eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2255}}'),fn("\\Eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"3d\\char"2237}}'),fn("\\eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2239}}'),fn("\\Eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"2212\\char"2237}}'),fn("\\colonapprox",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"3a\\char"2248}}'),fn("\\Colonapprox",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"2237\\char"2248}}'),fn("\\colonsim",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"3a\\char"223c}}'),fn("\\Colonsim",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"2237\\char"223c}}'),fn("\u2237","\\dblcolon"),fn("\u2239","\\eqcolon"),fn("\u2254","\\coloneqq"),fn("\u2255","\\eqqcolon"),fn("\u2a74","\\Coloneqq"),fn("\\ratio","\\vcentcolon"),fn("\\coloncolon","\\dblcolon"),fn("\\colonequals","\\coloneqq"),fn("\\coloncolonequals","\\Coloneqq"),fn("\\equalscolon","\\eqqcolon"),fn("\\equalscoloncolon","\\Eqqcolon"),fn("\\colonminus","\\coloneq"),fn("\\coloncolonminus","\\Coloneq"),fn("\\minuscolon","\\eqcolon"),fn("\\minuscoloncolon","\\Eqcolon"),fn("\\coloncolonapprox","\\Colonapprox"),fn("\\coloncolonsim","\\Colonsim"),fn("\\simcolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),fn("\\simcoloncolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}"),fn("\\approxcolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}"),fn("\\approxcoloncolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}"),fn("\\notni","\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220c}}"),fn("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}"),fn("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}"),fn("\\injlim","\\DOTSB\\operatorname*{inj\\,lim}"),fn("\\projlim","\\DOTSB\\operatorname*{proj\\,lim}"),fn("\\varlimsup","\\DOTSB\\operatorname*{\\overline{lim}}"),fn("\\varliminf","\\DOTSB\\operatorname*{\\underline{lim}}"),fn("\\varinjlim","\\DOTSB\\operatorname*{\\underrightarrow{lim}}"),fn("\\varprojlim","\\DOTSB\\operatorname*{\\underleftarrow{lim}}"),fn("\\gvertneqq","\\html@mathml{\\@gvertneqq}{\u2269}"),fn("\\lvertneqq","\\html@mathml{\\@lvertneqq}{\u2268}"),fn("\\ngeqq","\\html@mathml{\\@ngeqq}{\u2271}"),fn("\\ngeqslant","\\html@mathml{\\@ngeqslant}{\u2271}"),fn("\\nleqq","\\html@mathml{\\@nleqq}{\u2270}"),fn("\\nleqslant","\\html@mathml{\\@nleqslant}{\u2270}"),fn("\\nshortmid","\\html@mathml{\\@nshortmid}{\u2224}"),fn("\\nshortparallel","\\html@mathml{\\@nshortparallel}{\u2226}"),fn("\\nsubseteqq","\\html@mathml{\\@nsubseteqq}{\u2288}"),fn("\\nsupseteqq","\\html@mathml{\\@nsupseteqq}{\u2289}"),fn("\\varsubsetneq","\\html@mathml{\\@varsubsetneq}{\u228a}"),fn("\\varsubsetneqq","\\html@mathml{\\@varsubsetneqq}{\u2acb}"),fn("\\varsupsetneq","\\html@mathml{\\@varsupsetneq}{\u228b}"),fn("\\varsupsetneqq","\\html@mathml{\\@varsupsetneqq}{\u2acc}"),fn("\\imath","\\html@mathml{\\@imath}{\u0131}"),fn("\\jmath","\\html@mathml{\\@jmath}{\u0237}"),fn("\\llbracket","\\html@mathml{\\mathopen{[\\mkern-3.2mu[}}{\\mathopen{\\char`\u27e6}}"),fn("\\rrbracket","\\html@mathml{\\mathclose{]\\mkern-3.2mu]}}{\\mathclose{\\char`\u27e7}}"),fn("\u27e6","\\llbracket"),fn("\u27e7","\\rrbracket"),fn("\\lBrace","\\html@mathml{\\mathopen{\\{\\mkern-3.2mu[}}{\\mathopen{\\char`\u2983}}"),fn("\\rBrace","\\html@mathml{\\mathclose{]\\mkern-3.2mu\\}}}{\\mathclose{\\char`\u2984}}"),fn("\u2983","\\lBrace"),fn("\u2984","\\rBrace"),fn("\\minuso","\\mathbin{\\html@mathml{{\\mathrlap{\\mathchoice{\\kern{0.145em}}{\\kern{0.145em}}{\\kern{0.1015em}}{\\kern{0.0725em}}\\circ}{-}}}{\\char`\u29b5}}"),fn("\u29b5","\\minuso"),fn("\\darr","\\downarrow"),fn("\\dArr","\\Downarrow"),fn("\\Darr","\\Downarrow"),fn("\\lang","\\langle"),fn("\\rang","\\rangle"),fn("\\uarr","\\uparrow"),fn("\\uArr","\\Uparrow"),fn("\\Uarr","\\Uparrow"),fn("\\N","\\mathbb{N}"),fn("\\R","\\mathbb{R}"),fn("\\Z","\\mathbb{Z}"),fn("\\alef","\\aleph"),fn("\\alefsym","\\aleph"),fn("\\Alpha","\\mathrm{A}"),fn("\\Beta","\\mathrm{B}"),fn("\\bull","\\bullet"),fn("\\Chi","\\mathrm{X}"),fn("\\clubs","\\clubsuit"),fn("\\cnums","\\mathbb{C}"),fn("\\Complex","\\mathbb{C}"),fn("\\Dagger","\\ddagger"),fn("\\diamonds","\\diamondsuit"),fn("\\empty","\\emptyset"),fn("\\Epsilon","\\mathrm{E}"),fn("\\Eta","\\mathrm{H}"),fn("\\exist","\\exists"),fn("\\harr","\\leftrightarrow"),fn("\\hArr","\\Leftrightarrow"),fn("\\Harr","\\Leftrightarrow"),fn("\\hearts","\\heartsuit"),fn("\\image","\\Im"),fn("\\infin","\\infty"),fn("\\Iota","\\mathrm{I}"),fn("\\isin","\\in"),fn("\\Kappa","\\mathrm{K}"),fn("\\larr","\\leftarrow"),fn("\\lArr","\\Leftarrow"),fn("\\Larr","\\Leftarrow"),fn("\\lrarr","\\leftrightarrow"),fn("\\lrArr","\\Leftrightarrow"),fn("\\Lrarr","\\Leftrightarrow"),fn("\\Mu","\\mathrm{M}"),fn("\\natnums","\\mathbb{N}"),fn("\\Nu","\\mathrm{N}"),fn("\\Omicron","\\mathrm{O}"),fn("\\plusmn","\\pm"),fn("\\rarr","\\rightarrow"),fn("\\rArr","\\Rightarrow"),fn("\\Rarr","\\Rightarrow"),fn("\\real","\\Re"),fn("\\reals","\\mathbb{R}"),fn("\\Reals","\\mathbb{R}"),fn("\\Rho","\\mathrm{P}"),fn("\\sdot","\\cdot"),fn("\\sect","\\S"),fn("\\spades","\\spadesuit"),fn("\\sub","\\subset"),fn("\\sube","\\subseteq"),fn("\\supe","\\supseteq"),fn("\\Tau","\\mathrm{T}"),fn("\\thetasym","\\vartheta"),fn("\\weierp","\\wp"),fn("\\Zeta","\\mathrm{Z}"),fn("\\argmin","\\DOTSB\\operatorname*{arg\\,min}"),fn("\\argmax","\\DOTSB\\operatorname*{arg\\,max}"),fn("\\plim","\\DOTSB\\mathop{\\operatorname{plim}}\\limits"),fn("\\bra","\\mathinner{\\langle{#1}|}"),fn("\\ket","\\mathinner{|{#1}\\rangle}"),fn("\\braket","\\mathinner{\\langle{#1}\\rangle}"),fn("\\Bra","\\left\\langle#1\\right|"),fn("\\Ket","\\left|#1\\right\\rangle"),fn("\\angln","{\\angl n}"),fn("\\blue","\\textcolor{##6495ed}{#1}"),fn("\\orange","\\textcolor{##ffa500}{#1}"),fn("\\pink","\\textcolor{##ff00af}{#1}"),fn("\\red","\\textcolor{##df0030}{#1}"),fn("\\green","\\textcolor{##28ae7b}{#1}"),fn("\\gray","\\textcolor{gray}{#1}"),fn("\\purple","\\textcolor{##9d38bd}{#1}"),fn("\\blueA","\\textcolor{##ccfaff}{#1}"),fn("\\blueB","\\textcolor{##80f6ff}{#1}"),fn("\\blueC","\\textcolor{##63d9ea}{#1}"),fn("\\blueD","\\textcolor{##11accd}{#1}"),fn("\\blueE","\\textcolor{##0c7f99}{#1}"),fn("\\tealA","\\textcolor{##94fff5}{#1}"),fn("\\tealB","\\textcolor{##26edd5}{#1}"),fn("\\tealC","\\textcolor{##01d1c1}{#1}"),fn("\\tealD","\\textcolor{##01a995}{#1}"),fn("\\tealE","\\textcolor{##208170}{#1}"),fn("\\greenA","\\textcolor{##b6ffb0}{#1}"),fn("\\greenB","\\textcolor{##8af281}{#1}"),fn("\\greenC","\\textcolor{##74cf70}{#1}"),fn("\\greenD","\\textcolor{##1fab54}{#1}"),fn("\\greenE","\\textcolor{##0d923f}{#1}"),fn("\\goldA","\\textcolor{##ffd0a9}{#1}"),fn("\\goldB","\\textcolor{##ffbb71}{#1}"),fn("\\goldC","\\textcolor{##ff9c39}{#1}"),fn("\\goldD","\\textcolor{##e07d10}{#1}"),fn("\\goldE","\\textcolor{##a75a05}{#1}"),fn("\\redA","\\textcolor{##fca9a9}{#1}"),fn("\\redB","\\textcolor{##ff8482}{#1}"),fn("\\redC","\\textcolor{##f9685d}{#1}"),fn("\\redD","\\textcolor{##e84d39}{#1}"),fn("\\redE","\\textcolor{##bc2612}{#1}"),fn("\\maroonA","\\textcolor{##ffbde0}{#1}"),fn("\\maroonB","\\textcolor{##ff92c6}{#1}"),fn("\\maroonC","\\textcolor{##ed5fa6}{#1}"),fn("\\maroonD","\\textcolor{##ca337c}{#1}"),fn("\\maroonE","\\textcolor{##9e034e}{#1}"),fn("\\purpleA","\\textcolor{##ddd7ff}{#1}"),fn("\\purpleB","\\textcolor{##c6b9fc}{#1}"),fn("\\purpleC","\\textcolor{##aa87ff}{#1}"),fn("\\purpleD","\\textcolor{##7854ab}{#1}"),fn("\\purpleE","\\textcolor{##543b78}{#1}"),fn("\\mintA","\\textcolor{##f5f9e8}{#1}"),fn("\\mintB","\\textcolor{##edf2df}{#1}"),fn("\\mintC","\\textcolor{##e0e5cc}{#1}"),fn("\\grayA","\\textcolor{##f6f7f7}{#1}"),fn("\\grayB","\\textcolor{##f0f1f2}{#1}"),fn("\\grayC","\\textcolor{##e3e5e6}{#1}"),fn("\\grayD","\\textcolor{##d6d8da}{#1}"),fn("\\grayE","\\textcolor{##babec2}{#1}"),fn("\\grayF","\\textcolor{##888d93}{#1}"),fn("\\grayG","\\textcolor{##626569}{#1}"),fn("\\grayH","\\textcolor{##3b3e40}{#1}"),fn("\\grayI","\\textcolor{##21242c}{#1}"),fn("\\kaBlue","\\textcolor{##314453}{#1}"),fn("\\kaGreen","\\textcolor{##71B307}{#1}");var wn=function(e,t){var r,n,a,i,o=!1;if("supsub"===e.type?(r=e.sup,n=e.sub,a=Ft(e.base,"operatorname"),o=!0):a=Ft(e,"operatorname"),a.body.length>0){for(var s=a.body.map((function(e){var t=e.text;return"string"==typeof t?{type:"textord",mode:e.mode,text:t}:e})),l=ut(s,t.withFont("mathrm"),!0),h=0;h=0?s.setAttribute("height","+"+a+"em"):(s.setAttribute("height",a+"em"),s.setAttribute("depth","+"+-a+"em")),s.setAttribute("voffset",a+"em"),s}});var Sn=["\\tiny","\\sixptsize","\\scriptsize","\\footnotesize","\\small","\\normalsize","\\large","\\Large","\\LARGE","\\huge","\\Huge"];nt({type:"sizing",names:Sn,props:{numArgs:0,allowedInText:!0},handler:function(e,t){var r=e.breakOnTokenText,n=e.funcName,a=e.parser,i=a.parseExpression(!1,r);return{type:"sizing",mode:a.mode,size:Sn.indexOf(n)+1,body:i}},htmlBuilder:function(e,t){var r=t.havingSize(e.size);return kn(e.body,r,t)},mathmlBuilder:function(e,t){var r=t.havingSize(e.size),n=Bt(e.body,r),a=new Mt.MathNode("mstyle",n);return a.setAttribute("mathsize",r.sizeMultiplier+"em"),a}}),nt({type:"smash",names:["\\smash"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0},handler:function(e,t,r){var n=e.parser,a=!1,i=!1,o=r[0]&&Ft(r[0],"ordgroup");if(o)for(var s="",l=0;lr.height+r.depth+i&&(i=(i+c-r.height-r.depth)/2);var u=l.height-r.height-i-h;r.style.paddingLeft=m+"em";var p=je.makeVList({positionType:"firstBaseline",children:[{type:"elem",elem:r,wrapperClasses:["svg-align"]},{type:"kern",size:-(r.height+u)},{type:"elem",elem:l},{type:"kern",size:h}]},t);if(e.index){var d=t.havingStyle(b.SCRIPTSCRIPT),f=bt(e.index,d,t),g=.6*(p.height-p.depth),v=je.makeVList({positionType:"shift",positionData:-g,children:[{type:"elem",elem:f}]},t),y=je.makeSpan(["root"],[v]);return je.makeSpan(["mord","sqrt"],[y,p],t)}return je.makeSpan(["mord","sqrt"],[p],t)},mathmlBuilder:function(e,t){var r=e.body,n=e.index;return n?new Mt.MathNode("mroot",[Nt(r,t),Nt(n,t)]):new Mt.MathNode("msqrt",[Nt(r,t)])}});var Mn={display:b.DISPLAY,text:b.TEXT,script:b.SCRIPT,scriptscript:b.SCRIPTSCRIPT};nt({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler:function(e,t){var r=e.breakOnTokenText,n=e.funcName,a=e.parser,i=a.parseExpression(!0,r),o=n.slice(1,n.length-5);return{type:"styling",mode:a.mode,style:o,body:i}},htmlBuilder:function(e,t){var r=Mn[e.style],n=t.havingStyle(r).withFont("");return kn(e.body,n,t)},mathmlBuilder:function(e,t){var r=Mn[e.style],n=t.havingStyle(r),a=Bt(e.body,n),i=new Mt.MathNode("mstyle",a),o={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]}[e.style];return i.setAttribute("scriptlevel",o[0]),i.setAttribute("displaystyle",o[1]),i}});var zn=function(e,t){var r=e.base;return r?"op"===r.type?r.limits&&(t.style.size===b.DISPLAY.size||r.alwaysHandleSupSub)?hn:null:"operatorname"===r.type?r.alwaysHandleSupSub&&(t.style.size===b.DISPLAY.size||r.limits)?wn:null:"accent"===r.type?l.isCharacterBox(r.base)?Ut:null:"horizBrace"===r.type&&!e.sub===r.isOver?nn:null:null};at({type:"supsub",htmlBuilder:function(e,t){var r=zn(e,t);if(r)return r(e,t);var n,a,i,o=e.base,s=e.sup,h=e.sub,m=bt(o,t),c=t.fontMetrics(),u=0,p=0,d=o&&l.isCharacterBox(o);if(s){var f=t.havingStyle(t.style.sup());n=bt(s,f,t),d||(u=m.height-f.fontMetrics().supDrop*f.sizeMultiplier/t.sizeMultiplier)}if(h){var g=t.havingStyle(t.style.sub());a=bt(h,g,t),d||(p=m.depth+g.fontMetrics().subDrop*g.sizeMultiplier/t.sizeMultiplier)}i=t.style===b.DISPLAY?c.sup1:t.style.cramped?c.sup3:c.sup2;var v,y=t.sizeMultiplier,x=.5/c.ptPerEm/y+"em",w=null;if(a){var k=e.base&&"op"===e.base.type&&e.base.name&&("\\oiint"===e.base.name||"\\oiiint"===e.base.name);(m instanceof R||k)&&(w=-m.italic+"em")}if(n&&a){u=Math.max(u,i,n.depth+.25*c.xHeight),p=Math.max(p,c.sub2);var S=4*c.defaultRuleThickness;if(u-n.depth-(a.height-p)0&&(u+=M,p-=M)}var z=[{type:"elem",elem:a,shift:p,marginRight:x,marginLeft:w},{type:"elem",elem:n,shift:-u,marginRight:x}];v=je.makeVList({positionType:"individualShift",children:z},t)}else if(a){p=Math.max(p,c.sub1,a.height-.8*c.xHeight);var A=[{type:"elem",elem:a,marginLeft:w,marginRight:x}];v=je.makeVList({positionType:"shift",positionData:p,children:A},t)}else{if(!n)throw new Error("supsub must have either sup or sub.");u=Math.max(u,i,n.depth+.25*c.xHeight),v=je.makeVList({positionType:"shift",positionData:-u,children:[{type:"elem",elem:n,marginRight:x}]},t)}var T=gt(m,"right")||"mord";return je.makeSpan([T],[m,je.makeSpan(["msupsub"],[v])],t)},mathmlBuilder:function(e,t){var r,n=!1;e.base&&"horizBrace"===e.base.type&&!!e.sup===e.base.isOver&&(n=!0,r=e.base.isOver),!e.base||"op"!==e.base.type&&"operatorname"!==e.base.type||(e.base.parentIsSupSub=!0);var a,i=[Nt(e.base,t)];if(e.sub&&i.push(Nt(e.sub,t)),e.sup&&i.push(Nt(e.sup,t)),n)a=r?"mover":"munder";else if(e.sub)if(e.sup){var o=e.base;a=o&&"op"===o.type&&o.limits&&t.style===b.DISPLAY||o&&"operatorname"===o.type&&o.alwaysHandleSupSub&&(t.style===b.DISPLAY||o.limits)?"munderover":"msubsup"}else{var s=e.base;a=s&&"op"===s.type&&s.limits&&(t.style===b.DISPLAY||s.alwaysHandleSupSub)||s&&"operatorname"===s.type&&s.alwaysHandleSupSub&&(s.limits||t.style===b.DISPLAY)?"munder":"msub"}else{var l=e.base;a=l&&"op"===l.type&&l.limits&&(t.style===b.DISPLAY||l.alwaysHandleSupSub)||l&&"operatorname"===l.type&&l.alwaysHandleSupSub&&(l.limits||t.style===b.DISPLAY)?"mover":"msup"}return new Mt.MathNode(a,i)}}),at({type:"atom",htmlBuilder:function(e,t){return je.mathsym(e.text,e.mode,t,["m"+e.family])},mathmlBuilder:function(e,t){var r=new Mt.MathNode("mo",[zt(e.text,e.mode)]);if("bin"===e.family){var n=Tt(e,t);"bold-italic"===n&&r.setAttribute("mathvariant",n)}else"punct"===e.family?r.setAttribute("separator","true"):"open"!==e.family&&"close"!==e.family||r.setAttribute("stretchy","false");return r}});var An={mi:"italic",mn:"normal",mtext:"normal"};at({type:"mathord",htmlBuilder:function(e,t){return je.makeOrd(e,t,"mathord")},mathmlBuilder:function(e,t){var r=new Mt.MathNode("mi",[zt(e.text,e.mode,t)]),n=Tt(e,t)||"italic";return n!==An[r.type]&&r.setAttribute("mathvariant",n),r}}),at({type:"textord",htmlBuilder:function(e,t){return je.makeOrd(e,t,"textord")},mathmlBuilder:function(e,t){var r,n=zt(e.text,e.mode,t),a=Tt(e,t)||"normal";return r="text"===e.mode?new Mt.MathNode("mtext",[n]):/[0-9]/.test(e.text)?new Mt.MathNode("mn",[n]):"\\prime"===e.text?new Mt.MathNode("mo",[n]):new Mt.MathNode("mi",[n]),a!==An[r.type]&&r.setAttribute("mathvariant",a),r}});var Tn={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},Bn={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};at({type:"spacing",htmlBuilder:function(e,t){if(Bn.hasOwnProperty(e.text)){var r=Bn[e.text].className||"";if("text"===e.mode){var a=je.makeOrd(e,t,"textord");return a.classes.push(r),a}return je.makeSpan(["mspace",r],[je.mathsym(e.text,e.mode,t)],t)}if(Tn.hasOwnProperty(e.text))return je.makeSpan(["mspace",Tn[e.text]],[],t);throw new n('Unknown type of space "'+e.text+'"')},mathmlBuilder:function(e,t){if(!Bn.hasOwnProperty(e.text)){if(Tn.hasOwnProperty(e.text))return new Mt.MathNode("mspace");throw new n('Unknown type of space "'+e.text+'"')}return new Mt.MathNode("mtext",[new Mt.TextNode("\xa0")])}});var qn=function(){var e=new Mt.MathNode("mtd",[]);return e.setAttribute("width","50%"),e};at({type:"tag",mathmlBuilder:function(e,t){var r=new Mt.MathNode("mtable",[new Mt.MathNode("mtr",[qn(),new Mt.MathNode("mtd",[qt(e.body,t)]),qn(),new Mt.MathNode("mtd",[qt(e.tag,t)])])]);return r.setAttribute("width","100%"),r}});var Nn={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm"},Cn={"\\textbf":"textbf","\\textmd":"textmd"},In={"\\textit":"textit","\\textup":"textup"},Rn=function(e,t){var r=e.font;return r?Nn[r]?t.withTextFontFamily(Nn[r]):Cn[r]?t.withTextFontWeight(Cn[r]):t.withTextFontShape(In[r]):t};nt({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textmd","\\textit","\\textup"],props:{numArgs:1,argTypes:["text"],allowedInArgument:!0,allowedInText:!0},handler:function(e,t){var r=e.parser,n=e.funcName,a=t[0];return{type:"text",mode:r.mode,body:ot(a),font:n}},htmlBuilder:function(e,t){var r=Rn(e,t),n=ut(e.body,r,!0);return je.makeSpan(["mord","text"],n,r)},mathmlBuilder:function(e,t){var r=Rn(e,t);return qt(e.body,r)}}),nt({type:"underline",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler:function(e,t){return{type:"underline",mode:e.parser.mode,body:t[0]}},htmlBuilder:function(e,t){var r=bt(e.body,t),n=je.makeLineSpan("underline-line",t),a=t.fontMetrics().defaultRuleThickness,i=je.makeVList({positionType:"top",positionData:r.height,children:[{type:"kern",size:a},{type:"elem",elem:n},{type:"kern",size:3*a},{type:"elem",elem:r}]},t);return je.makeSpan(["mord","underline"],[i],t)},mathmlBuilder:function(e,t){var r=new Mt.MathNode("mo",[new Mt.TextNode("\u203e")]);r.setAttribute("stretchy","true");var n=new Mt.MathNode("munder",[Nt(e.body,t),r]);return n.setAttribute("accentunder","true"),n}}),nt({type:"vcenter",names:["\\vcenter"],props:{numArgs:1,argTypes:["original"],allowedInText:!1},handler:function(e,t){return{type:"vcenter",mode:e.parser.mode,body:t[0]}},htmlBuilder:function(e,t){var r=bt(e.body,t),n=t.fontMetrics().axisHeight,a=.5*(r.height-n-(r.depth+n));return je.makeVList({positionType:"shift",positionData:a,children:[{type:"elem",elem:r}]},t)},mathmlBuilder:function(e,t){return new Mt.MathNode("mpadded",[Nt(e.body,t)],["vcenter"])}}),nt({type:"verb",names:["\\verb"],props:{numArgs:0,allowedInText:!0},handler:function(e,t,r){throw new n("\\verb ended by end of line instead of matching delimiter")},htmlBuilder:function(e,t){for(var r=On(e),n=[],a=t.havingStyle(t.style.text()),i=0;i0&&(this.undefStack[this.undefStack.length-1][e]=t)}else{var a=this.undefStack[this.undefStack.length-1];a&&!a.hasOwnProperty(e)&&(a[e]=this.current[e])}this.current[e]=t},e}(),Vn={"\\relax":!0,"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0},Gn=function(){function e(e,t,r){this.settings=void 0,this.expansionCount=void 0,this.lexer=void 0,this.macros=void 0,this.stack=void 0,this.mode=void 0,this.settings=t,this.expansionCount=0,this.feed(e),this.macros=new Fn(dn,t.macros),this.mode=r,this.stack=[]}var t=e.prototype;return t.feed=function(e){this.lexer=new Pn(e,this.settings)},t.switchMode=function(e){this.mode=e},t.beginGroup=function(){this.macros.beginGroup()},t.endGroup=function(){this.macros.endGroup()},t.future=function(){return 0===this.stack.length&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]},t.popToken=function(){return this.future(),this.stack.pop()},t.pushToken=function(e){this.stack.push(e)},t.pushTokens=function(e){var t;(t=this.stack).push.apply(t,e)},t.scanArgument=function(e){var t,r,n;if(e){if(this.consumeSpaces(),"["!==this.future().text)return null;t=this.popToken();var a=this.consumeArg(["]"]);n=a.tokens,r=a.end}else{var i=this.consumeArg();n=i.tokens,t=i.start,r=i.end}return this.pushToken(new Ln("EOF",r.loc)),this.pushTokens(n),t.range(r,"")},t.consumeSpaces=function(){for(;;){if(" "!==this.future().text)break;this.stack.pop()}},t.consumeArg=function(e){var t=[],r=e&&e.length>0;r||this.consumeSpaces();var a,i=this.future(),o=0,s=0;do{if(a=this.popToken(),t.push(a),"{"===a.text)++o;else if("}"===a.text){if(-1===--o)throw new n("Extra }",a)}else if("EOF"===a.text)throw new n("Unexpected end of input in a macro argument, expected '"+(e&&r?e[s]:"}")+"'",a);if(e&&r)if((0===o||1===o&&"{"===e[s])&&a.text===e[s]){if(++s===e.length){t.splice(-s,s);break}}else s=0}while(0!==o||r);return"{"===i.text&&"}"===t[t.length-1].text&&(t.pop(),t.shift()),t.reverse(),{tokens:t,start:i,end:a}},t.consumeArgs=function(e,t){if(t){if(t.length!==e+1)throw new n("The length of delimiters doesn't match the number of args!");for(var r=t[0],a=0;athis.settings.maxExpand)throw new n("Too many expansions: infinite loop or need to increase maxExpand setting");var i=a.tokens,o=this.consumeArgs(a.numArgs,a.delimiters);if(a.numArgs)for(var s=(i=i.slice()).length-1;s>=0;--s){var l=i[s];if("#"===l.text){if(0===s)throw new n("Incomplete placeholder at end of macro body",l);if("#"===(l=i[--s]).text)i.splice(s+1,1);else{if(!/^[1-9]$/.test(l.text))throw new n("Not a valid argument number",l);var h;(h=i).splice.apply(h,[s,2].concat(o[+l.text-1]))}}}return this.pushTokens(i),i},t.expandAfterFuture=function(){return this.expandOnce(),this.future()},t.expandNextToken=function(){for(;;){var e=this.expandOnce();if(e instanceof Ln){if("\\relax"!==e.text&&!e.treatAsRelax)return this.stack.pop();this.stack.pop()}}throw new Error},t.expandMacro=function(e){return this.macros.has(e)?this.expandTokens([new Ln(e)]):void 0},t.expandTokens=function(e){var t=[],r=this.stack.length;for(this.pushTokens(e);this.stack.length>r;){var n=this.expandOnce(!0);n instanceof Ln&&(n.treatAsRelax&&(n.noexpand=!1,n.treatAsRelax=!1),t.push(this.stack.pop()))}return t},t.expandMacroAsText=function(e){var t=this.expandMacro(e);return t?t.map((function(e){return e.text})).join(""):t},t._getExpansion=function(e){var t=this.macros.get(e);if(null==t)return t;if(1===e.length){var r=this.lexer.catcodes[e];if(null!=r&&13!==r)return}var n="function"==typeof t?t(this):t;if("string"==typeof n){var a=0;if(-1!==n.indexOf("#"))for(var i=n.replace(/##/g,"");-1!==i.indexOf("#"+(a+1));)++a;for(var o=new Pn(n,this.settings),s=[],l=o.lex();"EOF"!==l.text;)s.push(l),l=o.lex();return s.reverse(),{tokens:s,numArgs:a}}return n},t.isDefined=function(e){return this.macros.has(e)||En.hasOwnProperty(e)||X.math.hasOwnProperty(e)||X.text.hasOwnProperty(e)||Vn.hasOwnProperty(e)},t.isExpandable=function(e){var t=this.macros.get(e);return null!=t?"string"==typeof t||"function"==typeof t||!t.unexpandable:En.hasOwnProperty(e)&&!En[e].primitive},e}(),Un={"\u0301":{text:"\\'",math:"\\acute"},"\u0300":{text:"\\`",math:"\\grave"},"\u0308":{text:'\\"',math:"\\ddot"},"\u0303":{text:"\\~",math:"\\tilde"},"\u0304":{text:"\\=",math:"\\bar"},"\u0306":{text:"\\u",math:"\\breve"},"\u030c":{text:"\\v",math:"\\check"},"\u0302":{text:"\\^",math:"\\hat"},"\u0307":{text:"\\.",math:"\\dot"},"\u030a":{text:"\\r",math:"\\mathring"},"\u030b":{text:"\\H"}},Yn={"\xe1":"a\u0301","\xe0":"a\u0300","\xe4":"a\u0308","\u01df":"a\u0308\u0304","\xe3":"a\u0303","\u0101":"a\u0304","\u0103":"a\u0306","\u1eaf":"a\u0306\u0301","\u1eb1":"a\u0306\u0300","\u1eb5":"a\u0306\u0303","\u01ce":"a\u030c","\xe2":"a\u0302","\u1ea5":"a\u0302\u0301","\u1ea7":"a\u0302\u0300","\u1eab":"a\u0302\u0303","\u0227":"a\u0307","\u01e1":"a\u0307\u0304","\xe5":"a\u030a","\u01fb":"a\u030a\u0301","\u1e03":"b\u0307","\u0107":"c\u0301","\u010d":"c\u030c","\u0109":"c\u0302","\u010b":"c\u0307","\u010f":"d\u030c","\u1e0b":"d\u0307","\xe9":"e\u0301","\xe8":"e\u0300","\xeb":"e\u0308","\u1ebd":"e\u0303","\u0113":"e\u0304","\u1e17":"e\u0304\u0301","\u1e15":"e\u0304\u0300","\u0115":"e\u0306","\u011b":"e\u030c","\xea":"e\u0302","\u1ebf":"e\u0302\u0301","\u1ec1":"e\u0302\u0300","\u1ec5":"e\u0302\u0303","\u0117":"e\u0307","\u1e1f":"f\u0307","\u01f5":"g\u0301","\u1e21":"g\u0304","\u011f":"g\u0306","\u01e7":"g\u030c","\u011d":"g\u0302","\u0121":"g\u0307","\u1e27":"h\u0308","\u021f":"h\u030c","\u0125":"h\u0302","\u1e23":"h\u0307","\xed":"i\u0301","\xec":"i\u0300","\xef":"i\u0308","\u1e2f":"i\u0308\u0301","\u0129":"i\u0303","\u012b":"i\u0304","\u012d":"i\u0306","\u01d0":"i\u030c","\xee":"i\u0302","\u01f0":"j\u030c","\u0135":"j\u0302","\u1e31":"k\u0301","\u01e9":"k\u030c","\u013a":"l\u0301","\u013e":"l\u030c","\u1e3f":"m\u0301","\u1e41":"m\u0307","\u0144":"n\u0301","\u01f9":"n\u0300","\xf1":"n\u0303","\u0148":"n\u030c","\u1e45":"n\u0307","\xf3":"o\u0301","\xf2":"o\u0300","\xf6":"o\u0308","\u022b":"o\u0308\u0304","\xf5":"o\u0303","\u1e4d":"o\u0303\u0301","\u1e4f":"o\u0303\u0308","\u022d":"o\u0303\u0304","\u014d":"o\u0304","\u1e53":"o\u0304\u0301","\u1e51":"o\u0304\u0300","\u014f":"o\u0306","\u01d2":"o\u030c","\xf4":"o\u0302","\u1ed1":"o\u0302\u0301","\u1ed3":"o\u0302\u0300","\u1ed7":"o\u0302\u0303","\u022f":"o\u0307","\u0231":"o\u0307\u0304","\u0151":"o\u030b","\u1e55":"p\u0301","\u1e57":"p\u0307","\u0155":"r\u0301","\u0159":"r\u030c","\u1e59":"r\u0307","\u015b":"s\u0301","\u1e65":"s\u0301\u0307","\u0161":"s\u030c","\u1e67":"s\u030c\u0307","\u015d":"s\u0302","\u1e61":"s\u0307","\u1e97":"t\u0308","\u0165":"t\u030c","\u1e6b":"t\u0307","\xfa":"u\u0301","\xf9":"u\u0300","\xfc":"u\u0308","\u01d8":"u\u0308\u0301","\u01dc":"u\u0308\u0300","\u01d6":"u\u0308\u0304","\u01da":"u\u0308\u030c","\u0169":"u\u0303","\u1e79":"u\u0303\u0301","\u016b":"u\u0304","\u1e7b":"u\u0304\u0308","\u016d":"u\u0306","\u01d4":"u\u030c","\xfb":"u\u0302","\u016f":"u\u030a","\u0171":"u\u030b","\u1e7d":"v\u0303","\u1e83":"w\u0301","\u1e81":"w\u0300","\u1e85":"w\u0308","\u0175":"w\u0302","\u1e87":"w\u0307","\u1e98":"w\u030a","\u1e8d":"x\u0308","\u1e8b":"x\u0307","\xfd":"y\u0301","\u1ef3":"y\u0300","\xff":"y\u0308","\u1ef9":"y\u0303","\u0233":"y\u0304","\u0177":"y\u0302","\u1e8f":"y\u0307","\u1e99":"y\u030a","\u017a":"z\u0301","\u017e":"z\u030c","\u1e91":"z\u0302","\u017c":"z\u0307","\xc1":"A\u0301","\xc0":"A\u0300","\xc4":"A\u0308","\u01de":"A\u0308\u0304","\xc3":"A\u0303","\u0100":"A\u0304","\u0102":"A\u0306","\u1eae":"A\u0306\u0301","\u1eb0":"A\u0306\u0300","\u1eb4":"A\u0306\u0303","\u01cd":"A\u030c","\xc2":"A\u0302","\u1ea4":"A\u0302\u0301","\u1ea6":"A\u0302\u0300","\u1eaa":"A\u0302\u0303","\u0226":"A\u0307","\u01e0":"A\u0307\u0304","\xc5":"A\u030a","\u01fa":"A\u030a\u0301","\u1e02":"B\u0307","\u0106":"C\u0301","\u010c":"C\u030c","\u0108":"C\u0302","\u010a":"C\u0307","\u010e":"D\u030c","\u1e0a":"D\u0307","\xc9":"E\u0301","\xc8":"E\u0300","\xcb":"E\u0308","\u1ebc":"E\u0303","\u0112":"E\u0304","\u1e16":"E\u0304\u0301","\u1e14":"E\u0304\u0300","\u0114":"E\u0306","\u011a":"E\u030c","\xca":"E\u0302","\u1ebe":"E\u0302\u0301","\u1ec0":"E\u0302\u0300","\u1ec4":"E\u0302\u0303","\u0116":"E\u0307","\u1e1e":"F\u0307","\u01f4":"G\u0301","\u1e20":"G\u0304","\u011e":"G\u0306","\u01e6":"G\u030c","\u011c":"G\u0302","\u0120":"G\u0307","\u1e26":"H\u0308","\u021e":"H\u030c","\u0124":"H\u0302","\u1e22":"H\u0307","\xcd":"I\u0301","\xcc":"I\u0300","\xcf":"I\u0308","\u1e2e":"I\u0308\u0301","\u0128":"I\u0303","\u012a":"I\u0304","\u012c":"I\u0306","\u01cf":"I\u030c","\xce":"I\u0302","\u0130":"I\u0307","\u0134":"J\u0302","\u1e30":"K\u0301","\u01e8":"K\u030c","\u0139":"L\u0301","\u013d":"L\u030c","\u1e3e":"M\u0301","\u1e40":"M\u0307","\u0143":"N\u0301","\u01f8":"N\u0300","\xd1":"N\u0303","\u0147":"N\u030c","\u1e44":"N\u0307","\xd3":"O\u0301","\xd2":"O\u0300","\xd6":"O\u0308","\u022a":"O\u0308\u0304","\xd5":"O\u0303","\u1e4c":"O\u0303\u0301","\u1e4e":"O\u0303\u0308","\u022c":"O\u0303\u0304","\u014c":"O\u0304","\u1e52":"O\u0304\u0301","\u1e50":"O\u0304\u0300","\u014e":"O\u0306","\u01d1":"O\u030c","\xd4":"O\u0302","\u1ed0":"O\u0302\u0301","\u1ed2":"O\u0302\u0300","\u1ed6":"O\u0302\u0303","\u022e":"O\u0307","\u0230":"O\u0307\u0304","\u0150":"O\u030b","\u1e54":"P\u0301","\u1e56":"P\u0307","\u0154":"R\u0301","\u0158":"R\u030c","\u1e58":"R\u0307","\u015a":"S\u0301","\u1e64":"S\u0301\u0307","\u0160":"S\u030c","\u1e66":"S\u030c\u0307","\u015c":"S\u0302","\u1e60":"S\u0307","\u0164":"T\u030c","\u1e6a":"T\u0307","\xda":"U\u0301","\xd9":"U\u0300","\xdc":"U\u0308","\u01d7":"U\u0308\u0301","\u01db":"U\u0308\u0300","\u01d5":"U\u0308\u0304","\u01d9":"U\u0308\u030c","\u0168":"U\u0303","\u1e78":"U\u0303\u0301","\u016a":"U\u0304","\u1e7a":"U\u0304\u0308","\u016c":"U\u0306","\u01d3":"U\u030c","\xdb":"U\u0302","\u016e":"U\u030a","\u0170":"U\u030b","\u1e7c":"V\u0303","\u1e82":"W\u0301","\u1e80":"W\u0300","\u1e84":"W\u0308","\u0174":"W\u0302","\u1e86":"W\u0307","\u1e8c":"X\u0308","\u1e8a":"X\u0307","\xdd":"Y\u0301","\u1ef2":"Y\u0300","\u0178":"Y\u0308","\u1ef8":"Y\u0303","\u0232":"Y\u0304","\u0176":"Y\u0302","\u1e8e":"Y\u0307","\u0179":"Z\u0301","\u017d":"Z\u030c","\u1e90":"Z\u0302","\u017b":"Z\u0307","\u03ac":"\u03b1\u0301","\u1f70":"\u03b1\u0300","\u1fb1":"\u03b1\u0304","\u1fb0":"\u03b1\u0306","\u03ad":"\u03b5\u0301","\u1f72":"\u03b5\u0300","\u03ae":"\u03b7\u0301","\u1f74":"\u03b7\u0300","\u03af":"\u03b9\u0301","\u1f76":"\u03b9\u0300","\u03ca":"\u03b9\u0308","\u0390":"\u03b9\u0308\u0301","\u1fd2":"\u03b9\u0308\u0300","\u1fd1":"\u03b9\u0304","\u1fd0":"\u03b9\u0306","\u03cc":"\u03bf\u0301","\u1f78":"\u03bf\u0300","\u03cd":"\u03c5\u0301","\u1f7a":"\u03c5\u0300","\u03cb":"\u03c5\u0308","\u03b0":"\u03c5\u0308\u0301","\u1fe2":"\u03c5\u0308\u0300","\u1fe1":"\u03c5\u0304","\u1fe0":"\u03c5\u0306","\u03ce":"\u03c9\u0301","\u1f7c":"\u03c9\u0300","\u038e":"\u03a5\u0301","\u1fea":"\u03a5\u0300","\u03ab":"\u03a5\u0308","\u1fe9":"\u03a5\u0304","\u1fe8":"\u03a5\u0306","\u038f":"\u03a9\u0301","\u1ffa":"\u03a9\u0300"},Wn=function(){function e(e,t){this.mode=void 0,this.gullet=void 0,this.settings=void 0,this.leftrightDepth=void 0,this.nextToken=void 0,this.mode="math",this.gullet=new Gn(e,t,this.mode),this.settings=t,this.leftrightDepth=0}var t=e.prototype;return t.expect=function(e,t){if(void 0===t&&(t=!0),this.fetch().text!==e)throw new n("Expected '"+e+"', got '"+this.fetch().text+"'",this.fetch());t&&this.consume()},t.consume=function(){this.nextToken=null},t.fetch=function(){return null==this.nextToken&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken},t.switchMode=function(e){this.mode=e,this.gullet.switchMode(e)},t.parse=function(){this.settings.globalGroup||this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");var e=this.parseExpression(!1);return this.expect("EOF"),this.settings.globalGroup||this.gullet.endGroup(),e},t.parseExpression=function(t,r){for(var n=[];;){"math"===this.mode&&this.consumeSpaces();var a=this.fetch();if(-1!==e.endOfExpression.indexOf(a.text))break;if(r&&a.text===r)break;if(t&&En[a.text]&&En[a.text].infix)break;var i=this.parseAtom(r);if(!i)break;"internal"!==i.type&&n.push(i)}return"text"===this.mode&&this.formLigatures(n),this.handleInfixNodes(n)},t.handleInfixNodes=function(e){for(var t,r=-1,a=0;a=0&&this.settings.reportNonstrict("unicodeTextInMathMode",'Latin-1/Unicode text character "'+t[0]+'" used in math mode',e);var s,l=X[this.mode][t].group,h=Hn.range(e);if(U.hasOwnProperty(l)){var m=l;s={type:"atom",mode:this.mode,family:m,loc:h,text:t}}else s={type:l,mode:this.mode,loc:h,text:t};i=s}else{if(!(t.charCodeAt(0)>=128))return null;this.settings.strict&&(w(t.charCodeAt(0))?"math"===this.mode&&this.settings.reportNonstrict("unicodeTextInMathMode",'Unicode text character "'+t[0]+'" used in math mode',e):this.settings.reportNonstrict("unknownSymbol",'Unrecognized Unicode character "'+t[0]+'" ('+t.charCodeAt(0)+")",e)),i={type:"textord",mode:"text",loc:Hn.range(e),text:t}}if(this.consume(),o)for(var c=0;c 15) { - left = "…" + input.slice(start - 15, start); - } else { - left = input.slice(0, start); - } - let right; - if (end + 15 < input.length) { - right = input.slice(end, end + 15) + "…"; - } else { - right = input.slice(end); - } - error += left + underlined + right; - } - - // Some hackery to make ParseError a prototype of Error - // See http://stackoverflow.com/a/8460753 - const self = new Error(error); - self.name = "ParseError"; - self.__proto__ = ParseError.prototype; - self.position = start; - return self; - } -} - -ParseError.prototype.__proto__ = Error.prototype; - -// -/** - * This file contains a list of utility functions which are useful in other - * files. - */ - -/** - * Return whether an element is contained in a list - */ -const contains = function(list, elem) { - return list.indexOf(elem) !== -1; -}; - -/** - * Provide a default value if a setting is undefined - */ -const deflt = function(setting, defaultIfUndefined) { - return setting === undefined ? defaultIfUndefined : setting; -}; - -// hyphenate and escape adapted from Facebook's React under Apache 2 license - -const uppercase = /([A-Z])/g; -const hyphenate = function(str) { - return str.replace(uppercase, "-$1").toLowerCase(); -}; - -const ESCAPE_LOOKUP = { - "&": "&", - ">": ">", - "<": "<", - '"': """, - "'": "'" -}; - -const ESCAPE_REGEX = /[&><"']/g; - -/** - * Escapes text to prevent scripting attacks. - */ -function escape(text) { - return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); -} - -/** - * Sometimes we want to pull out the innermost element of a group. In most - * cases, this will just be the group itself, but when ordgroups and colors have - * a single element, we want to pull that out. - */ -const getBaseElem = function(group) { - if (group.type === "ordgroup") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "color") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "font") { - return getBaseElem(group.body); - } else { - return group; - } -}; - -/** - * TeXbook algorithms often reference "character boxes", which are simply groups - * with a single character in them. To decide if something is a character box, - * we find its innermost group, and see if it is a single character. - */ -const isCharacterBox = function(group) { - const baseElem = getBaseElem(group); - - // These are all the types of groups which hold single characters - return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom" -}; - -const assert = function(value) { - if (!value) { - throw new Error("Expected non-null, but got " + String(value)); - } - return value; -}; - -/** - * Return the protocol of a URL, or "_relative" if the URL does not specify a - * protocol (and thus is relative). - */ -const protocolFromUrl = function(url) { - const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); - return protocol != null ? protocol[1] : "_relative"; -}; - -/** - * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook - * gives an acceptable rounding error of 100sp (which would be the nearest - * 1/6551.6em with our ptPerEm = 10): - * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69 - */ -const round = function(n) { - return +n.toFixed(4); -}; - -const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - const mtext = mrow.children[0]; - if (!mtext.attributes || mtext.type !== "mtext") { return mrow } - const variant = mtext.attributes.mathvariant || ""; - for (let i = 1; i < mrow.children.length; i++) { - // Check each child and, if possible, copy the character into child[0]. - const localVariant = mrow.children[i].attributes.mathvariant || ""; - if (mrow.children[i].type === "mrow") { - const childRow = mrow.children[i]; - for (let j = 0; j < childRow.children.length; j++) { - // We'll also check the children of a mrow. One level only. No recursion. - const childVariant = childRow.children[j].attributes.mathvariant || ""; - if (childVariant !== variant || childRow.children[j].type !== "mtext") { - return mrow // At least one element cannot be consolidated. Get out. - } else { - mtext.children[0].text += childRow.children[j].children[0].text; - } - } - } else if (localVariant !== variant || mrow.children[i].type !== "mtext") { - return mrow - } else { - mtext.children[0].text += mrow.children[i].children[0].text; - } - } - // Since we have gotten here, the text has been loaded into a single mtext node. - // Next, consolidate the children into a single element. - mtext.children.splice(1, mtext.children.length - 1); - // Firefox does not render a space at either end of an string. - // To get proper rendering, we replace leading or trailing spaces with no-break spaces. - if (mtext.children[0].text.charAt(0) === " ") { - mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1); - } - const L = mtext.children[0].text.length; - if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") { - mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0"; - } - return mtext -}; - -var utils = { - contains, - deflt, - escape, - hyphenate, - getBaseElem, - isCharacterBox, - protocolFromUrl, - round, - consolidateText -}; - -/** - * This is a module for storing settings passed into Temml. It correctly handles - * default settings. - */ - -/** - * The main Settings object - */ -class Settings { - constructor(options) { - // allow null options - options = options || {}; - this.displayMode = utils.deflt(options.displayMode, false); // boolean - this.annotate = utils.deflt(options.annotate, false); // boolean - this.elementIsMath = utils.deflt(options.elementIsMath, false); // boolean - this.leqno = utils.deflt(options.leqno, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.preventTagLap = utils.deflt(options.preventTagLap, false); // boolean - this.macros = options.macros || {}; - this.xml = utils.deflt(options.xml, false); // boolean - this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean - this.strict = utils.deflt(options.strict, false); // boolean - this.trust = utils.deflt(options.trust, false); // trust context. See html.js. - this.maxSize = (options.maxSize === undefined - ? [Infinity, Infinity] - : Array.isArray(options.maxSize) - ? options.maxSize - : [Infinity, Infinity] - ); - this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number - } - - /** - * Check whether to test potentially dangerous input, and return - * `true` (trusted) or `false` (untrusted). The sole argument `context` - * should be an object with `command` field specifying the relevant LaTeX - * command (as a string starting with `\`), and any other arguments, etc. - * If `context` has a `url` field, a `protocol` field will automatically - * get added by this function (changing the specified object). - */ - isTrusted(context) { - if (context.url && !context.protocol) { - context.protocol = utils.protocolFromUrl(context.url); - } - const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; - return Boolean(trust); - } -} - -/** - * All registered functions. - * `functions.js` just exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary. - */ -const _functions = {}; - -/** - * All MathML builders. Should be only used in the `define*` and the `build*ML` - * functions. - */ -const _mathmlGroupBuilders = {}; - -function defineFunction({ - type, - names, - props, - handler, - mathmlBuilder -}) { - // Set default values of functions - const data = { - type, - numArgs: props.numArgs, - argTypes: props.argTypes, - allowedInArgument: !!props.allowedInArgument, - allowedInText: !!props.allowedInText, - allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, - numOptionalArgs: props.numOptionalArgs || 0, - infix: !!props.infix, - primitive: !!props.primitive, - handler: handler - }; - for (let i = 0; i < names.length; ++i) { - _functions[names[i]] = data; - } - if (type) { - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } - } -} - -/** - * Use this to register only the MathML builder for a function(e.g. - * if the function's ParseNode is generated in Parser.js rather than via a - * stand-alone handler provided to `defineFunction`). - */ -function defineFunctionBuilders({ type, mathmlBuilder }) { - defineFunction({ - type, - names: [], - props: { numArgs: 0 }, - handler() { - throw new Error("Should never be called.") - }, - mathmlBuilder - }); -} - -const normalizeArgument = function(arg) { - return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg -}; - -// Since the corresponding buildMathML function expects a -// list of elements, we normalize for different kinds of arguments -const ordargument = function(arg) { - return arg.type === "ordgroup" ? arg.body : [arg] -}; - -/** - * This node represents a document fragment, which contains elements, but when - * placed into the DOM doesn't have any representation itself. It only contains - * children and doesn't have any DOM node properties. - */ -class DocumentFragment { - constructor(children) { - this.children = children; - this.classes = []; - this.style = {}; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - /** Convert the fragment into a node. */ - toNode() { - const frag = document.createDocumentFragment(); - - for (let i = 0; i < this.children.length; i++) { - frag.appendChild(this.children[i].toNode()); - } - - return frag; - } - - /** Convert the fragment into HTML markup. */ - toMarkup() { - let markup = ""; - - // Simply concatenate the markup for the children together. - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText. Applies to - * MathDomNode's only. - */ - toText() { - // To avoid this, we would subclass documentFragment separately for - // MathML, but polyfills for subclassing is expensive per PR 1469. - const toText = (child) => child.toText(); - return this.children.map(toText).join(""); - } -} - -/** - * These objects store the data about the DOM nodes we create, as well as some - * extra data. They can then be transformed into real DOM nodes with the - * `toNode` function or HTML markup using `toMarkup`. They are useful for both - * storing extra properties on the nodes, as well as providing a way to easily - * work with the DOM. - * - * Similar functions for working with MathML nodes exist in mathMLTree.js. - * - */ - -/** - * Create an HTML className based on a list of classes. In addition to joining - * with spaces, we also remove empty classes. - */ -const createClass = function(classes) { - return classes.filter((cls) => cls).join(" "); -}; - -const initNode = function(classes, style) { - this.classes = classes || []; - this.attributes = {}; - this.style = style || {}; -}; - -/** - * Convert into an HTML node - */ -const toNode = function(tagName) { - const node = document.createElement(tagName); - - // Apply the class - node.className = createClass(this.classes); - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - // Apply attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - // Append the children, also as HTML nodes - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; -}; - -/** - * Convert into an HTML markup string - */ -const toMarkup = function(tagName) { - let markup = `<${tagName}`; - - // Add the class - if (this.classes.length) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; - } - } - - markup += ">"; - - // Add the markup of the children, also as markup - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ``; - - return markup; -}; - -/** - * This node represents a span node, with a className, a list of children, and - * an inline style. - * - */ -class Span { - constructor(classes, children, style) { - initNode.call(this, classes, style); - this.children = children || []; - } - - setAttribute(attribute, value) { - this.attributes[attribute] = value; - } - - toNode() { - return toNode.call(this, "span"); - } - - toMarkup() { - return toMarkup.call(this, "span"); - } -} - -class TextNode$1 { - constructor(text) { - this.text = text; - } - toNode() { - return document.createTextNode(this.text); - } - toMarkup() { - return utils.escape(this.text); - } -} - -/** - * This node represents an image embed () element. - */ -class Img { - constructor(src, alt, style) { - this.alt = alt; - this.src = src; - this.classes = ["mord"]; - this.style = style; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - toNode() { - const node = document.createElement("img"); - node.src = this.src; - node.alt = this.alt; - node.className = "mord"; - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - return node; - } - - toMarkup() { - let markup = `${this.alt}` and - * `` tags). - */ -class MathNode { - constructor(type, children, classes, style) { - this.type = type; - this.attributes = {}; - this.children = children || []; - this.classes = classes || []; - this.style = style || {}; // Used for elements - } - - /** - * Sets an attribute on a MathML node. MathML depends on attributes to convey a - * semantic content, so this is used heavily. - */ - setAttribute(name, value) { - this.attributes[name] = value; - } - - /** - * Gets an attribute on a MathML node. - */ - getAttribute(name) { - return this.attributes[name]; - } - - /** - * Converts the math node into a MathML-namespaced DOM element. - */ - toNode() { - const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); - - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - if (this.classes.length > 0) { - node.className = createClass(this.classes); - } - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; - } - - /** - * Converts the math node into an HTML markup string. - */ - toMarkup() { - let markup = "<" + this.type; - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - markup += " " + attr + '="'; - markup += utils.escape(this.attributes[attr]); - markup += '"'; - } - } - - if (this.classes.length > 0) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - markup += ">"; - - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ""; - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText, but escaped. - */ - toText() { - return this.children.map((child) => child.toText()).join(""); - } -} - -/** - * This node represents a piece of text. - */ -class TextNode { - constructor(text) { - this.text = text; - } - - /** - * Converts the text node into a DOM text node. - */ - toNode() { - return document.createTextNode(this.text); - } - - /** - * Converts the text node into escaped HTML markup - * (representing the text itself). - */ - toMarkup() { - return utils.escape(this.toText()); - } - - /** - * Converts the text node into a string - * (representing the text iteself). - */ - toText() { - return this.text; - } -} - -// Do not make an the only child of a . -// An acts as its own implicit . -const wrapWithMstyle = expression => { - let node; - if (expression.length === 1 && expression[0].type === "mrow") { - node = expression.pop(); - node.type = "mstyle"; - } else { - node = new MathNode("mstyle", expression); - } - return node -}; - -var mathMLTree = { - MathNode, - TextNode, - newDocumentFragment -}; - -/** - * This file provides support for building horizontal stretchy elements. - */ - -const stretchyCodePoint = { - widehat: "^", - widecheck: "ˇ", - widetilde: "~", - wideparen: "⏜", // \u23dc - utilde: "~", - overleftarrow: "\u2190", - underleftarrow: "\u2190", - xleftarrow: "\u2190", - overrightarrow: "\u2192", - underrightarrow: "\u2192", - xrightarrow: "\u2192", - underbrace: "\u23df", - overbrace: "\u23de", - overgroup: "\u23e0", - overparen: "⏜", - undergroup: "\u23e1", - underparen: "\u23dd", - overleftrightarrow: "\u2194", - underleftrightarrow: "\u2194", - xleftrightarrow: "\u2194", - Overrightarrow: "\u21d2", - xRightarrow: "\u21d2", - overleftharpoon: "\u21bc", - xleftharpoonup: "\u21bc", - overrightharpoon: "\u21c0", - xrightharpoonup: "\u21c0", - xLeftarrow: "\u21d0", - xLeftrightarrow: "\u21d4", - xhookleftarrow: "\u21a9", - xhookrightarrow: "\u21aa", - xmapsto: "\u21a6", - xrightharpoondown: "\u21c1", - xleftharpoondown: "\u21bd", - xtwoheadleftarrow: "\u219e", - xtwoheadrightarrow: "\u21a0", - xlongequal: "=", - xrightleftarrows: "\u21c4", - yields: "\u2192", - yieldsLeft: "\u2190", - mesomerism: "\u2194", - longrightharpoonup: "\u21c0", - longleftharpoondown: "\u21bd", - eqrightharpoonup: "\u21c0", - eqleftharpoondown: "\u21bd", - "\\cdrightarrow": "\u2192", - "\\cdleftarrow": "\u2190", - "\\cdlongequal": "=" -}; - -const mathMLnode = function(label) { - const child = new mathMLTree.TextNode(stretchyCodePoint[label.slice(1)]); - const node = new mathMLTree.MathNode("mo", [child]); - node.setAttribute("stretchy", "true"); - return node -}; - -var stretchy = { - mathMLnode -}; - -/** - * This file holds a list of all no-argument functions and single-character - * symbols (like 'a' or ';'). - * - * For each of the symbols, there are two properties they can have: - * - group (required): the ParseNode group type the symbol should have (i.e. - "textord", "mathord", etc). - * - replace: the character that this symbol or function should be - * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi - * character in the main font). - * - * The outermost map in the table indicates what mode the symbols should be - * accepted in (e.g. "math" or "text"). - */ - -// Some of these have a "-token" suffix since these are also used as `ParseNode` -// types for raw text tokens, and we want to avoid conflicts with higher-level -// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by -// looking up the `symbols` map. -const ATOMS = { - bin: 1, - close: 1, - inner: 1, - open: 1, - punct: 1, - rel: 1 -}; -const NON_ATOMS = { - "accent-token": 1, - mathord: 1, - "op-token": 1, - spacing: 1, - textord: 1 -}; - -const symbols = { - math: {}, - text: {} -}; - -/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ -function defineSymbol(mode, group, replace, name, acceptUnicodeChar) { - symbols[mode][name] = { group, replace }; - - if (acceptUnicodeChar && replace) { - symbols[mode][replace] = symbols[mode][name]; - } -} - -// Some abbreviations for commonly used strings. -// This helps minify the code, and also spotting typos using jshint. - -// modes: -const math = "math"; -const text = "text"; - -// groups: -const accent = "accent-token"; -const bin = "bin"; -const close = "close"; -const inner = "inner"; -const mathord = "mathord"; -const op = "op-token"; -const open = "open"; -const punct = "punct"; -const rel = "rel"; -const spacing = "spacing"; -const textord = "textord"; - -// Now comes the symbol table - -// Relation Symbols -defineSymbol(math, rel, "\u2261", "\\equiv", true); -defineSymbol(math, rel, "\u227a", "\\prec", true); -defineSymbol(math, rel, "\u227b", "\\succ", true); -defineSymbol(math, rel, "\u223c", "\\sim", true); -defineSymbol(math, rel, "\u27c2", "\\perp", true); -defineSymbol(math, rel, "\u2aaf", "\\preceq", true); -defineSymbol(math, rel, "\u2ab0", "\\succeq", true); -defineSymbol(math, rel, "\u2243", "\\simeq", true); -defineSymbol(math, rel, "\u224c", "\\backcong", true); -defineSymbol(math, rel, "|", "\\mid", true); -defineSymbol(math, rel, "\u226a", "\\ll", true); -defineSymbol(math, rel, "\u226b", "\\gg", true); -defineSymbol(math, rel, "\u224d", "\\asymp", true); -defineSymbol(math, rel, "\u2225", "\\parallel"); -defineSymbol(math, rel, "\u22c8", "\\bowtie", true); -defineSymbol(math, rel, "\u2323", "\\smile", true); -defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true); -defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true); -defineSymbol(math, rel, "\u2250", "\\doteq", true); -defineSymbol(math, rel, "\u2322", "\\frown", true); -defineSymbol(math, rel, "\u220b", "\\ni", true); -defineSymbol(math, rel, "\u220c", "\\notni", true); -defineSymbol(math, rel, "\u221d", "\\propto", true); -defineSymbol(math, rel, "\u22a2", "\\vdash", true); -defineSymbol(math, rel, "\u22a3", "\\dashv", true); -defineSymbol(math, rel, "\u220b", "\\owns"); -defineSymbol(math, rel, "\u2258", "\\arceq", true); -defineSymbol(math, rel, "\u2259", "\\wedgeq", true); -defineSymbol(math, rel, "\u225a", "\\veeeq", true); -defineSymbol(math, rel, "\u225b", "\\stareq", true); -defineSymbol(math, rel, "\u225d", "\\eqdef", true); -defineSymbol(math, rel, "\u225e", "\\measeq", true); -defineSymbol(math, rel, "\u225f", "\\questeq", true); -defineSymbol(math, rel, "\u2260", "\\ne", true); -defineSymbol(math, rel, "\u2260", "\\neq"); -// mathtools.sty -defineSymbol(math, rel, "\u2237", "\\dblcolon", true); -defineSymbol(math, rel, "\u2254", "\\coloneqq", true); -defineSymbol(math, rel, "\u2255", "\\eqqcolon", true); -defineSymbol(math, rel, "\u2239", "\\eqcolon", true); -defineSymbol(math, rel, "\u2A74", "\\Coloneqq", true); - -// Punctuation -defineSymbol(math, punct, "\u002e", "\\ldotp"); -defineSymbol(math, punct, "\u00b7", "\\cdotp"); - -// Misc Symbols -defineSymbol(math, textord, "\u0023", "\\#"); -defineSymbol(text, textord, "\u0023", "\\#"); -defineSymbol(math, textord, "\u0026", "\\&"); -defineSymbol(text, textord, "\u0026", "\\&"); -defineSymbol(math, textord, "\u2135", "\\aleph", true); -defineSymbol(math, textord, "\u2200", "\\forall", true); -defineSymbol(math, textord, "\u210f", "\\hbar", true); -defineSymbol(math, textord, "\u2203", "\\exists", true); -defineSymbol(math, textord, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\AA", true); -defineSymbol(text, textord, "Å", "\\AA", true); -defineSymbol(math, textord, "\u2663", "\\clubsuit", true); -defineSymbol(math, textord, "\u2667", "\\varclubsuit", true); -defineSymbol(math, textord, "\u2118", "\\wp", true); -defineSymbol(math, textord, "\u266f", "\\sharp", true); -defineSymbol(math, textord, "\u2662", "\\diamondsuit", true); -defineSymbol(math, textord, "\u2666", "\\vardiamondsuit", true); -defineSymbol(math, textord, "\u211c", "\\Re", true); -defineSymbol(math, textord, "\u2661", "\\heartsuit", true); -defineSymbol(math, textord, "\u2665", "\\varheartsuit", true); -defineSymbol(math, textord, "\u2111", "\\Im", true); -defineSymbol(math, textord, "\u2660", "\\spadesuit", true); -defineSymbol(math, textord, "\u2664", "\\varspadesuit", true); -defineSymbol(math, textord, "\u2640", "\\female", true); -defineSymbol(math, textord, "\u2642", "\\male", true); -defineSymbol(math, textord, "\u00a7", "\\S", true); -defineSymbol(text, textord, "\u00a7", "\\S"); -defineSymbol(math, textord, "\u00b6", "\\P", true); -defineSymbol(text, textord, "\u00b6", "\\P"); -defineSymbol(text, textord, "\u263a", "\\smiley", true); -defineSymbol(math, textord, "\u263a", "\\smiley", true); - -// Math and Text -defineSymbol(math, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\textdagger"); -defineSymbol(math, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\textdaggerdbl"); - -// Large Delimiters -defineSymbol(math, close, "\u23b1", "\\rmoustache", true); -defineSymbol(math, open, "\u23b0", "\\lmoustache", true); -defineSymbol(math, close, "\u27ef", "\\rgroup", true); -defineSymbol(math, open, "\u27ee", "\\lgroup", true); - -// Binary Operators -defineSymbol(math, bin, "\u2213", "\\mp", true); -defineSymbol(math, bin, "\u2296", "\\ominus", true); -defineSymbol(math, bin, "\u228e", "\\uplus", true); -defineSymbol(math, bin, "\u2293", "\\sqcap", true); -defineSymbol(math, bin, "\u2217", "\\ast"); -defineSymbol(math, bin, "\u2294", "\\sqcup", true); -defineSymbol(math, bin, "\u25ef", "\\bigcirc", true); -defineSymbol(math, bin, "\u2219", "\\bullet", true); -defineSymbol(math, bin, "\u2021", "\\ddagger"); -defineSymbol(math, bin, "\u2240", "\\wr", true); -defineSymbol(math, bin, "\u2a3f", "\\amalg"); -defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath - -// Arrow Symbols -defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true); -defineSymbol(math, rel, "\u21d0", "\\Leftarrow", true); -defineSymbol(math, rel, "\u27f8", "\\Longleftarrow", true); -defineSymbol(math, rel, "\u27f6", "\\longrightarrow", true); -defineSymbol(math, rel, "\u21d2", "\\Rightarrow", true); -defineSymbol(math, rel, "\u27f9", "\\Longrightarrow", true); -defineSymbol(math, rel, "\u2194", "\\leftrightarrow", true); -defineSymbol(math, rel, "\u27f7", "\\longleftrightarrow", true); -defineSymbol(math, rel, "\u21d4", "\\Leftrightarrow", true); -defineSymbol(math, rel, "\u27fa", "\\Longleftrightarrow", true); -defineSymbol(math, rel, "\u21a6", "\\mapsto", true); -defineSymbol(math, rel, "\u27fc", "\\longmapsto", true); -defineSymbol(math, rel, "\u2197", "\\nearrow", true); -defineSymbol(math, rel, "\u21a9", "\\hookleftarrow", true); -defineSymbol(math, rel, "\u21aa", "\\hookrightarrow", true); -defineSymbol(math, rel, "\u2198", "\\searrow", true); -defineSymbol(math, rel, "\u21bc", "\\leftharpoonup", true); -defineSymbol(math, rel, "\u21c0", "\\rightharpoonup", true); -defineSymbol(math, rel, "\u2199", "\\swarrow", true); -defineSymbol(math, rel, "\u21bd", "\\leftharpoondown", true); -defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true); -defineSymbol(math, rel, "\u2196", "\\nwarrow", true); -defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true); -defineSymbol(math, mathord, "\u21af", "\\lightning", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); - -// AMS Negated Binary Relations -defineSymbol(math, rel, "\u226e", "\\nless", true); -// Symbol names preceeded by "@" each have a corresponding macro. -defineSymbol(math, rel, "\u2a87", "\\lneq", true); -defineSymbol(math, rel, "\u2268", "\\lneqq", true); -defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq"); -defineSymbol(math, rel, "\u22e6", "\\lnsim", true); -defineSymbol(math, rel, "\u2a89", "\\lnapprox", true); -defineSymbol(math, rel, "\u2280", "\\nprec", true); -// unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e0", "\\npreceq", true); -defineSymbol(math, rel, "\u22e8", "\\precnsim", true); -defineSymbol(math, rel, "\u2ab9", "\\precnapprox", true); -defineSymbol(math, rel, "\u2241", "\\nsim", true); -defineSymbol(math, rel, "\u2224", "\\nmid", true); -defineSymbol(math, rel, "\u2224", "\\nshortmid"); -defineSymbol(math, rel, "\u22ac", "\\nvdash", true); -defineSymbol(math, rel, "\u22ad", "\\nvDash", true); -defineSymbol(math, rel, "\u22ea", "\\ntriangleleft"); -defineSymbol(math, rel, "\u22ec", "\\ntrianglelefteq", true); -defineSymbol(math, rel, "\u2284", "\\nsubset", true); -defineSymbol(math, rel, "\u2285", "\\nsupset", true); -defineSymbol(math, rel, "\u228a", "\\subsetneq", true); -defineSymbol(math, rel, "\u228a\ufe00", "\\varsubsetneq"); -defineSymbol(math, rel, "\u2acb", "\\subsetneqq", true); -defineSymbol(math, rel, "\u2acb\ufe00", "\\varsubsetneqq"); -defineSymbol(math, rel, "\u226f", "\\ngtr", true); -defineSymbol(math, rel, "\u2a88", "\\gneq", true); -defineSymbol(math, rel, "\u2269", "\\gneqq", true); -defineSymbol(math, rel, "\u2269\ufe00", "\\gvertneqq"); -defineSymbol(math, rel, "\u22e7", "\\gnsim", true); -defineSymbol(math, rel, "\u2a8a", "\\gnapprox", true); -defineSymbol(math, rel, "\u2281", "\\nsucc", true); -// unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e1", "\\nsucceq", true); -defineSymbol(math, rel, "\u22e9", "\\succnsim", true); -defineSymbol(math, rel, "\u2aba", "\\succnapprox", true); -// unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u2246", "\\ncong", true); -defineSymbol(math, rel, "\u2226", "\\nparallel", true); -defineSymbol(math, rel, "\u2226", "\\nshortparallel"); -defineSymbol(math, rel, "\u22af", "\\nVDash", true); -defineSymbol(math, rel, "\u22eb", "\\ntriangleright"); -defineSymbol(math, rel, "\u22ed", "\\ntrianglerighteq", true); -defineSymbol(math, rel, "\u228b", "\\supsetneq", true); -defineSymbol(math, rel, "\u228b", "\\varsupsetneq"); -defineSymbol(math, rel, "\u2acc", "\\supsetneqq", true); -defineSymbol(math, rel, "\u2acc\ufe00", "\\varsupsetneqq"); -defineSymbol(math, rel, "\u22ae", "\\nVdash", true); -defineSymbol(math, rel, "\u2ab5", "\\precneqq", true); -defineSymbol(math, rel, "\u2ab6", "\\succneqq", true); -defineSymbol(math, bin, "\u22b4", "\\unlhd"); -defineSymbol(math, bin, "\u22b5", "\\unrhd"); - -// AMS Negated Arrows -defineSymbol(math, rel, "\u219a", "\\nleftarrow", true); -defineSymbol(math, rel, "\u219b", "\\nrightarrow", true); -defineSymbol(math, rel, "\u21cd", "\\nLeftarrow", true); -defineSymbol(math, rel, "\u21cf", "\\nRightarrow", true); -defineSymbol(math, rel, "\u21ae", "\\nleftrightarrow", true); -defineSymbol(math, rel, "\u21ce", "\\nLeftrightarrow", true); - -// AMS Misc -defineSymbol(math, rel, "\u25b3", "\\vartriangle"); -defineSymbol(math, textord, "\u210f", "\\hslash"); -defineSymbol(math, textord, "\u25bd", "\\triangledown"); -defineSymbol(math, textord, "\u25ca", "\\lozenge"); -defineSymbol(math, textord, "\u24c8", "\\circledS"); -defineSymbol(math, textord, "\u00ae", "\\circledR", true); -defineSymbol(text, textord, "\u00ae", "\\circledR"); -defineSymbol(text, textord, "\u00ae", "\\textregistered"); -defineSymbol(math, textord, "\u2221", "\\measuredangle", true); -defineSymbol(math, textord, "\u2204", "\\nexists"); -defineSymbol(math, textord, "\u2127", "\\mho"); -defineSymbol(math, textord, "\u2132", "\\Finv", true); -defineSymbol(math, textord, "\u2141", "\\Game", true); -defineSymbol(math, textord, "\u2035", "\\backprime"); -defineSymbol(math, textord, "\u25b2", "\\blacktriangle"); -defineSymbol(math, textord, "\u25bc", "\\blacktriangledown"); -defineSymbol(math, textord, "\u25a0", "\\blacksquare"); -defineSymbol(math, textord, "\u29eb", "\\blacklozenge"); -defineSymbol(math, textord, "\u2605", "\\bigstar"); -defineSymbol(math, textord, "\u2222", "\\sphericalangle", true); -defineSymbol(math, textord, "\u2201", "\\complement", true); -// unicode-math maps U+F0 to \matheth. We map to AMS function \eth -defineSymbol(math, textord, "\u00f0", "\\eth", true); -defineSymbol(text, textord, "\u00f0", "\u00f0"); -defineSymbol(math, textord, "\u2571", "\\diagup"); -defineSymbol(math, textord, "\u2572", "\\diagdown"); -defineSymbol(math, textord, "\u25a1", "\\square"); -defineSymbol(math, textord, "\u25a1", "\\Box"); -defineSymbol(math, textord, "\u25ca", "\\Diamond"); -// unicode-math maps U+A5 to \mathyen. We map to AMS function \yen -defineSymbol(math, textord, "\u00a5", "\\yen", true); -defineSymbol(text, textord, "\u00a5", "\\yen", true); -defineSymbol(math, textord, "\u2713", "\\checkmark", true); -defineSymbol(text, textord, "\u2713", "\\checkmark"); -defineSymbol(math, textord, "\u2717", "\\ballotx", true); -defineSymbol(text, textord, "\u2717", "\\ballotx"); -defineSymbol(text, textord, "\u2022", "\\textbullet"); - -// AMS Hebrew -defineSymbol(math, textord, "\u2136", "\\beth", true); -defineSymbol(math, textord, "\u2138", "\\daleth", true); -defineSymbol(math, textord, "\u2137", "\\gimel", true); - -// AMS Greek -defineSymbol(math, textord, "\u03dd", "\\digamma", true); -defineSymbol(math, textord, "\u03f0", "\\varkappa"); - -// AMS Delimiters -defineSymbol(math, open, "\u231C", "\\ulcorner", true); -defineSymbol(math, close, "\u231D", "\\urcorner", true); -defineSymbol(math, open, "\u231E", "\\llcorner", true); -defineSymbol(math, close, "\u231F", "\\lrcorner", true); - -// AMS Binary Relations -defineSymbol(math, rel, "\u2266", "\\leqq", true); -defineSymbol(math, rel, "\u2a7d", "\\leqslant", true); -defineSymbol(math, rel, "\u2a95", "\\eqslantless", true); -defineSymbol(math, rel, "\u2272", "\\lesssim", true); -defineSymbol(math, rel, "\u2a85", "\\lessapprox", true); -defineSymbol(math, rel, "\u224a", "\\approxeq", true); -defineSymbol(math, bin, "\u22d6", "\\lessdot"); -defineSymbol(math, rel, "\u22d8", "\\lll", true); -defineSymbol(math, rel, "\u2276", "\\lessgtr", true); -defineSymbol(math, rel, "\u22da", "\\lesseqgtr", true); -defineSymbol(math, rel, "\u2a8b", "\\lesseqqgtr", true); -defineSymbol(math, rel, "\u2251", "\\doteqdot"); -defineSymbol(math, rel, "\u2253", "\\risingdotseq", true); -defineSymbol(math, rel, "\u2252", "\\fallingdotseq", true); -defineSymbol(math, rel, "\u223d", "\\backsim", true); -defineSymbol(math, rel, "\u22cd", "\\backsimeq", true); -defineSymbol(math, rel, "\u2ac5", "\\subseteqq", true); -defineSymbol(math, rel, "\u22d0", "\\Subset", true); -defineSymbol(math, rel, "\u228f", "\\sqsubset", true); -defineSymbol(math, rel, "\u227c", "\\preccurlyeq", true); -defineSymbol(math, rel, "\u22de", "\\curlyeqprec", true); -defineSymbol(math, rel, "\u227e", "\\precsim", true); -defineSymbol(math, rel, "\u2ab7", "\\precapprox", true); -defineSymbol(math, rel, "\u22b2", "\\vartriangleleft"); -defineSymbol(math, rel, "\u22b4", "\\trianglelefteq"); -defineSymbol(math, rel, "\u22a8", "\\vDash", true); -defineSymbol(math, rel, "\u22aa", "\\Vvdash", true); -defineSymbol(math, rel, "\u2323", "\\smallsmile"); -defineSymbol(math, rel, "\u2322", "\\smallfrown"); -defineSymbol(math, rel, "\u224f", "\\bumpeq", true); -defineSymbol(math, rel, "\u224e", "\\Bumpeq", true); -defineSymbol(math, rel, "\u2267", "\\geqq", true); -defineSymbol(math, rel, "\u2a7e", "\\geqslant", true); -defineSymbol(math, rel, "\u2a96", "\\eqslantgtr", true); -defineSymbol(math, rel, "\u2273", "\\gtrsim", true); -defineSymbol(math, rel, "\u2a86", "\\gtrapprox", true); -defineSymbol(math, bin, "\u22d7", "\\gtrdot"); -defineSymbol(math, rel, "\u22d9", "\\ggg", true); -defineSymbol(math, rel, "\u2277", "\\gtrless", true); -defineSymbol(math, rel, "\u22db", "\\gtreqless", true); -defineSymbol(math, rel, "\u2a8c", "\\gtreqqless", true); -defineSymbol(math, rel, "\u2256", "\\eqcirc", true); -defineSymbol(math, rel, "\u2257", "\\circeq", true); -defineSymbol(math, rel, "\u225c", "\\triangleq", true); -defineSymbol(math, rel, "\u223c", "\\thicksim"); -defineSymbol(math, rel, "\u2248", "\\thickapprox"); -defineSymbol(math, rel, "\u2ac6", "\\supseteqq", true); -defineSymbol(math, rel, "\u22d1", "\\Supset", true); -defineSymbol(math, rel, "\u2290", "\\sqsupset", true); -defineSymbol(math, rel, "\u227d", "\\succcurlyeq", true); -defineSymbol(math, rel, "\u22df", "\\curlyeqsucc", true); -defineSymbol(math, rel, "\u227f", "\\succsim", true); -defineSymbol(math, rel, "\u2ab8", "\\succapprox", true); -defineSymbol(math, rel, "\u22b3", "\\vartriangleright"); -defineSymbol(math, rel, "\u22b5", "\\trianglerighteq"); -defineSymbol(math, rel, "\u22a9", "\\Vdash", true); -defineSymbol(math, rel, "\u2223", "\\shortmid"); -defineSymbol(math, rel, "\u2225", "\\shortparallel"); -defineSymbol(math, rel, "\u226c", "\\between", true); -defineSymbol(math, rel, "\u22d4", "\\pitchfork", true); -defineSymbol(math, rel, "\u221d", "\\varpropto"); -defineSymbol(math, rel, "\u25c0", "\\blacktriangleleft"); -// unicode-math says that \therefore is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2234", "\\therefore", true); -defineSymbol(math, rel, "\u220d", "\\backepsilon"); -defineSymbol(math, rel, "\u25b6", "\\blacktriangleright"); -// unicode-math says that \because is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2235", "\\because", true); -defineSymbol(math, rel, "\u22d8", "\\llless"); -defineSymbol(math, rel, "\u22d9", "\\gggtr"); -defineSymbol(math, bin, "\u22b2", "\\lhd"); -defineSymbol(math, bin, "\u22b3", "\\rhd"); -defineSymbol(math, rel, "\u2242", "\\eqsim", true); -defineSymbol(math, rel, "\u22c8", "\\Join"); -defineSymbol(math, rel, "\u2251", "\\Doteq", true); -defineSymbol(math, rel, "\u297d", "\\strictif", true); -defineSymbol(math, rel, "\u297c", "\\strictfi", true); - -// AMS Binary Operators -defineSymbol(math, bin, "\u2214", "\\dotplus", true); -defineSymbol(math, bin, "\u2216", "\\smallsetminus"); -defineSymbol(math, bin, "\u22d2", "\\Cap", true); -defineSymbol(math, bin, "\u22d3", "\\Cup", true); -defineSymbol(math, bin, "\u2a5e", "\\doublebarwedge", true); -defineSymbol(math, bin, "\u229f", "\\boxminus", true); -defineSymbol(math, bin, "\u229e", "\\boxplus", true); -defineSymbol(math, bin, "\u22c7", "\\divideontimes", true); -defineSymbol(math, bin, "\u22c9", "\\ltimes", true); -defineSymbol(math, bin, "\u22ca", "\\rtimes", true); -defineSymbol(math, bin, "\u22cb", "\\leftthreetimes", true); -defineSymbol(math, bin, "\u22cc", "\\rightthreetimes", true); -defineSymbol(math, bin, "\u22cf", "\\curlywedge", true); -defineSymbol(math, bin, "\u22ce", "\\curlyvee", true); -defineSymbol(math, bin, "\u229d", "\\circleddash", true); -defineSymbol(math, bin, "\u229b", "\\circledast", true); -defineSymbol(math, bin, "\u22ba", "\\intercal", true); -defineSymbol(math, bin, "\u22d2", "\\doublecap"); -defineSymbol(math, bin, "\u22d3", "\\doublecup"); -defineSymbol(math, bin, "\u22a0", "\\boxtimes", true); - -// AMS Arrows -// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. -// We'll map it to AMS function \dashrightarrow. It produces the same atom. -defineSymbol(math, rel, "\u21e2", "\\dashrightarrow", true); -// unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21e0", "\\dashleftarrow", true); -defineSymbol(math, rel, "\u21c7", "\\leftleftarrows", true); -defineSymbol(math, rel, "\u21c6", "\\leftrightarrows", true); -defineSymbol(math, rel, "\u21da", "\\Lleftarrow", true); -defineSymbol(math, rel, "\u219e", "\\twoheadleftarrow", true); -defineSymbol(math, rel, "\u21a2", "\\leftarrowtail", true); -defineSymbol(math, rel, "\u21ab", "\\looparrowleft", true); -defineSymbol(math, rel, "\u21cb", "\\leftrightharpoons", true); -defineSymbol(math, rel, "\u21b6", "\\curvearrowleft", true); -// unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21ba", "\\circlearrowleft", true); -defineSymbol(math, rel, "\u21b0", "\\Lsh", true); -defineSymbol(math, rel, "\u21c8", "\\upuparrows", true); -defineSymbol(math, rel, "\u21bf", "\\upharpoonleft", true); -defineSymbol(math, rel, "\u21c3", "\\downharpoonleft", true); -defineSymbol(math, rel, "\u22b6", "\\origof", true); -defineSymbol(math, rel, "\u22b7", "\\imageof", true); -defineSymbol(math, rel, "\u22b8", "\\multimap", true); -defineSymbol(math, rel, "\u21ad", "\\leftrightsquigarrow", true); -defineSymbol(math, rel, "\u21c9", "\\rightrightarrows", true); -defineSymbol(math, rel, "\u21c4", "\\rightleftarrows", true); -defineSymbol(math, rel, "\u21a0", "\\twoheadrightarrow", true); -defineSymbol(math, rel, "\u21a3", "\\rightarrowtail", true); -defineSymbol(math, rel, "\u21ac", "\\looparrowright", true); -defineSymbol(math, rel, "\u21b7", "\\curvearrowright", true); -// unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21bb", "\\circlearrowright", true); -defineSymbol(math, rel, "\u21b1", "\\Rsh", true); -defineSymbol(math, rel, "\u21ca", "\\downdownarrows", true); -defineSymbol(math, rel, "\u21be", "\\upharpoonright", true); -defineSymbol(math, rel, "\u21c2", "\\downharpoonright", true); -defineSymbol(math, rel, "\u21dd", "\\rightsquigarrow", true); -defineSymbol(math, rel, "\u21dd", "\\leadsto"); -defineSymbol(math, rel, "\u21db", "\\Rrightarrow", true); -defineSymbol(math, rel, "\u21be", "\\restriction"); - -defineSymbol(math, textord, "\u2018", "`"); -defineSymbol(math, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\textdollar"); -defineSymbol(math, textord, "%", "\\%"); -defineSymbol(text, textord, "%", "\\%"); -defineSymbol(math, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\textunderscore"); -defineSymbol(text, textord, "\u2423", "\\textvisiblespace", true); -defineSymbol(math, textord, "\u2220", "\\angle", true); -defineSymbol(math, textord, "\u221e", "\\infty", true); -defineSymbol(math, textord, "\u2032", "\\prime"); -defineSymbol(math, textord, "\u25b3", "\\triangle"); -defineSymbol(text, textord, "\u0391", "\\Alpha", true); -defineSymbol(text, textord, "\u0392", "\\Beta", true); -defineSymbol(text, textord, "\u0393", "\\Gamma", true); -defineSymbol(text, textord, "\u0394", "\\Delta", true); -defineSymbol(text, textord, "\u0395", "\\Epsilon", true); -defineSymbol(text, textord, "\u0396", "\\Zeta", true); -defineSymbol(text, textord, "\u0397", "\\Eta", true); -defineSymbol(text, textord, "\u0398", "\\Theta", true); -defineSymbol(text, textord, "\u0399", "\\Iota", true); -defineSymbol(text, textord, "\u039a", "\\Kappa", true); -defineSymbol(text, textord, "\u039b", "\\Lambda", true); -defineSymbol(text, textord, "\u039c", "\\Mu", true); -defineSymbol(text, textord, "\u039d", "\\Nu", true); -defineSymbol(text, textord, "\u039e", "\\Xi", true); -defineSymbol(text, textord, "\u039f", "\\Omicron", true); -defineSymbol(text, textord, "\u03a0", "\\Pi", true); -defineSymbol(text, textord, "\u03a1", "\\Rho", true); -defineSymbol(text, textord, "\u03a3", "\\Sigma", true); -defineSymbol(text, textord, "\u03a4", "\\Tau", true); -defineSymbol(text, textord, "\u03a5", "\\Upsilon", true); -defineSymbol(text, textord, "\u03a6", "\\Phi", true); -defineSymbol(text, textord, "\u03a7", "\\Chi", true); -defineSymbol(text, textord, "\u03a8", "\\Psi", true); -defineSymbol(text, textord, "\u03a9", "\\Omega", true); -defineSymbol(math, mathord, "\u0391", "\\Alpha", true); -defineSymbol(math, mathord, "\u0392", "\\Beta", true); -defineSymbol(math, mathord, "\u0393", "\\Gamma", true); -defineSymbol(math, mathord, "\u0394", "\\Delta", true); -defineSymbol(math, mathord, "\u0395", "\\Epsilon", true); -defineSymbol(math, mathord, "\u0396", "\\Zeta", true); -defineSymbol(math, mathord, "\u0397", "\\Eta", true); -defineSymbol(math, mathord, "\u0398", "\\Theta", true); -defineSymbol(math, mathord, "\u0399", "\\Iota", true); -defineSymbol(math, mathord, "\u039a", "\\Kappa", true); -defineSymbol(math, mathord, "\u039b", "\\Lambda", true); -defineSymbol(math, mathord, "\u039c", "\\Mu", true); -defineSymbol(math, mathord, "\u039d", "\\Nu", true); -defineSymbol(math, mathord, "\u039e", "\\Xi", true); -defineSymbol(math, mathord, "\u039f", "\\Omicron", true); -defineSymbol(math, mathord, "\u03a0", "\\Pi", true); -defineSymbol(math, mathord, "\u03a1", "\\Rho", true); -defineSymbol(math, mathord, "\u03a3", "\\Sigma", true); -defineSymbol(math, mathord, "\u03a4", "\\Tau", true); -defineSymbol(math, mathord, "\u03a5", "\\Upsilon", true); -defineSymbol(math, mathord, "\u03a6", "\\Phi", true); -defineSymbol(math, mathord, "\u03a7", "\\Chi", true); -defineSymbol(math, mathord, "\u03a8", "\\Psi", true); -defineSymbol(math, mathord, "\u03a9", "\\Omega", true); -defineSymbol(math, open, "\u00ac", "\\neg", true); -defineSymbol(math, open, "\u00ac", "\\lnot"); -defineSymbol(math, textord, "\u22a4", "\\top"); -defineSymbol(math, textord, "\u22a5", "\\bot"); -defineSymbol(math, textord, "\u2205", "\\emptyset"); -defineSymbol(math, textord, "\u00f8", "\\varnothing"); -defineSymbol(math, mathord, "\u03b1", "\\alpha", true); -defineSymbol(math, mathord, "\u03b2", "\\beta", true); -defineSymbol(math, mathord, "\u03b3", "\\gamma", true); -defineSymbol(math, mathord, "\u03b4", "\\delta", true); -defineSymbol(math, mathord, "\u03f5", "\\epsilon", true); -defineSymbol(math, mathord, "\u03b6", "\\zeta", true); -defineSymbol(math, mathord, "\u03b7", "\\eta", true); -defineSymbol(math, mathord, "\u03b8", "\\theta", true); -defineSymbol(math, mathord, "\u03b9", "\\iota", true); -defineSymbol(math, mathord, "\u03ba", "\\kappa", true); -defineSymbol(math, mathord, "\u03bb", "\\lambda", true); -defineSymbol(math, mathord, "\u03bc", "\\mu", true); -defineSymbol(math, mathord, "\u03bd", "\\nu", true); -defineSymbol(math, mathord, "\u03be", "\\xi", true); -defineSymbol(math, mathord, "\u03bf", "\\omicron", true); -defineSymbol(math, mathord, "\u03c0", "\\pi", true); -defineSymbol(math, mathord, "\u03c1", "\\rho", true); -defineSymbol(math, mathord, "\u03c3", "\\sigma", true); -defineSymbol(math, mathord, "\u03c4", "\\tau", true); -defineSymbol(math, mathord, "\u03c5", "\\upsilon", true); -defineSymbol(math, mathord, "\u03d5", "\\phi", true); -defineSymbol(math, mathord, "\u03c7", "\\chi", true); -defineSymbol(math, mathord, "\u03c8", "\\psi", true); -defineSymbol(math, mathord, "\u03c9", "\\omega", true); -defineSymbol(math, mathord, "\u03b5", "\\varepsilon", true); -defineSymbol(math, mathord, "\u03d1", "\\vartheta", true); -defineSymbol(math, mathord, "\u03d6", "\\varpi", true); -defineSymbol(math, mathord, "\u03f1", "\\varrho", true); -defineSymbol(math, mathord, "\u03c2", "\\varsigma", true); -defineSymbol(math, mathord, "\u03c6", "\\varphi", true); -defineSymbol(math, mathord, "\u03d8", "\\Coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\varcoppa", true); -defineSymbol(math, mathord, "\u03de", "\\Koppa", true); -defineSymbol(math, mathord, "\u03df", "\\koppa", true); -defineSymbol(math, mathord, "\u03e0", "\\Sampi", true); -defineSymbol(math, mathord, "\u03e1", "\\sampi", true); -defineSymbol(math, mathord, "\u03da", "\\Stigma", true); -defineSymbol(math, mathord, "\u03db", "\\stigma", true); -defineSymbol(math, mathord, "\u2aeb", "\\Bot"); -defineSymbol(math, bin, "\u2217", "\u2217", true); -defineSymbol(math, bin, "+", "+"); -defineSymbol(math, bin, "*", "*"); -defineSymbol(math, bin, "\u2044", "\u2044"); -defineSymbol(math, bin, "\u2212", "-", true); -defineSymbol(math, bin, "\u22c5", "\\cdot", true); -defineSymbol(math, bin, "\u2218", "\\circ", true); -defineSymbol(math, bin, "\u00f7", "\\div", true); -defineSymbol(math, bin, "\u00b1", "\\pm", true); -defineSymbol(math, bin, "\u00d7", "\\times", true); -defineSymbol(math, bin, "\u2229", "\\cap", true); -defineSymbol(math, bin, "\u222a", "\\cup", true); -defineSymbol(math, bin, "\u2216", "\\setminus", true); -defineSymbol(math, bin, "\u2227", "\\land"); -defineSymbol(math, bin, "\u2228", "\\lor"); -defineSymbol(math, bin, "\u2227", "\\wedge", true); -defineSymbol(math, bin, "\u2228", "\\vee", true); -defineSymbol(math, open, "\u27e6", "\\llbracket", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u27e7", "\\rrbracket", true); -defineSymbol(math, open, "\u27e8", "\\langle", true); -defineSymbol(math, open, "|", "\\lvert"); -defineSymbol(math, open, "\u2016", "\\lVert"); -defineSymbol(math, textord, "!", "\\oc"); // cmll package -defineSymbol(math, textord, "?", "\\wn"); -defineSymbol(math, textord, "\u2193", "\\shpos"); -defineSymbol(math, textord, "\u2195", "\\shift"); -defineSymbol(math, textord, "\u2191", "\\shneg"); -defineSymbol(math, close, "?", "?"); -defineSymbol(math, close, "!", "!"); -defineSymbol(math, close, "‼", "‼"); -defineSymbol(math, close, "\u27e9", "\\rangle", true); -defineSymbol(math, close, "|", "\\rvert"); -defineSymbol(math, close, "\u2016", "\\rVert"); -defineSymbol(math, open, "\u2983", "\\lBrace", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u2984", "\\rBrace", true); -defineSymbol(math, rel, "=", "\\equal", true); -defineSymbol(math, rel, ":", ":"); -defineSymbol(math, rel, "\u2248", "\\approx", true); -defineSymbol(math, rel, "\u2245", "\\cong", true); -defineSymbol(math, rel, "\u2265", "\\ge"); -defineSymbol(math, rel, "\u2265", "\\geq", true); -defineSymbol(math, rel, "\u2190", "\\gets"); -defineSymbol(math, rel, ">", "\\gt", true); -defineSymbol(math, rel, "\u2208", "\\in", true); -defineSymbol(math, rel, "\u2209", "\\notin", true); -defineSymbol(math, rel, "\ue020", "\\@not"); -defineSymbol(math, rel, "\u2282", "\\subset", true); -defineSymbol(math, rel, "\u2283", "\\supset", true); -defineSymbol(math, rel, "\u2286", "\\subseteq", true); -defineSymbol(math, rel, "\u2287", "\\supseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteqq"); -defineSymbol(math, rel, "\u2289", "\\nsupseteq", true); -defineSymbol(math, rel, "\u2289", "\\nsupseteqq"); -defineSymbol(math, rel, "\u22a8", "\\models"); -defineSymbol(math, rel, "\u2190", "\\leftarrow", true); -defineSymbol(math, rel, "\u2264", "\\le"); -defineSymbol(math, rel, "\u2264", "\\leq", true); -defineSymbol(math, rel, "<", "\\lt", true); -defineSymbol(math, rel, "\u2192", "\\rightarrow", true); -defineSymbol(math, rel, "\u2192", "\\to"); -defineSymbol(math, rel, "\u2271", "\\ngeq", true); -defineSymbol(math, rel, "\u2271", "\\ngeqq"); -defineSymbol(math, rel, "\u2271", "\\ngeqslant"); -defineSymbol(math, rel, "\u2270", "\\nleq", true); -defineSymbol(math, rel, "\u2270", "\\nleqq"); -defineSymbol(math, rel, "\u2270", "\\nleqslant"); -defineSymbol(math, rel, "\u2aeb", "\\Perp", true); //cmll package -defineSymbol(math, spacing, "\u00a0", "\\ "); -defineSymbol(math, spacing, "\u00a0", "\\space"); -// Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% -defineSymbol(math, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(text, spacing, "\u00a0", "\\ "); -defineSymbol(text, spacing, "\u00a0", " "); -defineSymbol(text, spacing, "\u00a0", "\\space"); -defineSymbol(text, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(math, spacing, null, "\\nobreak"); -defineSymbol(math, spacing, null, "\\allowbreak"); -defineSymbol(math, punct, ",", ","); -defineSymbol(text, punct, ":", ":"); -defineSymbol(math, punct, ";", ";"); -defineSymbol(math, bin, "\u22bc", "\\barwedge", true); -defineSymbol(math, bin, "\u22bb", "\\veebar", true); -defineSymbol(math, bin, "\u2299", "\\odot", true); -defineSymbol(math, bin, "\u2295", "\\oplus", true); -defineSymbol(math, bin, "\u2297", "\\otimes", true); -defineSymbol(math, textord, "\u2202", "\\partial", true); -defineSymbol(math, bin, "\u2298", "\\oslash", true); -defineSymbol(math, bin, "\u229a", "\\circledcirc", true); -defineSymbol(math, bin, "\u22a1", "\\boxdot", true); -defineSymbol(math, bin, "\u25b3", "\\bigtriangleup"); -defineSymbol(math, bin, "\u25bd", "\\bigtriangledown"); -defineSymbol(math, bin, "\u2020", "\\dagger"); -defineSymbol(math, bin, "\u22c4", "\\diamond"); -defineSymbol(math, bin, "\u22c6", "\\star"); -defineSymbol(math, bin, "\u25c3", "\\triangleleft"); -defineSymbol(math, bin, "\u25b9", "\\triangleright"); -defineSymbol(math, open, "{", "\\{"); -defineSymbol(text, textord, "{", "\\{"); -defineSymbol(text, textord, "{", "\\textbraceleft"); -defineSymbol(math, close, "}", "\\}"); -defineSymbol(text, textord, "}", "\\}"); -defineSymbol(text, textord, "}", "\\textbraceright"); -defineSymbol(math, open, "{", "\\lbrace"); -defineSymbol(math, close, "}", "\\rbrace"); -defineSymbol(math, open, "[", "\\lbrack", true); -defineSymbol(text, textord, "[", "\\lbrack", true); -defineSymbol(math, close, "]", "\\rbrack", true); -defineSymbol(text, textord, "]", "\\rbrack", true); -defineSymbol(math, open, "(", "\\lparen", true); -defineSymbol(math, close, ")", "\\rparen", true); -defineSymbol(text, textord, "<", "\\textless", true); // in T1 fontenc -defineSymbol(text, textord, ">", "\\textgreater", true); // in T1 fontenc -defineSymbol(math, open, "\u230a", "\\lfloor", true); -defineSymbol(math, close, "\u230b", "\\rfloor", true); -defineSymbol(math, open, "\u2308", "\\lceil", true); -defineSymbol(math, close, "\u2309", "\\rceil", true); -defineSymbol(math, textord, "\\", "\\backslash"); -defineSymbol(math, textord, "|", "|"); -defineSymbol(math, textord, "|", "\\vert"); -defineSymbol(text, textord, "|", "\\textbar", true); // in T1 fontenc -defineSymbol(math, textord, "\u2016", "\\|"); -defineSymbol(math, textord, "\u2016", "\\Vert"); -defineSymbol(text, textord, "\u2016", "\\textbardbl"); -defineSymbol(text, textord, "~", "\\textasciitilde"); -defineSymbol(text, textord, "\\", "\\textbackslash"); -defineSymbol(text, textord, "^", "\\textasciicircum"); -defineSymbol(math, rel, "\u2191", "\\uparrow", true); -defineSymbol(math, rel, "\u21d1", "\\Uparrow", true); -defineSymbol(math, rel, "\u2193", "\\downarrow", true); -defineSymbol(math, rel, "\u21d3", "\\Downarrow", true); -defineSymbol(math, rel, "\u2195", "\\updownarrow", true); -defineSymbol(math, rel, "\u21d5", "\\Updownarrow", true); -defineSymbol(math, op, "\u2210", "\\coprod"); -defineSymbol(math, op, "\u22c1", "\\bigvee"); -defineSymbol(math, op, "\u22c0", "\\bigwedge"); -defineSymbol(math, op, "\u2a04", "\\biguplus"); -defineSymbol(math, op, "\u22c2", "\\bigcap"); -defineSymbol(math, op, "\u22c3", "\\bigcup"); -defineSymbol(math, op, "\u222b", "\\int"); -defineSymbol(math, op, "\u222b", "\\intop"); -defineSymbol(math, op, "\u222c", "\\iint"); -defineSymbol(math, op, "\u222d", "\\iiint"); -defineSymbol(math, op, "\u220f", "\\prod"); -defineSymbol(math, op, "\u2211", "\\sum"); -defineSymbol(math, op, "\u2a02", "\\bigotimes"); -defineSymbol(math, op, "\u2a01", "\\bigoplus"); -defineSymbol(math, op, "\u2a00", "\\bigodot"); -defineSymbol(math, op, "\u222e", "\\oint"); -defineSymbol(math, op, "\u222f", "\\oiint"); -defineSymbol(math, op, "\u2230", "\\oiiint"); -defineSymbol(math, op, "\u2231", "\\intclockwise"); -defineSymbol(math, op, "\u2232", "\\varointclockwise"); -defineSymbol(math, op, "\u2a0c", "\\iiiint"); -defineSymbol(math, op, "\u2a0d", "\\intbar"); -defineSymbol(math, op, "\u2a0e", "\\intBar"); -defineSymbol(math, op, "\u2a0f", "\\fint"); -defineSymbol(math, op, "\u2a12", "\\rppolint"); -defineSymbol(math, op, "\u2a13", "\\scpolint"); -defineSymbol(math, op, "\u2a15", "\\pointint"); -defineSymbol(math, op, "\u2a16", "\\sqint"); -defineSymbol(math, op, "\u2a17", "\\intlarhk"); -defineSymbol(math, op, "\u2a18", "\\intx"); -defineSymbol(math, op, "\u2a19", "\\intcap"); -defineSymbol(math, op, "\u2a1a", "\\intcup"); -defineSymbol(math, op, "\u2a05", "\\bigsqcap"); -defineSymbol(math, op, "\u2a06", "\\bigsqcup"); -defineSymbol(math, op, "\u222b", "\\smallint"); -defineSymbol(text, inner, "\u2026", "\\textellipsis"); -defineSymbol(math, inner, "\u2026", "\\mathellipsis"); -defineSymbol(text, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u22f0", "\\iddots", true); -defineSymbol(math, inner, "\u22ef", "\\@cdots", true); -defineSymbol(math, inner, "\u22f1", "\\ddots", true); -defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro -defineSymbol(math, accent, "\u02ca", "\\acute"); -defineSymbol(math, accent, "\u0060", "\\grave"); -defineSymbol(math, accent, "\u00a8", "\\ddot"); -defineSymbol(math, accent, "\u20db", "\\dddot"); -defineSymbol(math, accent, "\u20dc", "\\ddddot"); -defineSymbol(math, accent, "\u007e", "\\tilde"); -defineSymbol(math, accent, "\u203e", "\\bar"); -defineSymbol(math, accent, "\u02d8", "\\breve"); -defineSymbol(math, accent, "\u02c7", "\\check"); -defineSymbol(math, accent, "\u005e", "\\hat"); -defineSymbol(math, accent, "\u20d7", "\\vec"); -defineSymbol(math, accent, "\u02d9", "\\dot"); -defineSymbol(math, accent, "\u02da", "\\mathring"); -defineSymbol(math, mathord, "\u0131", "\\imath", true); -defineSymbol(math, mathord, "\u0237", "\\jmath", true); -defineSymbol(math, textord, "\u0131", "\u0131"); -defineSymbol(math, textord, "\u0237", "\u0237"); -defineSymbol(text, textord, "\u0131", "\\i", true); -defineSymbol(text, textord, "\u0237", "\\j", true); -defineSymbol(text, textord, "\u00df", "\\ss", true); -defineSymbol(text, textord, "\u00e6", "\\ae", true); -defineSymbol(text, textord, "\u0153", "\\oe", true); -defineSymbol(text, textord, "\u00f8", "\\o", true); -defineSymbol(math, mathord, "\u00f8", "\\o", true); -defineSymbol(text, textord, "\u00c6", "\\AE", true); -defineSymbol(text, textord, "\u0152", "\\OE", true); -defineSymbol(text, textord, "\u00d8", "\\O", true); -defineSymbol(math, mathord, "\u00d8", "\\O", true); -defineSymbol(text, accent, "\u02ca", "\\'"); // acute -defineSymbol(text, accent, "\u02cb", "\\`"); // grave -defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(text, accent, "\u02dc", "\\~"); // tilde -defineSymbol(text, accent, "\u02c9", "\\="); // macron -defineSymbol(text, accent, "\u02d8", "\\u"); // breve -defineSymbol(text, accent, "\u02d9", "\\."); // dot above -defineSymbol(text, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(text, accent, "\u02da", "\\r"); // ring above -defineSymbol(text, accent, "\u02c7", "\\v"); // caron -defineSymbol(text, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(text, accent, "\u02dd", "\\H"); // double acute -defineSymbol(math, accent, "\u02ca", "\\'"); // acute -defineSymbol(math, accent, "\u02cb", "\\`"); // grave -defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(math, accent, "\u02dc", "\\~"); // tilde -defineSymbol(math, accent, "\u02c9", "\\="); // macron -defineSymbol(math, accent, "\u02d8", "\\u"); // breve -defineSymbol(math, accent, "\u02d9", "\\."); // dot above -defineSymbol(math, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(math, accent, "\u02da", "\\r"); // ring above -defineSymbol(math, accent, "\u02c7", "\\v"); // caron -defineSymbol(math, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(math, accent, "\u02dd", "\\H"); // double acute - -// These ligatures are detected and created in Parser.js's `formLigatures`. -const ligatures = { - "--": true, - "---": true, - "``": true, - "''": true -}; - -defineSymbol(text, textord, "\u2013", "--", true); -defineSymbol(text, textord, "\u2013", "\\textendash"); -defineSymbol(text, textord, "\u2014", "---", true); -defineSymbol(text, textord, "\u2014", "\\textemdash"); -defineSymbol(text, textord, "\u2018", "`", true); -defineSymbol(text, textord, "\u2018", "\\textquoteleft"); -defineSymbol(text, textord, "\u2019", "'", true); -defineSymbol(text, textord, "\u2019", "\\textquoteright"); -defineSymbol(text, textord, "\u201c", "``", true); -defineSymbol(text, textord, "\u201c", "\\textquotedblleft"); -defineSymbol(text, textord, "\u201d", "''", true); -defineSymbol(text, textord, "\u201d", "\\textquotedblright"); -// \degree from gensymb package -defineSymbol(math, textord, "\u00b0", "\\degree", true); -defineSymbol(text, textord, "\u00b0", "\\degree"); -// \textdegree from inputenc package -defineSymbol(text, textord, "\u00b0", "\\textdegree", true); -// TODO: In LaTeX, \pounds can generate a different character in text and math -// mode, but among our fonts, only Main-Regular defines this character "163". -defineSymbol(math, textord, "\u00a3", "\\pounds"); -defineSymbol(math, textord, "\u00a3", "\\mathsterling", true); -defineSymbol(text, textord, "\u00a3", "\\pounds"); -defineSymbol(text, textord, "\u00a3", "\\textsterling", true); -defineSymbol(math, textord, "\u2720", "\\maltese"); -defineSymbol(text, textord, "\u2720", "\\maltese"); -defineSymbol(math, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\texteuro"); -defineSymbol(math, textord, "\u00a9", "\\copyright", true); -defineSymbol(text, textord, "\u00a9", "\\textcopyright"); - -// Italic Greek -defineSymbol(math, textord, "𝛤", "\\varGamma"); -defineSymbol(math, textord, "𝛥", "\\varDelta"); -defineSymbol(math, textord, "𝛩", "\\varTheta"); -defineSymbol(math, textord, "𝛬", "\\varLambda"); -defineSymbol(math, textord, "𝛯", "\\varXi"); -defineSymbol(math, textord, "𝛱", "\\varPi"); -defineSymbol(math, textord, "𝛴", "\\varSigma"); -defineSymbol(math, textord, "𝛶", "\\varUpsilon"); -defineSymbol(math, textord, "𝛷", "\\varPhi"); -defineSymbol(math, textord, "𝛹", "\\varPsi"); -defineSymbol(math, textord, "𝛺", "\\varOmega"); -defineSymbol(text, textord, "𝛤", "\\varGamma"); -defineSymbol(text, textord, "𝛥", "\\varDelta"); -defineSymbol(text, textord, "𝛩", "\\varTheta"); -defineSymbol(text, textord, "𝛬", "\\varLambda"); -defineSymbol(text, textord, "𝛯", "\\varXi"); -defineSymbol(text, textord, "𝛱", "\\varPi"); -defineSymbol(text, textord, "𝛴", "\\varSigma"); -defineSymbol(text, textord, "𝛶", "\\varUpsilon"); -defineSymbol(text, textord, "𝛷", "\\varPhi"); -defineSymbol(text, textord, "𝛹", "\\varPsi"); -defineSymbol(text, textord, "𝛺", "\\varOmega"); - - -// There are lots of symbols which are the same, so we add them in afterwards. -// All of these are textords in math mode -const mathTextSymbols = '0123456789/@."'; -for (let i = 0; i < mathTextSymbols.length; i++) { - const ch = mathTextSymbols.charAt(i); - defineSymbol(math, textord, ch, ch); -} - -// All of these are textords in text mode -const textSymbols = '0123456789!@*()-=+";:?/.,'; -for (let i = 0; i < textSymbols.length; i++) { - const ch = textSymbols.charAt(i); - defineSymbol(text, textord, ch, ch); -} - -// All of these are textords in text mode, and mathords in math mode -const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -for (let i = 0; i < letters.length; i++) { - const ch = letters.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// Some more letters in Unicode Basic Multilingual Plane. -const narrow = "ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ"; -for (let i = 0; i < narrow.length; i++) { - const ch = narrow.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// The next loop loads wide (surrogate pair) characters. -// We support some letters in the Unicode range U+1D400 to U+1D7FF, -// Mathematical Alphanumeric Symbols. -let wideChar = ""; -for (let i = 0; i < letters.length; i++) { - // The hex numbers in the next line are a surrogate pair. - // 0xD835 is the high surrogate for all letters in the range we support. - // 0xDC00 is the low surrogate for bold A. - wideChar = String.fromCharCode(0xd835, 0xdc00 + i); // A-Z a-z bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc34 + i); // A-Z a-z italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc68 + i); // A-Z a-z bold italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd04 + i); // A-Z a-z Fractur - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdda0 + i); // A-Z a-z sans-serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xddd4 + i); // A-Z a-z sans bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde08 + i); // A-Z a-z sans italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde70 + i); // A-Z a-z monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd38 + i); // A-Z a-z double struck - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - const ch = letters.charAt(i); - wideChar = String.fromCharCode(0xd835, 0xdc9c + i); // A-Z a-z calligraphic - defineSymbol(math, mathord, ch, wideChar); - defineSymbol(text, textord, ch, wideChar); -} - -// Next, some wide character numerals -for (let i = 0; i < 10; i++) { - wideChar = String.fromCharCode(0xd835, 0xdfce + i); // 0-9 bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfe2 + i); // 0-9 sans serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfec + i); // 0-9 bold sans - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdff6 + i); // 0-9 monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); -} - -/* - * Neither Firefox nor Chrome support hard line breaks or soft line breaks. - * (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs) - * So Temml has work-arounds for both hard and soft breaks. - * The work-arounds sadly do not work simultaneously. Any top-level hard - * break makes soft line breaks impossible. - * - * Hard breaks are simulated by creating a and putting each line in its own . - * - * To create soft line breaks, Temml avoids using the and tags. - * Then the top level of a element can be occupied by elements, and the browser - * will break after a if the expression extends beyond the container limit. - * - * We want the expression to render with soft line breaks after each top-level binary or - * relational operator, per TeXbook p. 173. So we gather the expression into s so that - * each ends in a binary or relational operator. - * - * Soft line breaks will not work in Chromium and Safari, only Firefox. - * - * Hopefully browsers will someday do their own linebreaking and we will be able to delete - * much of this module. - */ - -function setLineBreaks(expression, isDisplayMode, isAnnotated, color = undefined) { - if (color === undefined) { - // First, make one pass through the expression and split any color nodes. - const upperLimit = expression.length - 1; - for (let i = upperLimit; i >= 0; i--) { - const node = expression[i]; - if (node.type === "mstyle" && node.attributes.mathcolor) { - const color = node.attributes.mathcolor; - const fragment = setLineBreaks(node.children, isDisplayMode, isAnnotated, color); - if (!(fragment.type && fragment.type !== "mtable")) { - expression.splice(i, 1, ...fragment.children); - - } - } - } - } - - const tagName = color ? "mstyle" : "mrow"; - - const mtrs = []; - let mrows = []; - let block = []; - let canBeBIN = false; // The first node cannot be an infix binary operator. - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type && node.type === "mstyle" && node.attributes.mathcolor) { - // Start a new block. (Insert a soft linebreak.) - mrows.push(new mathMLTree.MathNode(tagName, block)); - // Insert the mstyle - mrows.push(node); - block = []; - continue - } - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(new mathMLTree.MathNode(tagName, block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - continue - } - block.push(node); - if (node.type && node.type === "mo" && !isDisplayMode && !isAnnotated) { - // This may be a place for a soft line break. - if (canBeBIN && !node.attributes.form) { - // Check if the following node is a \nobreak text node, e.g. "~"" - const next = i < expression.length - 1 ? expression[i + 1] : null; - let glueIsFreeOfNobreak = true; - if ( - !( - next && - next.type === "mtext" && - next.attributes.linebreak && - next.attributes.linebreak === "nobreak" - ) - ) { - // We may need to start a new block. - // First, put any post-operator glue on same line as operator. - for (let j = i + 1; j < expression.length; j++) { - const nd = expression[j]; - if ( - nd.type && - nd.type === "mspace" && - !(nd.attributes.linebreak && nd.attributes.linebreak === "newline") - ) { - block.push(nd); - i += 1; - if ( - nd.attributes && - nd.attributes.linebreak && - nd.attributes.linebreak === "nobreak" - ) { - glueIsFreeOfNobreak = false; - } - } else { - break; - } - } - } - if (glueIsFreeOfNobreak) { - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - block = []; - } - canBeBIN = false; - } - const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"; - // Any operator that follows an open delimiter is unary. - canBeBIN = !(node.attributes.separator || isOpenDelimiter); - } else { - canBeBIN = true; - } - } - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - const mtr = new mathMLTree.MathNode("mtr", [mtd]); - mtrs.push(mtr); - const mtable = new mathMLTree.MathNode("mtable", mtrs); - if (!isDisplayMode) { - mtable.setAttribute("columnalign", "left"); - mtable.setAttribute("rowspacing", "0em"); - } - return mtable - } - return mathMLTree.newDocumentFragment(mrows); -} - -/** - * This file converts a parse tree into a cooresponding MathML tree. The main - * entry point is the `buildMathML` function, which takes a parse tree from the - * parser. - */ - -/** - * Takes a symbol and converts it into a MathML text node after performing - * optional replacement from symbols.js. - */ -const makeText = function(text, mode, style) { - if ( - symbols[mode][text] && - symbols[mode][text].replace && - text.charCodeAt(0) !== 0xd835 && - !( - Object.prototype.hasOwnProperty.call(ligatures, text) && - style && - ((style.fontFamily && style.fontFamily.slice(4, 6) === "tt") || - (style.font && style.font.slice(4, 6) === "tt")) - ) - ) { - text = symbols[mode][text].replace; - } - - return new mathMLTree.TextNode(text); -}; - -/** - * Wrap the given array of nodes in an node if needed, i.e., - * unless the array has length 1. Always returns a single node. - */ -const makeRow = function(body) { - if (body.length === 1) { - return body[0]; - } else { - return new mathMLTree.MathNode("mrow", body); - } -}; - -const isRel = item => { - return (item.type === "atom" && item.family === "rel") || - (item.type === "mclass" && item.mclass === "mrel") -}; - -/** - * Takes a list of nodes, builds them, and returns a list of the generated - * MathML nodes. Also do a couple chores along the way: - * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}. - * (2) Suppress spacing between two adjacent relations. - */ -const buildExpression = function(expression, style, isOrdgroup) { - if (expression.length === 1) { - const group = buildGroup$1(expression[0], style); - if (isOrdgroup && group instanceof MathNode && group.type === "mo") { - // When TeX writers want to suppress spacing on an operator, - // they often put the operator by itself inside braces. - group.setAttribute("lspace", "0em"); - group.setAttribute("rspace", "0em"); - } - return [group]; - } - - const groups = []; - for (let i = 0; i < expression.length; i++) { - const group = buildGroup$1(expression[i], style); - // Suppress spacing between adjacent relations - if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) { - group.setAttribute("rspace", "0em"); - } - if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) { - group.setAttribute("lspace", "0em"); - } - groups.push(group); - } - return groups; -}; - -/** - * Equivalent to buildExpression, but wraps the elements in an - * if there's more than one. Returns a single node instead of an array. - */ -const buildExpressionRow = function(expression, style, isOrdgroup) { - return makeRow(buildExpression(expression, style, isOrdgroup)); -}; - -/** - * Takes a group from the parser and calls the appropriate groupBuilders function - * on it to produce a MathML node. - */ -const buildGroup$1 = function(group, style) { - if (!group) { - return new mathMLTree.MathNode("mrow"); - } - - if (_mathmlGroupBuilders[group.type]) { - // Call the groupBuilders function - const result = _mathmlGroupBuilders[group.type](group, style); - return result; - } else { - throw new ParseError("Got group of unknown type: '" + group.type + "'"); - } -}; - -const glue = _ => { - const glueNode = new mathMLTree.MathNode("mtd", []); - glueNode.setAttribute("style", "padding: 0;width: 50%;"); - return glueNode -}; - -const taggedExpression = (expression, tag, style, leqno, preventTagLap) => { - tag = buildExpressionRow(tag[0].body, style); - tag = utils.consolidateText(tag); - tag.classes = ["tml-tag"]; - if (!preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - tag.setAttribute((leqno ? "rspace" : "lspace"), "-1width"); - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = leqno - ? [tag, glue(), expression, glue()] - : [glue(), expression, glue(), tag]; - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.setAttribute("width", "100%"); - table.setAttribute("displaystyle", "true"); - return table -}; - -/** - * Takes a full parse tree and settings and builds a MathML representation of - * it. - */ -function buildMathML(tree, texExpression, style, settings) { - // Strip off outer tag wrapper for processing below. - let tag = null; - if (tree.length === 1 && tree[0].type === "tag") { - tag = tree[0].tag; - tree = tree[0].body; - } - - const expression = buildExpression(tree, style); - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - && !(n1.type === "mstyle" && n1.attributes.mathcolor) - ? expression[0] - : setLineBreaks(expression, settings.displayMode, settings.annotate); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno, settings.preventTagLap); - } - - let semantics; - if (settings.annotate) { - // Build a TeX annotation of the source - const annotation = new mathMLTree.MathNode( - "annotation", [new mathMLTree.TextNode(texExpression)]); - annotation.setAttribute("encoding", "application/x-tex"); - semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = settings.annotate - ? new mathMLTree.MathNode("math", [semantics]) - : new mathMLTree.MathNode("math", [wrapper]); - - if (settings.xml) { - math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); - } - if (settings.displayMode) { - math.setAttribute("display", "block"); - } - return math; -} - -const mathmlBuilder$a = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.mathMLnode(group.label) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup$1(group.base, style), accentNode] - ); - - node.setAttribute("accent", "true"); - return node; -}; - -const NON_STRETCHY_ACCENT_REGEX = new RegExp( - [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" - ] - .map((accent) => `\\${accent}`) - .join("|") -); - -// Accents -defineFunction({ - type: "accent", - names: [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring", - "\\overparen", - "\\widecheck", - "\\widehat", - "\\wideparen", - "\\widetilde", - "\\overrightarrow", - "\\overleftarrow", - "\\Overrightarrow", - "\\overleftrightarrow", - "\\overgroup", - "\\overleftharpoon", - "\\overrightharpoon" - ], - props: { - numArgs: 1 - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - - const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); - const isShifty = - !isStretchy || - context.funcName === "\\widehat" || - context.funcName === "\\widetilde" || - context.funcName === "\\widecheck"; - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - isShifty: isShifty, - base: base - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - -// Text-mode accents -defineFunction({ - type: "accent", - names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\c", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"], - props: { - numArgs: 1, - allowedInText: true, - allowedInMath: true, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - const mode = context.parser.mode; - - if (mode === "math" && context.parser.settings.strict) { - // LaTeX only writes a warning. It doesn't stop. We'll issue the same warning. - // eslint-disable-next-line no-console - console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`); - } - - return { - type: "accent", - mode: mode, - label: context.funcName, - isStretchy: false, - isShifty: true, - base: base - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - -defineFunction({ - type: "accentUnder", - names: [ - "\\underleftarrow", - "\\underrightarrow", - "\\underleftrightarrow", - "\\undergroup", - "\\underparen", - "\\utilde" - ], - props: { - numArgs: 1 - }, - handler: ({ parser, funcName }, args) => { - const base = args[0]; - return { - type: "accentUnder", - mode: parser.mode, - label: funcName, - base: base - }; - }, - mathmlBuilder: (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - const node = new mathMLTree.MathNode("munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - node.setAttribute("accentunder", "true"); - return node; - } -}); - -/** - * This file does conversion between units. In particular, it provides - * calculateSize to convert other units into CSS units. - */ - -const ptPerUnit = { - // Convert to CSS (Postscipt) points, not TeX points - // https://en.wikibooks.org/wiki/LaTeX/Lengths and - // https://tex.stackexchange.com/a/8263 - pt: 800 / 803, // convert TeX point to CSS (Postscript) point - pc: (12 * 800) / 803, // pica - dd: ((1238 / 1157) * 800) / 803, // didot - cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot) - nd: ((685 / 642) * 800) / 803, // new didot - nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot) - sp: ((1 / 65536) * 800) / 803, // scaled point (TeX's internal smallest unit) - mm: (25.4 / 72), - cm: (2.54 / 72), - in: (1 / 72), - px: (96 / 72) -}; - -/** - * Determine whether the specified unit (either a string defining the unit - * or a "size" parse node containing a unit field) is valid. - */ -const validUnits = [ - "em", - "ex", - "mu", - "pt", - "mm", - "cm", - "in", - "px", - "bp", - "pc", - "dd", - "cc", - "nd", - "nc", - "sp" -]; - -const validUnit = function(unit) { - if (typeof unit !== "string") { - unit = unit.unit; - } - return validUnits.indexOf(unit) > -1 -}; - -const emScale = styleLevel => { - const scriptLevel = Math.max(styleLevel - 1, 0); - return [1, 0.7, 0.5][scriptLevel] -}; - -/* - * Convert a "size" parse node (with numeric "number" and string "unit" fields, - * as parsed by functions.js argType "size") into a CSS value. - */ -const calculateSize = function(sizeValue, style) { - let number = sizeValue.number; - if (style.maxSize[0] < 0 && number > 0) { - return { number: 0, unit: "em" } - } - const unit = sizeValue.unit; - switch (unit) { - case "mm": - case "cm": - case "in": - case "px": { - const numInCssPts = number * ptPerUnit[unit]; - if (numInCssPts > style.maxSize[1]) { - return { number: style.maxSize[1], unit: "pt" } - } - return { number, unit }; // absolute CSS units. - } - case "em": - case "ex": { - // In TeX, em and ex do not change size in \scriptstyle. - if (unit === "ex") { number *= 0.431; } - number = Math.min(number / emScale(style.level), style.maxSize[0]); - return { number: utils.round(number), unit: "em" }; - } - case "bp": { - if (number > style.maxSize[1]) { number = style.maxSize[1]; } - return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch). - } - case "pt": - case "pc": - case "dd": - case "cc": - case "nd": - case "nc": - case "sp": { - number = Math.min(number * ptPerUnit[unit], style.maxSize[1]); - return { number: utils.round(number), unit: "pt" } - } - case "mu": { - number = Math.min(number / 18, style.maxSize[0]); - return { number: utils.round(number), unit: "em" } - } - default: - throw new ParseError("Invalid unit: '" + unit + "'") - } -}; - -// Helper functions -const paddedNode = (group, width, lspace = "0.3em") => { - const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); - node.setAttribute("width", width); - node.setAttribute("lspace", lspace); - return node; -}; - -const labelSize = (size, scriptLevel) => (size / emScale(scriptLevel)).toFixed(4) + "em"; - -const munderoverNode = (name, body, below, style) => { - const arrowNode = stretchy.mathMLnode(name); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = name.slice(1, 3) === "eq"; - const minWidth = name.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are 1.75em long - : name.slice(2, 4) === "cd" - ? "3.0" // cd package arrows - : isEq - ? "1.0" // The shorter harpoon of a mhchem equilibrium arrow - : "2.0"; // other mhchem arrows - arrowNode.setAttribute("minsize", String(minWidth) + "em"); - arrowNode.setAttribute("lspace", "0"); - arrowNode.setAttribute("rspace", (isEq ? "0.5em" : "0")); - - // upper and lower labels are set to scriptlevel by MathML - // So we have to adjust our dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3); - const emptyLabelWidth = labelSize(minWidth, labelStyle.level); - const lspace = labelSize((isEq ? 0 : 0.3), labelStyle.level); - let widthAdder = labelSize((isEq ? -0.4 : 0.6), labelStyle.level); - if (widthAdder.charAt(0) !== "-") { widthAdder = "+" + widthAdder; } - - const upperNode = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)) - ? paddedNode(buildGroup$1(body, labelStyle), widthAdder, lspace) - // Since Firefox does not recognize minsize set on the arrow, - // create an upper node w/correct width. - : paddedNode(null, emptyLabelWidth, "0"); - const lowerNode = (below && below.body && - (below.body.body || below.body.length > 0)) - ? paddedNode(buildGroup$1(below, labelStyle), widthAdder, lspace) - : paddedNode(null, emptyLabelWidth, "0"); - const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - return node -}; - -// Stretchy arrows with an optional argument -defineFunction({ - type: "xArrow", - names: [ - "\\xleftarrow", - "\\xrightarrow", - "\\xLeftarrow", - "\\xRightarrow", - "\\xleftrightarrow", - "\\xLeftrightarrow", - "\\xhookleftarrow", - "\\xhookrightarrow", - "\\xmapsto", - "\\xrightharpoondown", - "\\xrightharpoonup", - "\\xleftharpoondown", - "\\xleftharpoonup", - "\\xlongequal", - "\\xtwoheadrightarrow", - "\\xtwoheadleftarrow", - // The next 7 functions are here only to support mhchem - "\\yields", - "\\yieldsLeft", - "\\mesomerism", - "\\longrightharpoonup", - "\\longleftharpoondown", - // The next 3 functions are here only to support the {CD} environment. - "\\\\cdrightarrow", - "\\\\cdleftarrow", - "\\\\cdlongequal" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - return { - type: "xArrow", - mode: parser.mode, - name: funcName, - body: args[0], - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - // Build the arrow and its labels. - const node = munderoverNode(group.name, group.body, group.below, style); - // Create operator spacing for a relation. - const wrapper = new mathMLTree.MathNode("mpadded", [node]); - wrapper.setAttribute("lspace", "0.2778em"); - wrapper.setAttribute("width", "+0.5556em"); - return wrapper - } -}); - -const arrowComponent = { - "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"], - "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"], - "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"], - "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"], - // The next three all get the same harpoon glyphs. Only the lengths and paddings differ. - "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"], - "\\equilibriumRight": ["\\longrightharpoonup", "\\eqleftharpoondown"], - "\\equilibriumLeft": ["\\eqrightharpoonup", "\\longleftharpoondown"] -}; - -// Browsers are not good at stretching a glyph that contains a pair of stacked arrows such as ⇄. -// So we stack a pair of single arrows. -defineFunction({ - type: "stackedArrow", - names: [ - "\\xtofrom", // expfeil - "\\xleftrightharpoons", // mathtools - "\\xrightleftharpoons", // mathtools - "\\yieldsLeftRight", // mhchem - "\\equilibrium", // mhchem - "\\equilibriumRight", - "\\equilibriumLeft" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - const lowerArrowBody = args[0] - ? { - type: "hphantom", - mode: parser.mode, - body: args[0] - } - : null; - const upperArrowBelow = optArgs[0] - ? { - type: "hphantom", - mode: parser.mode, - body: optArgs[0] - } - : null; - return { - type: "stackedArrow", - mode: parser.mode, - name: funcName, - body: args[0], - upperArrowBelow, - lowerArrowBody, - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - const topLabel = arrowComponent[group.name][0]; - const botLabel = arrowComponent[group.name][1]; - const topArrow = munderoverNode(topLabel, group.body, group.upperArrowBelow, style); - const botArrow = munderoverNode(botLabel, group.lowerArrowBody, group.below, style); - let wrapper; - - const raiseNode = new mathMLTree.MathNode("mpadded", [topArrow]); - raiseNode.setAttribute("voffset", "0.3em"); - raiseNode.setAttribute("height", "+0.3em"); - raiseNode.setAttribute("depth", "-0.3em"); - // One of the arrows is given ~zero width. so the other has the same horzontal alignment. - if (group.name === "\\equilibriumLeft") { - const botNode = new mathMLTree.MathNode("mpadded", [botArrow]); - botNode.setAttribute("width", "0.5em"); - wrapper = new mathMLTree.MathNode("mpadded", [botNode, raiseNode]); - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")); - wrapper = new mathMLTree.MathNode("mpadded", [raiseNode, botArrow]); - } - - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("width", "+0.5556em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - wrapper.setAttribute("lspace", "0.2778em"); - return wrapper - } -}); - -defineFunction({ - type: "cancelto", - names: ["\\cancelto"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "cancelto", - mode: parser.mode, - value: args[0], - expression: args[1] - }; - }, - mathmlBuilder(group, style) { - const value = new mathMLTree.MathNode( - "mpadded", - [buildGroup$1(group.value, style)] - ); - value.setAttribute("depth", `-0.1em`); - value.setAttribute("height", `+0.1em`); - value.setAttribute("voffset", `0.1em`); - - const expression = new mathMLTree.MathNode( - "menclose", - [buildGroup$1(group.expression, style)] - ); - expression.setAttribute("notation", `updiagonalarrow`); - - return new mathMLTree.MathNode("msup", [expression, value]) - } -}); - -/** - * Asserts that the node is of the given type and returns it with stricter - * typing. Throws if the node's type does not match. - */ -function assertNodeType(node, type) { - if (!node || node.type !== type) { - throw new Error( - `Expected node of type ${type}, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return node; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function assertSymbolNodeType(node) { - const typedNode = checkSymbolNodeType(node); - if (!typedNode) { - throw new Error( - `Expected node of symbol group type, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return typedNode; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function checkSymbolNodeType(node) { - if (node && (node.type === "atom" || - Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) { - return node; - } - return null; -} - -const cdArrowFunctionName = { - ">": "\\\\cdrightarrow", - "<": "\\\\cdleftarrow", - "=": "\\\\cdlongequal", - A: "\\uparrow", - V: "\\downarrow", - "|": "\\Vert", - ".": "no arrow" -}; - -const newCell = () => { - // Create an empty cell, to be filled below with parse nodes. - return { type: "styling", body: [], mode: "math", scriptLevel: "display" }; -}; - -const isStartOfArrow = (node) => { - return node.type === "textord" && node.text === "@"; -}; - -const isLabelEnd = (node, endChar) => { - return (node.type === "mathord" || node.type === "atom") && node.text === endChar; -}; - -function cdArrow(arrowChar, labels, parser) { - // Return a parse tree of an arrow and its labels. - // This acts in a way similar to a macro expansion. - const funcName = cdArrowFunctionName[arrowChar]; - switch (funcName) { - case "\\\\cdrightarrow": - case "\\\\cdleftarrow": - return parser.callFunction(funcName, [labels[0]], [labels[1]]); - case "\\uparrow": - case "\\downarrow": { - const leftLabel = parser.callFunction("\\\\cdleft", [labels[0]], []); - const bareArrow = { - type: "atom", - text: funcName, - mode: "math", - family: "rel" - }; - const sizedArrow = parser.callFunction("\\Big", [bareArrow], []); - const rightLabel = parser.callFunction("\\\\cdright", [labels[1]], []); - const arrowGroup = { - type: "ordgroup", - mode: "math", - body: [leftLabel, sizedArrow, rightLabel] - }; - return parser.callFunction("\\\\cdparent", [arrowGroup], []); - } - case "\\\\cdlongequal": - return parser.callFunction("\\\\cdlongequal", [], []); - case "\\Vert": { - const arrow = { type: "textord", text: "\\Vert", mode: "math" }; - return parser.callFunction("\\Big", [arrow], []); - } - default: - return { type: "textord", text: " ", mode: "math" }; - } -} - -function parseCD(parser) { - // Get the array's parse nodes with \\ temporarily mapped to \cr. - const parsedRows = []; - parser.gullet.beginGroup(); - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - parser.gullet.beginGroup(); - while (true) { // eslint-disable-line no-constant-condition - // Get the parse nodes for the next row. - parsedRows.push(parser.parseExpression(false, "\\\\")); - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - const next = parser.fetch().text; - if (next === "&" || next === "\\\\") { - parser.consume(); - } else if (next === "\\end") { - if (parsedRows[parsedRows.length - 1].length === 0) { - parsedRows.pop(); // final row ended in \\ - } - break; - } else { - throw new ParseError("Expected \\\\ or \\cr or \\end", parser.nextToken); - } - } - - let row = []; - const body = [row]; - - // Loop thru the parse nodes. Collect them into cells and arrows. - for (let i = 0; i < parsedRows.length; i++) { - // Start a new row. - const rowNodes = parsedRows[i]; - // Create the first cell. - let cell = newCell(); - - for (let j = 0; j < rowNodes.length; j++) { - if (!isStartOfArrow(rowNodes[j])) { - // If a parseNode is not an arrow, it goes into a cell. - cell.body.push(rowNodes[j]); - } else { - // Parse node j is an "@", the start of an arrow. - // Before starting on the arrow, push the cell into `row`. - row.push(cell); - - // Now collect parseNodes into an arrow. - // The character after "@" defines the arrow type. - j += 1; - const arrowChar = assertSymbolNodeType(rowNodes[j]).text; - - // Create two empty label nodes. We may or may not use them. - const labels = new Array(2); - labels[0] = { type: "ordgroup", mode: "math", body: [] }; - labels[1] = { type: "ordgroup", mode: "math", body: [] }; - - // Process the arrow. - if ("=|.".indexOf(arrowChar) > -1) ; else if ("<>AV".indexOf(arrowChar) > -1) { - // Four arrows, `@>>>`, `@<<<`, `@AAA`, and `@VVV`, each take - // two optional labels. E.g. the right-point arrow syntax is - // really: @>{optional label}>{optional label}> - // Collect parseNodes into labels. - for (let labelNum = 0; labelNum < 2; labelNum++) { - let inLabel = true; - for (let k = j + 1; k < rowNodes.length; k++) { - if (isLabelEnd(rowNodes[k], arrowChar)) { - inLabel = false; - j = k; - break; - } - if (isStartOfArrow(rowNodes[k])) { - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[k] - ); - } - - labels[labelNum].body.push(rowNodes[k]); - } - if (inLabel) { - // isLabelEnd never returned a true. - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[j] - ); - } - } - } else { - throw new ParseError(`Expected one of "<>AV=|." after @.`); - } - - // Now join the arrow to its labels. - const arrow = cdArrow(arrowChar, labels, parser); - - // Wrap the arrow in a styling node - row.push(arrow); - // In CD's syntax, cells are implicit. That is, everything that - // is not an arrow gets collected into a cell. So create an empty - // cell now. It will collect upcoming parseNodes. - cell = newCell(); - } - } - if (i % 2 === 0) { - // Even-numbered rows consist of: cell, arrow, cell, arrow, ... cell - // The last cell is not yet pushed into `row`, so: - row.push(cell); - } else { - // Odd-numbered rows consist of: vert arrow, empty cell, ... vert arrow - // Remove the empty cell that was placed at the beginning of `row`. - row.shift(); - } - row = []; - body.push(row); - } - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - // define column separation. - const cols = new Array(body[0].length).fill({ - type: "align", - align: "c" - }); - - return { - type: "array", - mode: "math", - body, - arraystretch: 1, - addJot: true, - rowGaps: [null], - cols, - colSeparationType: "CD", - hLinesBeforeRow: new Array(body.length + 1).fill([]) - }; -} - -// The functions below are not available for general use. -// They are here only for internal use by the {CD} environment in placing labels -// next to vertical arrows. - -// We don't need any such functions for horizontal arrows because we can reuse -// the functionality that already exists for extensible arrows. - -defineFunction({ - type: "cdlabel", - names: ["\\\\cdleft", "\\\\cdright"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "cdlabel", - mode: parser.mode, - side: funcName.slice(4), - label: args[0] - }; - }, - mathmlBuilder(group, style) { - let label = new mathMLTree.MathNode("mrow", [buildGroup$1(group.label, style)]); - label = new mathMLTree.MathNode("mpadded", [label]); - label.setAttribute("width", "0"); - if (group.side === "left") { - label.setAttribute("lspace", "-1width"); - } - // We have to guess at vertical alignment. We know the arrow is 1.8em tall, - // But we don't know the height or depth of the label. - label.setAttribute("voffset", "0.7em"); - label = new mathMLTree.MathNode("mstyle", [label]); - label.setAttribute("displaystyle", "false"); - label.setAttribute("scriptlevel", "1"); - return label; - } -}); - -defineFunction({ - type: "cdlabelparent", - names: ["\\\\cdparent"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - return { - type: "cdlabelparent", - mode: parser.mode, - fragment: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow", [buildGroup$1(group.fragment, style)]); - } -}); - -// \@char is an internal function that takes a grouped decimal argument like -// {123} and converts into symbol with code 123. It is used by the *macro* -// \char defined in macros.js. -defineFunction({ - type: "textord", - names: ["\\@char"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser, token }, args) { - const arg = assertNodeType(args[0], "ordgroup"); - const group = arg.body; - let number = ""; - for (let i = 0; i < group.length; i++) { - const node = assertNodeType(group[i], "textord"); - number += node.text; - } - const code = parseInt(number); - if (isNaN(code)) { - throw new ParseError(`\\@char has non-numeric argument ${number}`, token) - } - return { - type: "textord", - mode: parser.mode, - text: String.fromCodePoint(code) - } - } -}); - -// Helpers -const htmlRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6})$/i; -const htmlOrNameRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i; -const RGBregEx = /^ *\d{1,3} *(?:, *\d{1,3} *){2}$/; -const rgbRegEx = /^ *[10](?:\.\d*)? *(?:, *[10](?:\.\d*)? *){2}$/; -const xcolorHtmlRegEx = /^[a-f0-9]{6}$/i; -const toHex = num => { - let str = num.toString(16); - if (str.length === 1) { str = "0" + str; } - return str -}; - -// Colors from Tables 4.1 and 4.2 of the xcolor package. -// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx. -// Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable -// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274. -const xcolors = JSON.parse(`{ - "Apricot": "#ffb484", - "Aquamarine": "#08b4bc", - "Bittersweet": "#c84c14", - "blue": "#0000FF", - "Blue": "#303494", - "BlueGreen": "#08b4bc", - "BlueViolet": "#503c94", - "BrickRed": "#b8341c", - "brown": "#BF8040", - "Brown": "#802404", - "BurntOrange": "#f8941c", - "CadetBlue": "#78749c", - "CarnationPink": "#f884b4", - "Cerulean": "#08a4e4", - "CornflowerBlue": "#40ace4", - "cyan": "#00FFFF", - "Cyan": "#08acec", - "Dandelion": "#ffbc44", - "darkgray": "#404040", - "DarkOrchid": "#a8548c", - "Emerald": "#08ac9c", - "ForestGreen": "#089c54", - "Fuchsia": "#90348c", - "Goldenrod": "#ffdc44", - "gray": "#808080", - "Gray": "#98949c", - "green": "#00FF00", - "Green": "#08a44c", - "GreenYellow": "#e0e474", - "JungleGreen": "#08ac9c", - "Lavender": "#f89cc4", - "lightgray": "#c0c0c0", - "lime": "#BFFF00", - "LimeGreen": "#90c43c", - "magenta": "#FF00FF", - "Magenta": "#f0048c", - "Mahogany": "#b0341c", - "Maroon": "#b03434", - "Melon": "#f89c7c", - "MidnightBlue": "#086494", - "Mulberry": "#b03c94", - "NavyBlue": "#086cbc", - "olive": "#7F7F00", - "OliveGreen": "#407c34", - "orange": "#FF8000", - "Orange": "#f8843c", - "OrangeRed": "#f0145c", - "Orchid": "#b074ac", - "Peach": "#f8945c", - "Periwinkle": "#8074bc", - "PineGreen": "#088c74", - "pink": "#ff7f7f", - "Plum": "#98248c", - "ProcessBlue": "#08b4ec", - "purple": "#BF0040", - "Purple": "#a0449c", - "RawSienna": "#983c04", - "red": "#ff0000", - "Red": "#f01c24", - "RedOrange": "#f86434", - "RedViolet": "#a0246c", - "Rhodamine": "#f0549c", - "Royallue": "#0874bc", - "RoyalPurple": "#683c9c", - "RubineRed": "#f0047c", - "Salmon": "#f8948c", - "SeaGreen": "#30bc9c", - "Sepia": "#701404", - "SkyBlue": "#48c4dc", - "SpringGreen": "#c8dc64", - "Tan": "#e09c74", - "teal": "#007F7F", - "TealBlue": "#08acb4", - "Thistle": "#d884b4", - "Turquoise": "#08b4cc", - "violet": "#800080", - "Violet": "#60449c", - "VioletRed": "#f054a4", - "WildStrawberry": "#f0246c", - "yellow": "#FFFF00", - "Yellow": "#fff404", - "YellowGreen": "#98cc6c", - "YellowOrange": "#ffa41c" -}`); - -const colorFromSpec = (model, spec) => { - let color = ""; - if (model === "HTML") { - if (!htmlRegEx.test(spec)) { - throw new ParseError("Invalid HTML input.") - } - color = spec; - } else if (model === "RGB") { - if (!RGBregEx.test(spec)) { - throw new ParseError("Invalid RGB input.") - } - spec.split(",").map(e => { color += toHex(Number(e.trim())); }); - } else { - if (!rgbRegEx.test(spec)) { - throw new ParseError("Invalid rbg input.") - } - spec.split(",").map(e => { - const num = Number(e.trim()); - if (num > 1) { throw new ParseError("Color rgb input must be < 1.") } - color += toHex((num * 255)); - }); - } - if (color.charAt(0) !== "#") { color = "#" + color; } - return color -}; - -const validateColor = (color, macros, token) => { - const macroName = `\\\\color@${color}`; // from \defineColor. - const match = htmlOrNameRegEx.exec(color); - if (!match) { throw new ParseError("Invalid color: '" + color + "'", token) } - // We allow a 6-digit HTML color spec without a leading "#". - // This follows the xcolor package's HTML color model. - // Predefined color names are all missed by this RegEx pattern. - if (xcolorHtmlRegEx.test(color)) { - return "#" + color - } else if (color.charAt(0) === "#") { - return color - } else if (macros.has(macroName)) { - color = macros.get(macroName).tokens[0].text; - } else if (xcolors[color]) { - color = xcolors[color]; - } - return color -}; - -const mathmlBuilder$9 = (group, style) => { - const inner = buildExpression(group.body, style.withColor(group.color)); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("mathcolor", group.color); - // Wrap w/. We get better operator spacing that way. - return new mathMLTree.MathNode("mrow", [node]) -}; - -defineFunction({ - type: "color", - names: ["\\textcolor"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "original"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token); - } - const body = args[1]; - return { - type: "color", - mode: parser.mode, - color, - body: ordargument(body) - } - }, - mathmlBuilder: mathmlBuilder$9 -}); - -defineFunction({ - type: "color", - names: ["\\color"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token); - } - - // Set macro \current@color in current namespace to store the current - // color, mimicking the behavior of color.sty. - // This is currently used just to correctly color a \right - // that follows a \color command. - parser.gullet.macros.set("\\current@color", color); - - // Parse out the implicit body that should be colored. - // Since \color nodes should not be nested, break on \color. - const body = parser.parseExpression(true, "\\color"); - - return { - type: "color", - mode: parser.mode, - color, - body - } - }, - mathmlBuilder: mathmlBuilder$9 -}); - -defineFunction({ - type: "color", - names: ["\\definecolor"], - props: { - numArgs: 3, - allowedInText: true, - argTypes: ["raw", "raw", "raw"] - }, - handler({ parser, funcName, token }, args) { - const name = assertNodeType(args[0], "raw").string; - if (!/^[A-Za-z]+$/.test(name)) { - throw new ParseError("Color name must be latin letters.", token) - } - const model = assertNodeType(args[1], "raw").string; - if (!["HTML", "RGB", "rgb"].includes(model)) { - throw new ParseError("Color model must be HTML, RGB, or rgb.", token) - } - const spec = assertNodeType(args[2], "raw").string; - const color = colorFromSpec(model, spec); - parser.gullet.macros.set(`\\\\color@${name}`, { tokens: [{ text: color }], numArgs: 0 }); - return { type: "internal", mode: parser.mode } - } - // No mathmlBuilder. The point of \definecolor is to set a macro. -}); - -// Row breaks within tabular environments, and line breaks at top level - -// \DeclareRobustCommand\\{...\@xnewline} -defineFunction({ - type: "cr", - names: ["\\\\"], - props: { - numArgs: 0, - numOptionalArgs: 1, - argTypes: ["size"], - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = optArgs[0]; - const newLine = !parser.settings.displayMode; - return { - type: "cr", - mode: parser.mode, - newLine, - size: size && assertNodeType(size, "size").value - } - }, - - // The following builder is called only at the top level, - // not within tabular/array environments. - - mathmlBuilder(group, style) { - // MathML 3.0 calls for newline to occur in an or an . - // Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.linebreaking - const node = new mathMLTree.MathNode("mo"); - if (group.newLine) { - node.setAttribute("linebreak", "newline"); - if (group.size) { - const size = calculateSize(group.size, style); - node.setAttribute("height", size.number + size.unit); - } - } - return node - } -}); - -const checkControlSequence = (tok) => { - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - return name; -}; - -const getRHS = (parser) => { - let tok = parser.gullet.popToken(); - if (tok.text === "=") { - // consume optional equals - tok = parser.gullet.popToken(); - if (tok.text === " ") { - // consume one optional space - tok = parser.gullet.popToken(); - } - } - return tok; -}; - -const letCommand = (parser, name, tok) => { - let macro = parser.gullet.macros.get(tok.text); - if (macro == null) { - // don't expand it later even if a macro with the same name is defined - // e.g., \let\foo=\frac \def\frac{\relax} \frac12 - tok.noexpand = true; - macro = { - tokens: [tok], - numArgs: 0, - // reproduce the same behavior in expansion - unexpandable: !parser.gullet.isExpandable(tok.text) - }; - } - parser.gullet.macros.set(name, macro); -}; - -// Basic support for macro definitions: \def -// -> -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\edef"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let tok = parser.gullet.popToken(); - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - - let numArgs = 0; - let insert; - const delimiters = [[]]; - // contains no braces - while (parser.gullet.future().text !== "{") { - tok = parser.gullet.popToken(); - if (tok.text === "#") { - // If the very last character of the is #, so that - // this # is immediately followed by {, TeX will behave as if the { - // had been inserted at the right end of both the parameter text - // and the replacement text. - if (parser.gullet.future().text === "{") { - insert = parser.gullet.future(); - delimiters[numArgs].push("{"); - break; - } - - // A parameter, the first appearance of # must be followed by 1, - // the next by 2, and so on; up to nine #’s are allowed - tok = parser.gullet.popToken(); - if (!/^[1-9]$/.test(tok.text)) { - throw new ParseError(`Invalid argument number "${tok.text}"`); - } - if (parseInt(tok.text) !== numArgs + 1) { - throw new ParseError(`Argument number "${tok.text}" out of order`); - } - numArgs++; - delimiters.push([]); - } else if (tok.text === "EOF") { - throw new ParseError("Expected a macro definition"); - } else { - delimiters[numArgs].push(tok.text); - } - } - // replacement text, enclosed in '{' and '}' and properly nested - let { tokens } = parser.gullet.consumeArg(); - if (insert) { - tokens.unshift(insert); - } - - if (funcName === "\\edef") { - tokens = parser.gullet.expandTokens(tokens); - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set(name, { tokens, numArgs, delimiters } - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: ["\\let"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.consumeSpaces(); - const tok = getRHS(parser); - letCommand(parser, name, tok); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: ["\\futurelet"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - const middle = parser.gullet.popToken(); - const tok = parser.gullet.popToken(); - letCommand(parser, name, tok); - parser.gullet.pushToken(tok); - parser.gullet.pushToken(middle); - return { type: "internal", mode: parser.mode }; - } -}); - -defineFunction({ - type: "internal", - names: ["\\newcommand", "\\renewcommand", "\\providecommand"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let name = ""; - const tok = parser.gullet.popToken(); - if (tok.text === "{") { - name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.popToken(); - } else { - name = checkControlSequence(tok); - } - - const exists = parser.gullet.isDefined(name); - if (exists && funcName === "\\newcommand") { - throw new ParseError( - `\\newcommand{${name}} attempting to redefine ${name}; use \\renewcommand` - ); - } - if (!exists && funcName === "\\renewcommand") { - throw new ParseError( - `\\renewcommand{${name}} when command ${name} does not yet exist; use \\newcommand` - ); - } - - let numArgs = 0; - if (parser.gullet.future().text === "[") { - let tok = parser.gullet.popToken(); - tok = parser.gullet.popToken(); - if (!/^[0-9]$/.test(tok.text)) { - throw new ParseError(`Invalid number of arguments: "${tok.text}"`); - } - numArgs = parseInt(tok.text); - tok = parser.gullet.popToken(); - if (tok.text !== "]") { - throw new ParseError(`Invalid argument "${tok.text}"`); - } - } - - // replacement text, enclosed in '{' and '}' and properly nested - const { tokens } = parser.gullet.consumeArg(); - - parser.gullet.macros.set(name, { tokens, numArgs }); - - return { type: "internal", mode: parser.mode }; - - } -}); - -// Extra data needed for the delimiter handler down below -const delimiterSizes = { - "\\bigl": { mclass: "mopen", size: 1 }, - "\\Bigl": { mclass: "mopen", size: 2 }, - "\\biggl": { mclass: "mopen", size: 3 }, - "\\Biggl": { mclass: "mopen", size: 4 }, - "\\bigr": { mclass: "mclose", size: 1 }, - "\\Bigr": { mclass: "mclose", size: 2 }, - "\\biggr": { mclass: "mclose", size: 3 }, - "\\Biggr": { mclass: "mclose", size: 4 }, - "\\bigm": { mclass: "mrel", size: 1 }, - "\\Bigm": { mclass: "mrel", size: 2 }, - "\\biggm": { mclass: "mrel", size: 3 }, - "\\Biggm": { mclass: "mrel", size: 4 }, - "\\big": { mclass: "mord", size: 1 }, - "\\Big": { mclass: "mord", size: 2 }, - "\\bigg": { mclass: "mord", size: 3 }, - "\\Bigg": { mclass: "mord", size: 4 } -}; - -const delimiters = [ - "(", - "\\lparen", - ")", - "\\rparen", - "[", - "\\lbrack", - "]", - "\\rbrack", - "\\{", - "\\lbrace", - "\\}", - "\\rbrace", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lt", - "\\gt", - "\\lvert", - "\\rvert", - "\\lVert", - "\\rVert", - "\\lgroup", - "\\rgroup", - "\u27ee", - "\u27ef", - "\\lmoustache", - "\\rmoustache", - "\u23b0", - "\u23b1", - "\\llbracket", - "\\rrbracket", - "\u27e6", - "\u27e6", - "\\lBrace", - "\\rBrace", - "\u2983", - "\u2984", - "/", - "\\backslash", - "|", - "\\vert", - "\\|", - "\\Vert", - "\\uparrow", - "\\Uparrow", - "\\downarrow", - "\\Downarrow", - "\\updownarrow", - "\\Updownarrow", - "." -]; - -// Metrics of the different sizes. Found by looking at TeX's output of -// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ -// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. -const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; - -// Delimiter functions -function checkDelimiter(delim, context) { - if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") { - // Recover "/" from the zero spacing group. (See macros.js) - delim = { type: "textord", text: "/", mode: "math" }; - } - const symDelim = checkSymbolNodeType(delim); - if (symDelim && utils.contains(delimiters, symDelim.text)) { - // If a character is not in the MathML operator dictionary, it will not stretch. - // Replace such characters w/characters that will stretch. - if (utils.contains(["<", "\\lt"], symDelim.text)) { symDelim.text = "⟨"; } - if (utils.contains([">", "\\gt"], symDelim.text)) { symDelim.text = "⟩"; } - if (symDelim.text === "/") { symDelim.text = "\u2215"; } - if (symDelim.text === "\\backslash") { symDelim.text = "\u2216"; } - return symDelim; - } else if (symDelim) { - throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim); - } else { - throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim); - } -} - -defineFunction({ - type: "delimsizing", - names: [ - "\\bigl", - "\\Bigl", - "\\biggl", - "\\Biggl", - "\\bigr", - "\\Bigr", - "\\biggr", - "\\Biggr", - "\\bigm", - "\\Bigm", - "\\biggm", - "\\Biggm", - "\\big", - "\\Big", - "\\bigg", - "\\Bigg" - ], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - return { - type: "delimsizing", - mode: context.parser.mode, - size: delimiterSizes[context.funcName].size, - mclass: delimiterSizes[context.funcName].mclass, - delim: delim.text - }; - }, - mathmlBuilder: (group) => { - const children = []; - - if (group.delim === ".") { group.delim = ""; } - children.push(makeText(group.delim, group.mode)); - - const node = new mathMLTree.MathNode("mo", children); - - if (group.mclass === "mopen" || group.mclass === "mclose") { - // Only some of the delimsizing functions act as fences, and they - // return "mopen" or "mclose" mclass. - node.setAttribute("fence", "true"); - } else { - // Explicitly disable fencing if it's not a fence, to override the - // defaults. - node.setAttribute("fence", "false"); - } - if (group.delim === "\u2216") { - // \backslash is not in the operator dictionary, - // so we have to explicitly set stretchy to true. - node.setAttribute("stretchy", "true"); - } - - node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox. - node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em"); - node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em"); - - return node; - } -}); - -function assertParsed(group) { - if (!group.body) { - throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); - } -} - -defineFunction({ - type: "leftright-right", - names: ["\\right"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - // \left case below triggers parsing of \right in - // `const right = parser.parseFunction();` - // uses this return value. - const color = context.parser.gullet.macros.get("\\current@color"); - if (color && typeof color !== "string") { - throw new ParseError("\\current@color set to non-string in \\right"); - } - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text, - color // undefined if not set via \color - }; - } -}); - -defineFunction({ - type: "leftright", - names: ["\\left"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - const parser = context.parser; - // Parse out the implicit body - ++parser.leftrightDepth; - // parseExpression stops before '\\right' - const body = parser.parseExpression(false); - --parser.leftrightDepth; - // Check the next token - parser.expect("\\right", false); - const right = assertNodeType(parser.parseFunction(), "leftright-right"); - return { - type: "leftright", - mode: parser.mode, - body, - left: delim.text, - right: right.delim, - rightColor: right.color - }; - }, - mathmlBuilder: (group, style) => { - assertParsed(group); - const inner = buildExpression(group.body, style); - - if (group.left === ".") { group.left = ""; } - const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]); - leftNode.setAttribute("fence", "true"); - leftNode.setAttribute("form", "prefix"); - if (group.left === "\u2216") { leftNode.setAttribute("stretchy", "true"); } - inner.unshift(leftNode); - - if (group.right === ".") { group.right = ""; } - const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]); - rightNode.setAttribute("fence", "true"); - rightNode.setAttribute("form", "postfix"); - if (group.right === "\u2216") { rightNode.setAttribute("stretchy", "true"); } - if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor); } - inner.push(rightNode); - - return makeRow(inner); - } -}); - -defineFunction({ - type: "middle", - names: ["\\middle"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - if (!context.parser.leftrightDepth) { - throw new ParseError("\\middle without preceding \\left", delim); - } - - return { - type: "middle", - mode: context.parser.mode, - delim: delim.text - }; - }, - mathmlBuilder: (group, style) => { - const textNode = makeText(group.delim, group.mode); - const middleNode = new mathMLTree.MathNode("mo", [textNode]); - middleNode.setAttribute("fence", "true"); - // MathML gives 5/18em spacing to each element. - // \middle should get delimiter spacing instead. - middleNode.setAttribute("lspace", "0.05em"); - middleNode.setAttribute("rspace", "0.05em"); - return middleNode; - } -}); - -const mathmlBuilder$8 = (group, style) => { - const node = new mathMLTree.MathNode( - group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", - [buildGroup$1(group.body, style)] - ); - switch (group.label) { - case "\\cancel": - node.setAttribute("notation", "updiagonalstrike"); - break; - case "\\bcancel": - node.setAttribute("notation", "downdiagonalstrike"); - break; - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break; - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break; - case "\\sout": - node.setAttribute("notation", "horizontalstrike"); - break; - case "\\fbox": - node.setAttribute("notation", "box"); - break; - case "\\angl": - node.setAttribute("notation", "actuarial"); - break; - case "\\fcolorbox": - case "\\colorbox": { - // doesn't have a good notation option for \colorbox. - // So use instead. Set some attributes that come - // included with . - const fboxsep = 3; // 3 pt from LaTeX source2e - node.setAttribute("width", `+${2 * fboxsep}pt`); - node.setAttribute("height", `+${2 * fboxsep}pt`); - node.setAttribute("lspace", `${fboxsep}pt`); // - node.setAttribute("voffset", `${fboxsep}pt`); - if (group.label === "\\fcolorbox") { - node.setAttribute("style", "border: 0.06em solid " + String(group.borderColor)); - } - break; - } - case "\\xcancel": - node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); - break; - } - if (group.backgroundColor) { - node.setAttribute("mathbackground", group.backgroundColor); - } - return node; -}; - -defineFunction({ - type: "enclose", - names: ["\\colorbox"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - const body = args[1]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor: color, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -defineFunction({ - type: "enclose", - names: ["\\fcolorbox"], - props: { - numArgs: 3, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let borderColor = ""; - let backgroundColor; - if (model) { - const borderSpec = assertNodeType(args[0], "raw").string; - const backgroundSpec = assertNodeType(args[0], "raw").string; - borderColor = colorFromSpec(model, borderSpec); - backgroundColor = colorFromSpec(model, backgroundSpec); - } else { - borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros); - } - const body = args[2]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor, - borderColor, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -defineFunction({ - type: "enclose", - names: ["\\fbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "enclose", - mode: parser.mode, - label: "\\fbox", - body: args[0] - }; - } -}); - -defineFunction({ - type: "enclose", - names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\angl", "\\phase", "\\longdiv"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -/** - * All registered environments. - * `environments.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `environments.js`. - */ -const _environments = {}; - -function defineEnvironment({ type, names, props, handler, mathmlBuilder }) { - // Set default values of environments. - const data = { - type, - numArgs: props.numArgs || 0, - allowedInText: false, - numOptionalArgs: 0, - handler - }; - for (let i = 0; i < names.length; ++i) { - _environments[names[i]] = data; - } - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } -} - -// In TeX, there are actually three sets of dimensions, one for each of - -// Math style is not quite the same thing as script level. -const StyleLevel = { - DISPLAY: 0, - TEXT: 1, - SCRIPT: 2, - SCRIPTSCRIPT: 3 -}; - -// Helper functions -function getHLines(parser) { - // Return an array. The array length = number of hlines. - // Each element in the array tells if the line is dashed. - const hlineInfo = []; - parser.consumeSpaces(); - let nxt = parser.fetch().text; - while (nxt === "\\hline" || nxt === "\\hdashline") { - parser.consume(); - hlineInfo.push(nxt === "\\hdashline"); - parser.consumeSpaces(); - nxt = parser.fetch().text; - } - return hlineInfo; -} - -const validateAmsEnvironmentContext = context => { - const settings = context.parser.settings; - if (!settings.displayMode) { - throw new ParseError(`{${context.envName}} can be used only in display mode.`); - } -}; - -const getTag = (group, style, rowNum) => { - let tag; - const tagContents = group.tags.shift(); - if (tagContents) { - // The author has written a \tag or a \notag in this row. - if (tagContents.body) { - tag = buildExpressionRow(tagContents.body, style); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } - } else if (group.colSeparationType === "multline" && - ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) { - // A multiline that does not receive a tag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a post-processor. - tag = new mathMLTree.MathNode("mtext", [], ["tml-eqn"]); - } - if (!group.preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - if (!group.leqno) { tag.setAttribute("lspace", "-1width"); } - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!group.preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - return tag -}; - -/** - * Parse the body of the environment, with rows delimited by \\ and - * columns delimited by &, and create a nested list in row-major order - * with one group per cell. If given an optional argument scriptLevel - * ("text", "display", etc.), then each cell is cast into that scriptLevel. - */ -function parseArray( - parser, - { - hskipBeforeAndAfter, // boolean - addJot, // boolean - cols, // [{ type: string , align: l|c|r|null }] - arraystretch, // number - colSeparationType, // "align" | "alignat" | "gather" | "small" | "CD" | "multline" - addEqnNum, // boolean - singleRow, // boolean - emptySingleRow, // boolean - maxNumCols, // number - leqno // boolean - }, - scriptLevel -) { - parser.gullet.beginGroup(); - if (!singleRow) { - // \cr is equivalent to \\ without the optional size argument (see below) - // TODO: provide helpful error when \cr is used outside array environment - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - } - if (addEqnNum) { - parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // Get current arraystretch if it's not set by the environment - if (arraystretch === undefined || Number.isNaN(arraystretch)) { - const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); - if (stretch == null) { - // Default \arraystretch from lttab.dtx - arraystretch = 1; - } else { - arraystretch = parseFloat(stretch); - if (!arraystretch || arraystretch < 0) { - throw new ParseError(`Invalid \\arraystretch: ${stretch}`); - } - } - } - - // Start group for first cell - parser.gullet.beginGroup(); - - let row = []; - const body = [row]; - const rowGaps = []; - const tags = []; - let rowTag; - const hLinesBeforeRow = []; - - // Test for \hline at the top of the array. - hLinesBeforeRow.push(getHLines(parser)); - - // eslint-disable-next-line no-constant-condition - while (true) { - // Parse each cell in its own group (namespace) - let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\"); - - if (addEqnNum && !rowTag) { - // Check if the author wrote a \tag{} inside this cell. - for (let i = 0; i < cell.length; i++) { - if (cell[i].type === "envTag" || cell[i].type === "noTag") { - // Get the contents of the \text{} nested inside the \env@Tag{} - rowTag = cell[i].type === "envTag" - ? cell.splice(i, 1)[0].body.body[0] - : { body: null }; - break - } - } - } - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - - cell = { - type: "ordgroup", - mode: parser.mode, - body: cell - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (colSeparationType === "split") { - throw new ParseError("The split environment accepts no more than two columns", - parser.nextToken); - } else if (colSeparationType === "array") { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else { - throw new ParseError("The equation environment accepts only one column", - parser.nextToken) - } - } - parser.consume(); - } else if (next === "\\end") { - // Arrays terminate newlines with `\crcr` which consumes a `\cr` if - // the last line is empty. However, AMS environments keep the - // empty row if it's the only one. - // NOTE: Currently, `cell` is the last item added into `row`. - if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) { - body.pop(); - } - if (hLinesBeforeRow.length < body.length + 1) { - hLinesBeforeRow.push([]); - } - break; - } else if (next === "\\\\") { - parser.consume(); - let size; - // \def\Let@{\let\\\math@cr} - // \def\math@cr{...\math@cr@} - // \def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}} - // \def\math@cr@@[#1]{...\math@cr@@@...} - // \def\math@cr@@@{\cr} - if (parser.gullet.future().text !== " ") { - size = parser.parseSizeGroup(true); - } - rowGaps.push(size ? size.value : null); - - tags.push(rowTag); - - // check for \hline(s) following the row separator - hLinesBeforeRow.push(getHLines(parser)); - - row = []; - rowTag = null; - body.push(row); - } else { - throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); - } - } - - // End cell group - parser.gullet.endGroup(); - // End array group defining \cr - parser.gullet.endGroup(); - - tags.push(rowTag); - - return { - type: "array", - mode: parser.mode, - addJot, - arraystretch, - body, - cols, - rowGaps, - hskipBeforeAndAfter, - hLinesBeforeRow, - colSeparationType, - addEqnNum, - scriptLevel, - tags, - leqno, - preventTagLap: parser.settings.preventTagLap - }; -} - -// Decides on a scriptLevel for cells in an array according to whether the given -// environment name starts with the letter 'd'. -function dCellStyle(envName) { - return envName.slice(0, 1) === "d" ? "display" : "text" -} - -const alignMap = { - c: "center ", - l: "left ", - r: "right " -}; - -const mathmlBuilder$7 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - let glue; - if (group.addEqnNum) { - glue = new mathMLTree.MathNode("mtd", [], []); - const glueStyle = "padding: 0;width: " + - (group.colSeparationType === "multline" ? "7.5%" : "50%"); - glue.setAttribute("style", glueStyle); - } - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellStyle = group.scriptLevel === "text" - ? StyleLevel.TEXT - : group.scriptLevel === "script" - ? StyleLevel.SCRIPT - : StyleLevel.DISPLAY; - - for (let j = 0; j < rw.length; j++) { - const mtd = new mathMLTree.MathNode( - "mtd", - [buildGroup$1(rw[j], style.withLevel(cellStyle))] - ); - if (group.colSeparationType === "multline") { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue); - row.push(glue); - const tag = getTag(group, style.withLevel(cellStyle), i); - if (group.leqno) { - row.unshift(tag); - } else { - row.push(tag); - } - } - // If group.addEqnNum, insert a breadcrumb to be found by temmlPostProcess(). - tbl.push(new mathMLTree.MathNode("mtr", row, group.addEqnNum ? ["tml-tageqn"] : [] )); - } - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - // Set column alignment, row spacing, column spacing, and - // array lines by setting attributes on the table element. - - // Set the row spacing. In MathML, we specify a gap distance. - // We do not use rowGap[] because MathML automatically increases - // cell height with the height/depth of the element content. - - // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. - // We simulate this by adding (arraystretch - 1)em to the gap. This - // does a reasonable job of adjusting arrays containing 1 em tall content. - - // The 0.16 and 0.09 values are found emprically. They produce an array - // similar to LaTeX and in which content does not interfere with \hines. - const gap = - group.arraystretch === 0 - ? 0 // {subarray} - : group.arraystretch === 0.5 - ? 0.1 // {smallmatrix} - : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); - table.setAttribute("rowspacing", utils.round(gap) + "em"); - - if (group.addEqnNum || group.colSeparationType === "multline") { - table.setAttribute("width", "100%"); - } - - // MathML table lines go only between cells. - // To place a line on an edge we'll use , if necessary. - let menclose = ""; - let align = ""; - - if (group.cols && group.cols.length > 0) { - // Find column alignment, column spacing, and vertical lines. - const cols = group.cols; - let columnLines = ""; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - if (cols[0].type === "separator") { - menclose += "left "; - iStart = 1; - } - if (cols[cols.length - 1].type === "separator") { - menclose += "right "; - iEnd -= 1; - } - - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - align += alignMap[cols[i].align]; - - if (prevTypeWasAlign) { - columnLines += "none "; - } - prevTypeWasAlign = true; - } else if (cols[i].type === "separator") { - // MathML accepts only single lines between cells. - // So we read only the first of consecutive separators. - if (prevTypeWasAlign) { - columnLines += cols[i].separator === "|" ? "solid " : "dashed "; - prevTypeWasAlign = false; - } - } - } - if (group.addEqnNum) { - align = "left " + align + "right "; // allow for glue cells on each side - align = group.leqno ? "left " + align : align += "right"; // eqn num cell - } - - table.setAttribute("columnalign", align.trim()); - - if (/[sd]/.test(columnLines)) { - table.setAttribute("columnlines", columnLines.trim()); - } - } - - // Set column spacing. - switch (group.colSeparationType) { - case "gather": - case "gathered": - case "alignedat": - case "alignat": - case "alignat*": - table.setAttribute("columnspacing", "0em"); - break - case "small": - table.setAttribute("columnspacing", "0.2778em"); - break - case "CD": - table.setAttribute("columnspacing", "0.5em"); - break - case "align": - case "align*": { - const cols = group.cols || []; - let spacing = group.addEqnNum ? "0em " : ""; - for (let i = 1; i < cols.length; i++) { - spacing += i % 2 ? "0em " : "1em "; - } - if (group.addEqnNum) { spacing += "0em"; } - table.setAttribute("columnspacing", spacing.trim()); - break - } - default: - table.setAttribute("columnspacing", "1em"); - } - - // Address \hline and \hdashline - let rowLines = ""; - const hlines = group.hLinesBeforeRow; - - menclose += hlines[0].length > 0 ? "top " : ""; - menclose += hlines[hlines.length - 1].length > 0 ? "bottom " : ""; - - for (let i = 1; i < hlines.length - 1; i++) { - rowLines += - hlines[i].length === 0 - ? "none " - : // MathML accepts only a single line between rows. Read one element. - hlines[i][0] - ? "dashed " - : "solid "; - } - if (/[sd]/.test(rowLines)) { - table.setAttribute("rowlines", rowLines.trim()); - } - - if (menclose !== "") { - table = new mathMLTree.MathNode("menclose", [table]); - table.setAttribute("notation", menclose.trim()); - } - - if (!Number.isNaN(group.arraystretch) && group.arraystretch < 1) { - // A small array. Wrap in scriptstyle so row gap is not too large. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table; -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addJot: true, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - colSeparationType: context.envName, - maxNumCols: context.envName === "split" ? 2 : undefined, - leqno: context.parser.settings.leqno - }, - "display" - ); - - // Determining number of columns. - // 1. If the first argument is given, we use it as a number of columns, - // and makes sure that each row doesn't exceed that number. - // 2. Otherwise, just count number of columns = maximum number - // of cells in each row ("aligned" mode -- isAligned will be true). - // - // At the same time, prepend empty group {} at beginning of every second - // cell in each row (starting with second cell) so that operators become - // binary. This behavior is implemented in amsmath's \start@aligned. - let numMaths; - let numCols = 0; - if (args[0] && args[0].type === "ordgroup") { - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - const isAligned = !numCols; - res.body.forEach(function(row) { - if (!isAligned) { - // Case 1 - const curMaths = row.length / 2; - if (numMaths < curMaths) { - throw new ParseError( - "Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, - row[0] - ); - } - } else if (numCols < row.length) { - // Case 2 - numCols = row.length; - } - }); - - // Adjusting alignment. - // In aligned mode, we add one \qquad between columns; - // otherwise we add nothing. - for (let i = 0; i < numCols; ++i) { - let align = "r"; - if (i % 2 === 1) { - align = "l"; - } - cols[i] = { - type: "align", - align: align - }; - } - res.colSeparationType = isAligned ? "align" : "alignat"; - return res; -}; - -// Arrays are part of LaTeX, defined in lttab.dtx so its documentation -// is part of the source2e.pdf file of LaTeX2e source documentation. -// {darray} is an {array} environment where cells are set in \displaystyle, -// as defined in nccmath.sty. -defineEnvironment({ - type: "array", - names: ["array", "darray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Since no types are specified above, the two possibilities are - // - The argument is wrapped in {} or [], in which case Parser's - // parseGroup() returns an "ordgroup" wrapping some symbol node. - // - The argument is a bare symbol node. - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - if ("lcr".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } else if (ca === "|") { - return { - type: "separator", - separator: "|" - }; - } else if (ca === ":") { - return { - type: "separator", - separator: ":" - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - const res = { - cols, - colSeparationType: "array", - hskipBeforeAndAfter: true, // \@preamble in lttab.dtx - maxNumCols: cols.length - }; - return parseArray(context.parser, res, dCellStyle(context.envName)); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// The matrix environments of amsmath builds on the array environment -// of LaTeX, which is discussed above. -// The mathtools package adds starred versions of the same environments. -// These have an optional argument to choose left|center|right justification. -defineEnvironment({ - type: "array", - names: [ - "matrix", - "pmatrix", - "bmatrix", - "Bmatrix", - "vmatrix", - "Vmatrix", - "matrix*", - "pmatrix*", - "bmatrix*", - "Bmatrix*", - "vmatrix*", - "Vmatrix*" - ], - props: { - numArgs: 0 - }, - handler(context) { - const delimiters = { - matrix: null, - pmatrix: ["(", ")"], - bmatrix: ["[", "]"], - Bmatrix: ["\\{", "\\}"], - vmatrix: ["|", "|"], - Vmatrix: ["\\Vert", "\\Vert"] - }[context.envName.replace("*", "")]; - // \hskip -\arraycolsep in amsmath - let colAlign = "c"; - const payload = { - hskipBeforeAndAfter: false, - colSeparationType: "matrix", - cols: [{ type: "align", align: colAlign }] - }; - if (context.envName.charAt(context.envName.length - 1) === "*") { - // It's one of the mathtools starred functions. - // Parse the optional alignment argument. - const parser = context.parser; - parser.consumeSpaces(); - if (parser.fetch().text === "[") { - parser.consume(); - parser.consumeSpaces(); - colAlign = parser.fetch().text; - if ("lcr".indexOf(colAlign) === -1) { - throw new ParseError("Expected l or c or r", parser.nextToken); - } - parser.consume(); - parser.consumeSpaces(); - parser.expect("]"); - parser.consume(); - payload.cols = [{ type: "align", align: colAlign }]; - } - } - const res = parseArray(context.parser, payload, "text"); - // Populate cols with the correct number of column alignment specs. - const numCols = Math.max(0, ...res.body.map((row) => row.length)); - res.cols = new Array(numCols).fill({ type: "align", align: colAlign }); - return delimiters - ? { - type: "leftright", - mode: context.mode, - body: [res], - left: delimiters[0], - right: delimiters[1], - rightColor: undefined // \right uninfluenced by \color in array - } - : res; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["smallmatrix"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { arraystretch: 0.5 }; - const res = parseArray(context.parser, payload, "script"); - res.colSeparationType = "small"; - return res; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["subarray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Parsing of {subarray} is similar to {array} - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - // {subarray} only recognizes "l" & "c" - if ("lc".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - if (cols.length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - let res = { - cols, - hskipBeforeAndAfter: false, - colSeparationType: "array", - arraystretch: 0 - }; - res = parseArray(context.parser, res, "script"); - if (res.body.length > 0 && res.body[0].length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - return res; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// A cases environment (in amsmath.sty) is almost equivalent to -// \def -// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. -// {dcases} is a {cases} environment where cells are set in \displaystyle, -// as defined in mathtools.sty. -// {rcases} is another mathtools environment. It's brace is on the right side. -defineEnvironment({ - type: "array", - names: ["cases", "dcases", "rcases", "drcases"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { - cols: [ - { - type: "align", - align: "l" - }, - { - type: "align", - align: "l" - } - ], - colSeparationType: "cases" - }; - const res = parseArray(context.parser, payload, dCellStyle(context.envName)); - return { - type: "leftright", - mode: context.mode, - body: [res], - left: context.envName.indexOf("r") > -1 ? "." : "\\{", - right: context.envName.indexOf("r") > -1 ? "\\}" : ".", - rightColor: undefined - }; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// In the align environment, one uses ampersands, &, to specify number of -// columns in each row, and to locate spacing between each column. -// align gets automatic numbering. align* and aligned do not. -// The alignedat environment can be used in math mode. -// Note that we assume \nomallineskiplimit to be zero, -// so that \strut@ is the same as \strut. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$7 -}); - -// A gathered environment is like an array environment with one centered -// column, but where rows are considered lines so get \jot line spacing -// and contents are set in \displaystyle. -defineEnvironment({ - type: "array", - names: ["gathered", "gather", "gather*"], - props: { - numArgs: 0 - }, - handler(context) { - if (utils.contains(["gather", "gather*"], context.envName)) { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [ - { - type: "align", - align: "c" - } - ], - addJot: true, - colSeparationType: "gather", - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// alignat environment is like an align environment, but one must explicitly -// specify maximum number of columns in each row, and can adjust spacing between -// each columns. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["equation", "equation*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "equation", - emptySingleRow: true, - singleRow: true, - maxNumCols: 1, - colSeparationType: "gather", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["multline", "multline*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "multline", - maxNumCols: 1, - colSeparationType: "multline", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["CD"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - return parseCD(context.parser); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// Catch \hline outside array environment -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\hline", "\\hdashline"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: true - }, - handler(context, args) { - throw new ParseError(`${context.funcName} valid only within array environment`); - } -}); - -const environments = _environments; - -// Environment delimiters. HTML/MathML rendering is defined in the corresponding -// defineEnvironment definitions. -defineFunction({ - type: "environment", - names: ["\\begin", "\\end"], - props: { - numArgs: 1, - argTypes: ["text"] - }, - handler({ parser, funcName }, args) { - const nameGroup = args[0]; - if (nameGroup.type !== "ordgroup") { - throw new ParseError("Invalid environment name", nameGroup); - } - let envName = ""; - for (let i = 0; i < nameGroup.body.length; ++i) { - envName += assertNodeType(nameGroup.body[i], "textord").text; - } - - if (funcName === "\\begin") { - // begin...end is similar to left...right - if (!Object.prototype.hasOwnProperty.call(environments, envName )) { - throw new ParseError("No such environment: " + envName, nameGroup); - } - // Build the environment object. Arguments and other information will - // be made available to the begin and end methods using properties. - const env = environments[envName]; - const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env); - const context = { - mode: parser.mode, - envName, - parser - }; - const result = env.handler(context, args, optArgs); - parser.expect("\\end", false); - const endNameToken = parser.nextToken; - const end = assertNodeType(parser.parseFunction(), "environment"); - if (end.name !== envName) { - throw new ParseError( - `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, - endNameToken - ); - } - return result; - } - - return { - type: "environment", - mode: parser.mode, - name: envName, - nameGroup - }; - } -}); - -defineFunction({ - type: "envTag", - names: ["\\env@tag"], - props: { - numArgs: 1, - argTypes: ["math"] - }, - handler({ parser }, args) { - return { - type: "envTag", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -defineFunction({ - type: "noTag", - names: ["\\env@notag"], - props: { - numArgs: 0 - }, - handler({ parser }) { - return { - type: "noTag", - mode: parser.mode - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -const mathmlBuilder$6 = (group, style) => { - const font = group.font; - const newStyle = style.withFont(font); - const mathGroup = buildGroup$1(group.body, newStyle); - - if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{} - if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - let canConsolidate = mathGroup.children[0].type === "mo"; - for (let i = 1; i < mathGroup.children.length; i++) { - if (mathGroup.children[i].type === "mo" && font === "boldsymbol") { - mathGroup.children[i].style.fontWeight = "bold"; - } - if (mathGroup.children[i].type !== "mi") { canConsolidate = false; } - const localVariant = mathGroup.children[i].attributes && - mathGroup.children[i].attributes.mathvariant || ""; - if (localVariant !== "normal") { canConsolidate = false; } - } - if (!canConsolidate) { return mathGroup } - // Consolidate the elements. - const mi = mathGroup.children[0]; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children.push(mathGroup.children[i].children[0]); - } - if (mathGroup.attributes.mathcolor) { mi.attributes.mathcolor = mathGroup.attributes.mathcolor; } - if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") { - // Workaround for a Firefox bug that renders spurious space around - // a - // Ref: https://bugs.webkit.org/show_bug.cgi?id=129097 - // We insert a text node that contains a zero-width space and wrap in an mrow. - // TODO: Get rid of this workaround when the Firefox bug is fixed. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - return mi -}; - -const fontAliases = { - "\\Bbb": "\\mathbb", - "\\bold": "\\mathbf", - "\\frak": "\\mathfrak", - "\\bm": "\\boldsymbol" -}; - -defineFunction({ - type: "font", - names: [ - // styles - "\\mathrm", - "\\mathit", - "\\mathbf", - "\\mathnormal", - "\\up@greek", - "\\boldsymbol", - - // families - "\\mathbb", - "\\mathcal", - "\\mathfrak", - "\\mathscr", - "\\mathsf", - "\\mathtt", - "\\oldstylenums", - - // aliases - "\\Bbb", - "\\bm", - "\\bold", - "\\frak" - ], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = normalizeArgument(args[0]); - let func = funcName; - if (func in fontAliases) { - func = fontAliases[func]; - } - return { - type: "font", - mode: parser.mode, - font: func.slice(1), - body - }; - }, - mathmlBuilder: mathmlBuilder$6 -}); - -// Old font changing functions -defineFunction({ - type: "font", - names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ parser, funcName, breakOnTokenText }, args) => { - const { mode } = parser; - const body = parser.parseExpression(true, breakOnTokenText); - const fontStyle = `math${funcName.slice(1)}`; - - return { - type: "font", - mode: mode, - font: fontStyle, - body: { - type: "ordgroup", - mode: parser.mode, - body - } - }; - }, - mathmlBuilder: mathmlBuilder$6 -}); - -const stylArray = ["display", "text", "script", "scriptscript"]; -const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 }; - -const mathmlBuilder$5 = (group, style) => { - // Track the scriptLevel of the numerator and denominator. - // We may need that info for \mathchoice or for adjusting em dimensions. - const childOptions = group.scriptLevel === "auto" - ? style.incrementLevel() - : group.scriptLevel === "display" - ? style.withLevel(StyleLevel.TEXT) - : group.scriptLevel === "text" - ? style.withLevel(StyleLevel.SCRIPT) - : style.withLevel(StyleLevel.SCRIPTSCRIPT); - - let node = new mathMLTree.MathNode("mfrac", [ - buildGroup$1(group.numer, childOptions), - buildGroup$1(group.denom, childOptions) - ]); - - if (!group.hasBarLine) { - node.setAttribute("linethickness", "0px"); - } else if (group.barSize) { - const ruleWidth = calculateSize(group.barSize, style); - node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit); - } - - if (group.leftDelim != null || group.rightDelim != null) { - const withDelims = []; - - if (group.leftDelim != null) { - const leftOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.leftDelim.replace("\\", "")) - ]); - leftOp.setAttribute("fence", "true"); - withDelims.push(leftOp); - } - - withDelims.push(node); - - if (group.rightDelim != null) { - const rightOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.rightDelim.replace("\\", "")) - ]); - rightOp.setAttribute("fence", "true"); - withDelims.push(rightOp); - } - - node = makeRow(withDelims); - } - - if (group.scriptLevel !== "auto") { - node = new mathMLTree.MathNode("mstyle", [node]); - node.setAttribute("displaystyle", String(group.scriptLevel === "display")); - node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]); - } - - return node; -}; - -defineFunction({ - type: "genfrac", - names: [ - "\\dfrac", - "\\frac", - "\\tfrac", - "\\dbinom", - "\\binom", - "\\tbinom", - "\\\\atopfrac", // can’t be entered directly - "\\\\bracefrac", - "\\\\brackfrac" // ditto - ], - props: { - numArgs: 2, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - let hasBarLine = false; - let leftDelim = null; - let rightDelim = null; - let scriptLevel = "auto"; - - switch (funcName) { - case "\\dfrac": - case "\\frac": - case "\\tfrac": - hasBarLine = true; - break; - case "\\\\atopfrac": - hasBarLine = false; - break; - case "\\dbinom": - case "\\binom": - case "\\tbinom": - leftDelim = "("; - rightDelim = ")"; - break; - case "\\\\bracefrac": - leftDelim = "\\{"; - rightDelim = "\\}"; - break; - case "\\\\brackfrac": - leftDelim = "["; - rightDelim = "]"; - break; - default: - throw new Error("Unrecognized genfrac command"); - } - - switch (funcName) { - case "\\dfrac": - case "\\dbinom": - scriptLevel = "display"; - break; - case "\\tfrac": - case "\\tbinom": - scriptLevel = "text"; - break; - } - - return { - type: "genfrac", - mode: parser.mode, - continued: false, - numer, - denom, - hasBarLine, - leftDelim, - rightDelim, - scriptLevel, - barSize: null - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -defineFunction({ - type: "genfrac", - names: ["\\cfrac"], - props: { - numArgs: 2 - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - - return { - type: "genfrac", - mode: parser.mode, - continued: true, - numer, - denom, - hasBarLine: true, - leftDelim: null, - rightDelim: null, - scriptLevel: "display", - barSize: null - }; - } -}); - -// Infix generalized fractions -- these are not rendered directly, but replaced -// immediately by one of the variants above. -defineFunction({ - type: "infix", - names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], - props: { - numArgs: 0, - infix: true - }, - handler({ parser, funcName, token }) { - let replaceWith; - switch (funcName) { - case "\\over": - replaceWith = "\\frac"; - break; - case "\\choose": - replaceWith = "\\binom"; - break; - case "\\atop": - replaceWith = "\\\\atopfrac"; - break; - case "\\brace": - replaceWith = "\\\\bracefrac"; - break; - case "\\brack": - replaceWith = "\\\\brackfrac"; - break; - default: - throw new Error("Unrecognized infix genfrac command"); - } - return { - type: "infix", - mode: parser.mode, - replaceWith, - token - }; - } -}); - -const delimFromValue = function(delimString) { - let delim = null; - if (delimString.length > 0) { - delim = delimString; - delim = delim === "." ? null : delim; - } - return delim; -}; - -defineFunction({ - type: "genfrac", - names: ["\\genfrac"], - props: { - numArgs: 6, - allowedInArgument: true, - argTypes: ["math", "math", "size", "text", "math", "math"] - }, - handler({ parser }, args) { - const numer = args[4]; - const denom = args[5]; - - // Look into the parse nodes to get the desired delimiters. - const leftNode = normalizeArgument(args[0]); - const leftDelim = leftNode.type === "atom" && leftNode.family === "open" - ? delimFromValue(leftNode.text) - : null; - const rightNode = normalizeArgument(args[1]); - const rightDelim = - rightNode.type === "atom" && rightNode.family === "close" - ? delimFromValue(rightNode.text) - : null; - - const barNode = assertNodeType(args[2], "size"); - let hasBarLine; - let barSize = null; - if (barNode.isBlank) { - // \genfrac acts differently than \above. - // \genfrac treats an empty size group as a signal to use a - // standard bar size. \above would see size = 0 and omit the bar. - hasBarLine = true; - } else { - barSize = barNode.value; - hasBarLine = barSize.number > 0; - } - - // Find out if we want displaystyle, textstyle, etc. - let scriptLevel = "auto"; - let styl = args[3]; - if (styl.type === "ordgroup") { - if (styl.body.length > 0) { - const textOrd = assertNodeType(styl.body[0], "textord"); - scriptLevel = stylArray[Number(textOrd.text)]; - } - } else { - styl = assertNodeType(styl, "textord"); - scriptLevel = stylArray[Number(styl.text)]; - } - - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim, - rightDelim, - scriptLevel - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -// \above is an infix fraction that also defines a fraction bar size. -defineFunction({ - type: "infix", - names: ["\\above"], - props: { - numArgs: 1, - argTypes: ["size"], - infix: true - }, - handler({ parser, funcName, token }, args) { - return { - type: "infix", - mode: parser.mode, - replaceWith: "\\\\abovefrac", - barSize: assertNodeType(args[0], "size").value, - token - }; - } -}); - -defineFunction({ - type: "genfrac", - names: ["\\\\abovefrac"], - props: { - numArgs: 3, - argTypes: ["math", "size", "math"] - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const barSize = assert(assertNodeType(args[1], "infix").barSize); - const denom = args[2]; - - const hasBarLine = barSize.number > 0; - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim: null, - rightDelim: null, - scriptLevel: "auto" - }; - }, - - mathmlBuilder: mathmlBuilder$5 -}); - -const mathmlBuilder$4 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [ - buildGroup$1(group.base, style), - accentNode - ]); -}; - -// Horizontal stretchy braces -defineFunction({ - type: "horizBrace", - names: ["\\overbrace", "\\underbrace"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "horizBrace", - mode: parser.mode, - label: funcName, - isOver: /^\\over/.test(funcName), - base: args[0] - }; - }, - mathmlBuilder: mathmlBuilder$4 -}); - -defineFunction({ - type: "href", - names: ["\\href"], - props: { - numArgs: 2, - argTypes: ["url", "original"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const body = args[1]; - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\href", - url: href - }) - ) { - throw new ParseError(`Function "\\href" is not trusted`, token) - } - - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - let math = buildExpressionRow(group.body, style); - if (!(math instanceof MathNode)) { - math = new MathNode("mrow", [math]); - } - math.setAttribute("href", group.href); - return math; - } -}); - -defineFunction({ - type: "href", - names: ["\\url"], - props: { - numArgs: 1, - argTypes: ["url"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\url", - url: href - }) - ) { - throw new ParseError(`Function "\\url" is not trusted`, token) - } - - const chars = []; - for (let i = 0; i < href.length; i++) { - let c = href[i]; - if (c === "~") { - c = "\\textasciitilde"; - } - chars.push({ - type: "textord", - mode: "text", - text: c - }); - } - const body = { - type: "text", - mode: parser.mode, - font: "\\texttt", - body: chars - }; - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - } -}); - -defineFunction({ - type: "html", - names: ["\\class", "\\id", "\\style", "\\data"], - props: { - numArgs: 2, - argTypes: ["raw", "original"], - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - const value = assertNodeType(args[0], "raw").string; - const body = args[1]; - - if (parser.settings.strict) { - throw new ParseError(`Function "${funcName}" is disabled in strict mode`, token) - } - - let trustContext; - const attributes = {}; - - switch (funcName) { - case "\\class": - attributes.class = value; - trustContext = { - command: "\\class", - class: value - }; - break; - case "\\id": - attributes.id = value; - trustContext = { - command: "\\id", - id: value - }; - break; - case "\\style": - attributes.style = value; - trustContext = { - command: "\\style", - style: value - }; - break; - case "\\data": { - const data = value.split(","); - for (let i = 0; i < data.length; i++) { - const keyVal = data[i].split("="); - if (keyVal.length !== 2) { - throw new ParseError("Error parsing key-value for \\data"); - } - attributes["data-" + keyVal[0].trim()] = keyVal[1].trim(); - } - - trustContext = { - command: "\\data", - attributes - }; - break; - } - default: - throw new Error("Unrecognized html command"); - } - - if (!parser.settings.isTrusted(trustContext)) { - throw new ParseError(`Function "${funcName}" is not trusted`, token) - } - return { - type: "html", - mode: parser.mode, - attributes, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const element = buildExpressionRow(group.body, style); - - const classes = []; - if (group.attributes.class) { - classes.push(...group.attributes.class.trim().split(/\s+/)); - } - element.classes = classes; - - for (const attr in group.attributes) { - if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) { - element.setAttribute(attr, group.attributes[attr]); - } - } - - return element; - } -}); - -const sizeData = function(str) { - if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { - // str is a number with no unit specified. - // default unit is bp, per graphix package. - return { number: +str, unit: "bp" } - } else { - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); - if (!match) { - throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); - } - return data - } -}; - -defineFunction({ - type: "includegraphics", - names: ["\\includegraphics"], - props: { - numArgs: 1, - numOptionalArgs: 1, - argTypes: ["raw", "url"], - allowedInText: false - }, - handler: ({ parser, token }, args, optArgs) => { - let width = { number: 0, unit: "em" }; - let height = { number: 0.9, unit: "em" }; // sorta character sized. - let totalheight = { number: 0, unit: "em" }; - let alt = ""; - - if (optArgs[0]) { - const attributeStr = assertNodeType(optArgs[0], "raw").string; - - // Parser.js does not parse key/value pairs. We get a string. - const attributes = attributeStr.split(","); - for (let i = 0; i < attributes.length; i++) { - const keyVal = attributes[i].split("="); - if (keyVal.length === 2) { - const str = keyVal[1].trim(); - switch (keyVal[0].trim()) { - case "alt": - alt = str; - break - case "width": - width = sizeData(str); - break - case "height": - height = sizeData(str); - break - case "totalheight": - totalheight = sizeData(str); - break - default: - throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics.") - } - } - } - } - - const src = assertNodeType(args[0], "url").url; - - if (alt === "") { - // No alt given. Use the file name. Strip away the path. - alt = src; - alt = alt.replace(/^.*[\\/]/, ""); - alt = alt.substring(0, alt.lastIndexOf(".")); - } - - if ( - !parser.settings.isTrusted({ - command: "\\includegraphics", - url: src - }) - ) { - throw new ParseError(`Function "\\includegraphics" is not trusted`, token) - } - - return { - type: "includegraphics", - mode: parser.mode, - alt: alt, - width: width, - height: height, - totalheight: totalheight, - src: src - } - }, - mathmlBuilder: (group, style) => { - const height = calculateSize(group.height, style); - const depth = { number: 0, unit: "em" }; - - if (group.totalheight.number > 0) { - if (group.totalheight.unit === height.unit && - group.totalheight.number > height.number) { - depth.number = group.totalheight.number - height.number; - depth.unit = height.unit; - } - } - - let width = 0; - if (group.width.number > 0) { - width = calculateSize(group.width, style); - } - - const graphicStyle = { height: height.number + depth.number + "em" }; - if (width.number > 0) { - graphicStyle.width = width.number + width.unit; - } - if (depth.number > 0) { - graphicStyle.verticalAlign = -depth.number + depth.unit; - } - - const node = new Img(group.src, group.alt, graphicStyle); - node.height = height; - node.depth = depth; - return new mathMLTree.MathNode("mtext", [node]) - } -}); - -// Horizontal spacing commands - -// TODO: \hskip and \mskip should support plus and minus in lengths - -defineFunction({ - type: "kern", - names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], - props: { - numArgs: 1, - argTypes: ["size"], - primitive: true, - allowedInText: true - }, - handler({ parser, funcName, token }, args) { - const size = assertNodeType(args[0], "size"); - if (parser.settings.strict) { - const mathFunction = funcName[1] === "m"; // \mkern, \mskip - const muUnit = size.value.unit === "mu"; - if (mathFunction) { - if (!muUnit) { - throw new ParseError(`LaTeX's ${funcName} supports only mu units, ` + - `not ${size.value.unit} units`, token) - } - if (parser.mode !== "math") { - throw new ParseError(`LaTeX's ${funcName} works only in math mode`, token) - } - } else { - // !mathFunction - if (muUnit) { - throw new ParseError(`LaTeX's ${funcName} doesn't support mu units`, token) - } - } - } - return { - type: "kern", - mode: parser.mode, - dimension: size.value - }; - }, - mathmlBuilder(group, style) { - const dimension = calculateSize(group.dimension, style); - const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : ""; - if (group.mode === "text" && ch.length > 0) { - const character = new mathMLTree.TextNode(ch); - return new mathMLTree.MathNode("mtext", [character]); - } else { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", dimension.number + dimension.unit); - return node; - } - } -}); - -const spaceCharacter = function(width) { - if (width >= 0.05555 && width <= 0.05556) { - return "\u200a"; //   - } else if (width >= 0.1666 && width <= 0.1667) { - return "\u2009"; //   - } else if (width >= 0.2222 && width <= 0.2223) { - return "\u2005"; //   - } else if (width >= 0.2777 && width <= 0.2778) { - return "\u2005\u200a"; //    - } else { - return ""; - } -}; - -// Limit valid characters to a small set, for safety. -const invalidIdRegEx = /[^A-Za-z_0-9-]/g; - -defineFunction({ - type: "label", - names: ["\\label"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser }, args) { - return { - type: "label", - mode: parser.mode, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Return a no-width, no-ink element with an HTML id. - const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]); - if (group.string.length > 0) { - node.setAttribute("id", group.string); - } - return node - } -}); - -// Horizontal overlap functions - -const textModeLap = ["\\clap", "\\llap", "\\rlap"]; - -defineFunction({ - type: "lap", - names: ["\\mathllap", "\\mathrlap", "\\mathclap", "\\clap", "\\llap", "\\rlap"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - if (textModeLap.includes(funcName)) { - if (parser.settings.strict && parser.mode !== "text") { - throw new ParseError(`{${funcName}} can be used only in text mode. - Try \\math${funcName.slice(1)}`, token) - } - funcName = funcName.slice(1); - } else { - funcName = funcName.slice(5); - } - const body = args[0]; - return { - type: "lap", - mode: parser.mode, - alignment: funcName, - body - } - }, - mathmlBuilder: (group, style) => { - // mathllap, mathrlap, mathclap - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, style)]); - - if (group.alignment === "rlap") { - if (group.body.body.length > 0 && group.body.body[0].type === "genfrac") { - // In Firefox, a squashes the 3/18em padding of a child \frac. Put it back. - node.setAttribute("lspace", "0.16667em"); - } - } else { - const offset = group.alignment === "llap" ? "-1" : "-0.5"; - node.setAttribute("lspace", offset + "width"); - } - node.setAttribute("width", "0px"); - return node - } -}); - -// Switching from text mode back to math mode -defineFunction({ - type: "ordgroup", - names: ["\\(", "$"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler({ funcName, parser }, args) { - const outerMode = parser.mode; - parser.switchMode("math"); - const close = funcName === "\\(" ? "\\)" : "$"; - const body = parser.parseExpression(false, close); - parser.expect(close); - parser.switchMode(outerMode); - return { - type: "ordgroup", - mode: parser.mode, - body - }; - } -}); - -// Check for extra closing math delimiters -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\)", "\\]"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler(context, token) { - throw new ParseError(`Mismatched ${context.funcName}`, token); - } -}); - -const chooseStyle = (group, style) => { - switch (style.level) { - case StyleLevel.DISPLAY: // 0 - return group.display; - case StyleLevel.TEXT: // 1 - return group.text; - case StyleLevel.SCRIPT: // 2 - return group.script; - case StyleLevel.SCRIPTSCRIPT: // 3 - return group.scriptscript; - default: - return group.text; - } -}; - -defineFunction({ - type: "mathchoice", - names: ["\\mathchoice"], - props: { - numArgs: 4, - primitive: true - }, - handler: ({ parser }, args) => { - return { - type: "mathchoice", - mode: parser.mode, - display: ordargument(args[0]), - text: ordargument(args[1]), - script: ordargument(args[2]), - scriptscript: ordargument(args[3]) - }; - }, - mathmlBuilder: (group, style) => { - const body = chooseStyle(group, style); - return buildExpressionRow(body, style); - } -}); - -const textAtomTypes = ["text", "textord", "mathord", "atom"]; - -function mathmlBuilder$3(group, style) { - let node; - const inner = buildExpression(group.body, style); - - if (group.mclass === "minner") { - node = new mathMLTree.MathNode("mpadded", inner); - } else if (group.mclass === "mord") { - if (group.isCharacterBox || inner[0].type === "mathord") { - node = inner[0]; - node.type = "mi"; - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - if (group.mustPromote) { - node = inner[0]; - node.type = "mo"; - if (group.isCharacterBox && group.body[0].text && /[A-Za-z]/.test(group.body[0].text)) { - node.setAttribute("mathvariant", "italic"); - } - } else { - node = new mathMLTree.MathNode("mo", inner); - } - - // Set spacing based on what is the most likely adjacent atom type. - // See TeXbook p170. - const doSpacing = style.level < 2; // Operator spacing is zero inside a (sub|super)script. - if (group.mclass === "mbin") { - // medium space - node.attributes.lspace = (doSpacing ? "0.2222em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2222em" : "0"); - } else if (group.mclass === "mrel") { - // thickspace - node.attributes.lspace = (doSpacing ? "0.2778em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2778em" : "0"); - } else if (group.mclass === "mpunct") { - node.attributes.lspace = "0em"; - node.attributes.rspace = (doSpacing ? "0.1667em" : "0"); - } else if (group.mclass === "mopen" || group.mclass === "mclose") { - node.attributes.lspace = "0em"; - node.attributes.rspace = "0em"; - } else if (group.mclass === "minner" && doSpacing) { - node.attributes.lspace = "0.0556em"; // 1 mu is the most likely option - node.attributes.width = "+0.1111em"; - } - if (!(group.mclass === "mopen" || group.mclass === "mclose")) { - delete node.attributes.stretchy; - delete node.attributes.form; - } - } - return node; -} - -// Math class commands except \mathop -defineFunction({ - type: "mclass", - names: [ - "\\mathord", - "\\mathbin", - "\\mathrel", - "\\mathopen", - "\\mathclose", - "\\mathpunct", - "\\mathinner" - ], - props: { - numArgs: 1, - primitive: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - const isCharacterBox = utils.isCharacterBox(body); - // We should not wrap a around a or . That would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - let mustPromote = true; - const mord = { type: "mathord", text: "", mode: parser.mode }; - const arr = (body.body) ? body.body : [body]; - for (const arg of arr) { - if (textAtomTypes.includes(arg.type)) { - if (arg.text) { - mord.text += arg.text; - } else if (arg.body) { - arg.body.map(e => { mord.text += e.text; }); - } - } else { - mustPromote = false; - break - } - } - return { - type: "mclass", - mode: parser.mode, - mclass: "m" + funcName.slice(5), - body: ordargument(mustPromote ? mord : body), - isCharacterBox, - mustPromote - }; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -const binrelClass = (arg) => { - // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. - // (by rendering separately and with {}s before and after, and measuring - // the change in spacing). We'll do roughly the same by detecting the - // atom type directly. - const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; - if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { - return "m" + atom.family; - } else { - return "mord"; - } -}; - -// \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. -// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. -defineFunction({ - type: "mclass", - names: ["\\@binrel"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "mclass", - mode: parser.mode, - mclass: binrelClass(args[0]), - body: ordargument(args[1]), - isCharacterBox: utils.isCharacterBox(args[1]) - }; - } -}); - -// Build a relation or stacked op by placing one symbol on top of another -defineFunction({ - type: "mclass", - names: ["\\stackrel", "\\overset", "\\underset"], - props: { - numArgs: 2 - }, - handler({ parser, funcName }, args) { - const baseArg = args[1]; - const shiftedArg = args[0]; - - const baseOp = { - type: "op", - mode: baseArg.mode, - limits: true, - alwaysHandleSupSub: true, - parentIsSupSub: false, - symbol: false, - stack: true, - suppressBaseShift: funcName !== "\\stackrel", - body: ordargument(baseArg) - }; - - return { - type: "supsub", - mode: shiftedArg.mode, - base: baseOp, - sup: funcName === "\\underset" ? null : shiftedArg, - sub: funcName === "\\underset" ? shiftedArg : null - }; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// Helper function -const buildGroup = (el, style, noneNode) => { - if (!el) { return noneNode } - const node = buildGroup$1(el, style); - if (node.type === "mrow" && node.children.length === 0) { return noneNode } - return node -}; - -defineFunction({ - type: "multiscript", - names: ["\\sideset", "\\pres@cript"], // See macros.js for \prescript - props: { - numArgs: 3 - }, - handler({ parser, funcName, token }, args) { - if (args[2].body.length === 0) { - throw new ParseError(funcName + `cannot parse an empty base.`) - } - const base = args[2].body[0]; - if (parser.settings.strict && funcName === "\\sideset" && !base.symbol) { - throw new ParseError(`The base of \\sideset must be a big operator. Try \\prescript.`) - } - - if ((args[0].body.length > 0 && args[0].body[0].type !== "supsub") || - (args[1].body.length > 0 && args[1].body[0].type !== "supsub")) { - throw new ParseError("\\sideset can parse only subscripts and " + - "superscripts in its first two arguments", token) - } - - // The prescripts and postscripts come wrapped in a supsub. - const prescripts = args[0].body.length > 0 ? args[0].body[0] : null; - const postscripts = args[1].body.length > 0 ? args[1].body[0] : null; - - if (!prescripts && !postscripts) { - return base - } else if (!prescripts) { - // It's not a multi-script. Get a \textstyle supsub. - return { - type: "styling", - mode: parser.mode, - scriptLevel: "text", - body: [{ - type: "supsub", - mode: parser.mode, - base, - sup: postscripts.sup, - sub: postscripts.sub - }] - } - } else { - return { - type: "multiscript", - mode: parser.mode, - isSideset: funcName === "\\sideset", - prescripts, - postscripts, - base - } - } - }, - mathmlBuilder(group, style) { - const base = buildGroup$1(group.base, style); - - const prescriptsNode = new mathMLTree.MathNode("mprescripts"); - const noneNode = new mathMLTree.MathNode("none"); - let children = []; - - const preSub = buildGroup(group.prescripts.sub, style, noneNode); - const preSup = buildGroup(group.prescripts.sup, style, noneNode); - if (group.isSideset) { - // This seems silly, but LaTeX does this. Firefox ignores it, which does not make me sad. - preSub.setAttribute("style", "text-align: left;"); - preSup.setAttribute("style", "text-align: left;"); - } - - if (group.postscripts) { - const postSub = buildGroup(group.postscripts.sub, style, noneNode); - const postSup = buildGroup(group.postscripts.sup, style, noneNode); - children = [base, postSub, postSup, prescriptsNode, preSub, preSup]; - } else { - children = [base, prescriptsNode, preSub, preSup]; - } - - return new mathMLTree.MathNode("mmultiscripts", children); - } -}); - -defineFunction({ - type: "not", - names: ["\\not"], - props: { - numArgs: 1, - primitive: true, - allowedInText: false - }, - handler({ parser }, args) { - const isCharacterBox = utils.isCharacterBox(args[0]); - let body; - if (isCharacterBox) { - body = ordargument(args[0]); - if (body[0].text.charAt(0) === "\\") { - body[0].text = symbols.math[body[0].text].replace; - } - // \u0338 is the Unicode Combining Long Solidus Overlay - body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1); - } else { - // When the argument is not a character box, TeX does an awkward, poorly placed overlay. - // We'll do the same. - const notNode = { type: "textord", mode: "math", text: "\u0338" }; - const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } }; - body = [notNode, kernNode, args[0]]; - } - return { - type: "not", - mode: parser.mode, - body, - isCharacterBox - }; - }, - mathmlBuilder(group, style) { - if (group.isCharacterBox) { - const inner = buildExpression(group.body, style); - return inner[0] - } else { - return buildExpressionRow(group.body, style, true) - } - } -}); - -// Limits, symbols - -// Some helpers - -const ordAtomTypes = ["textord", "mathord", "atom"]; - -// Most operators have a large successor symbol, but these don't. -const noSuccessor = ["\\smallint"]; - -// Math operators (e.g. \sin) need a space between these types and themselves: -const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"]; - -const dels = ["}", "\\left", "\\middle", "\\right"]; -const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)); - -// NOTE: Unlike most `builders`s, this one handles not only "op", but also -// "supsub" since some of them (like \int) can affect super/subscripting. - -const mathmlBuilder$2 = (group, style) => { - let node; - - if (group.symbol) { - // This is a symbol. Just add the symbol. - node = new MathNode("mo", [makeText(group.name, group.mode)]); - if (utils.contains(noSuccessor, group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - } else { - // This is a text operator. Add all of the characters from the operator's name. - node = new MathNode("mi", [new TextNode(group.name.slice(1))]); - - if (!group.parentIsSupSub) { - // Append an invisible . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new MathNode("mo", [makeText("\u2061", "text")]); - node = new MathNode("mpadded", [node, operator]); - const lSpace = group.needsLeadingSpace ? 0.1667 : 0; - const rSpace = group.isFollowedByDelimiter ? 0 : 0.1666; - if (group.needsLeadingSpace) { - node.setAttribute("lspace", "0.1667em"); // thin space. - } - if ((lSpace + rSpace) > 0) { - node.setAttribute("width", `+${lSpace + rSpace}em`); - } - } - } - - return node; -}; - -const singleCharBigOps = { - "\u220F": "\\prod", - "\u2210": "\\coprod", - "\u2211": "\\sum", - "\u22c0": "\\bigwedge", - "\u22c1": "\\bigvee", - "\u22c2": "\\bigcap", - "\u22c3": "\\bigcup", - "\u2a00": "\\bigodot", - "\u2a01": "\\bigoplus", - "\u2a02": "\\bigotimes", - "\u2a04": "\\biguplus", - "\u2a05": "\\bigsqcap", - "\u2a06": "\\bigsqcup" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\smallint", - "\u220F", - "\u2210", - "\u2211", - "\u22c0", - "\u22c1", - "\u22c2", - "\u22c3", - "\u2a00", - "\u2a01", - "\u2a02", - "\u2a04", - "\u2a06" - ], - props: { - numArgs: 0 - }, - handler: ({ parser, funcName }, args) => { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharBigOps[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: true, - stack: false, // This is true for \stackrel{}, not here. - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// Note: calling defineFunction with a type that's already been defined only -// works because the same mathmlBuilder is being used. -defineFunction({ - type: "op", - names: ["\\mathop"], - props: { - numArgs: 1, - primitive: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - // It would be convienient to just wrap a around the argument. - // But if the argument is a or , that would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - const arr = (body.body) ? body.body : [body]; - const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type); - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: isSymbol, - stack: false, - name: isSymbol ? arr[0].text : null, - body: isSymbol ? null : ordargument(body) - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// There are 2 flags for operators; whether they produce limits in -// displaystyle, and whether they are symbols and should grow in -// displaystyle. These four groups cover the four possible choices. - -const singleCharIntegrals = { - "\u222b": "\\int", - "\u222c": "\\iint", - "\u222d": "\\iiint", - "\u222e": "\\oint", - "\u222f": "\\oiint", - "\u2230": "\\oiiint", - "\u2231": "\\intclockwise", - "\u2232": "\\varointclockwise", - "\u2a0c": "\\iiiint", - "\u2a0d": "\\intbar", - "\u2a0e": "\\intBar", - "\u2a0f": "\\fint", - "\u2a12": "\\rppolint", - "\u2a13": "\\scpolint", - "\u2a15": "\\pointint", - "\u2a16": "\\sqint", - "\u2a17": "\\intlarhk", - "\u2a18": "\\intx", - "\u2a19": "\\intcap", - "\u2a1a": "\\intcup" -}; - -// No limits, not symbols -defineFunction({ - type: "op", - names: [ - "\\arcsin", - "\\arccos", - "\\arctan", - "\\arctg", - "\\arcctg", - "\\arg", - "\\ch", - "\\cos", - "\\cosec", - "\\cosh", - "\\cot", - "\\cotg", - "\\coth", - "\\csc", - "\\ctg", - "\\cth", - "\\deg", - "\\dim", - "\\exp", - "\\hom", - "\\ker", - "\\lg", - "\\ln", - "\\log", - "\\sec", - "\\sin", - "\\sinh", - "\\sh", - "\\sgn", - "\\tan", - "\\tanh", - "\\tg", - "\\th" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - const next = parser.gullet.future().text; - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// Limits, not symbols -defineFunction({ - type: "op", - names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - const next = parser.gullet.future().text; - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// No limits, symbols -defineFunction({ - type: "op", - names: [ - "\\int", - "\\iint", - "\\iiint", - "\\iiiint", - "\\oint", - "\\oiint", - "\\oiiint", - "\\intclockwise", - "\\varointclockwise", - "\\intbar", - "\\intBar", - "\\fint", - "\\rppolint", - "\\scpolint", - "\\pointint", - "\\sqint", - "\\intlarhk", - "\\intx", - "\\intcap", - "\\intcup", - "\u222b", - "\u222c", - "\u222d", - "\u222e", - "\u222f", - "\u2230", - "\u2231", - "\u2232", - "\u2a0c", - "\u2a0d", - "\u2a0e", - "\u2a0f", - "\u2a12", - "\u2a13", - "\u2a15", - "\u2a16", - "\u2a17", - "\u2a18", - "\u2a19", - "\u2a1a" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharIntegrals[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: true, - stack: false, - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -/** - * All registered global/built-in macros. - * `macros.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `macros.js`. - */ -const _macros = {}; - -// This function might one day accept an additional argument and do more things. -function defineMacro(name, body) { - _macros[name] = body; -} - -// NOTE: Unlike most builders, this one handles not only -// "operatorname", but also "supsub" since \operatorname* can -// affect super/subscripting. - -const mathmlBuilder$1 = (group, style) => { - let expression = buildExpression(group.body, style.withFont("mathrm")); - - // Is expression a string or has it something like a fraction? - let isAllString = true; // default - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - switch (node.type) { - case "mi": - case "mn": - case "ms": - case "mtext": - break; // Do nothing yet. - case "mspace": - { - if (node.attributes.width) { - const width = node.attributes.width.replace("em", ""); - const ch = spaceCharacter(Number(width)); - if (ch === "") { - isAllString = false; - } else { - expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)]); - } - } - } - break - case "mo": { - const child = node.children[0]; - if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { - child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); - } else { - isAllString = false; - } - break - } - default: - isAllString = false; - } - } else { - isAllString = false; - } - } - - if (isAllString) { - // Write a single TextNode instead of multiple nested tags. - const word = expression.map((node) => node.toText()).join(""); - expression = [new mathMLTree.TextNode(word)]; - } else if ( - expression.length === 1 - && utils.contains(["mover", "munder"], expression[0].type) && - (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext") - ) { - expression[0].children[0].type = "mi"; - if (group.parentIsSupSub) { - return new mathMLTree.MathNode("mrow", expression) - } else { - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - return mathMLTree.newDocumentFragment([expression[0], operator]) - } - } - - let wrapper; - if (isAllString) { - wrapper = new mathMLTree.MathNode("mi", expression); - wrapper.setAttribute("mathvariant", "normal"); - } else { - wrapper = new mathMLTree.MathNode("mrow", expression); - } - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (group.needsLeadingSpace) { - // LaTeX gives operator spacing, but a gets ord spacing. - // So add a leading space. - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - return mathMLTree.newDocumentFragment([space, wrapper, operator]) - } else { - return mathMLTree.newDocumentFragment([wrapper, operator]) - } - } - - return wrapper -}; - -// \operatorname -// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ -defineFunction({ - type: "operatorname", - names: ["\\operatorname@", "\\operatornamewithlimits"], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = args[0]; - const prevAtomType = parser.prevAtomType; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, true); - } -}); - -defineFunction({ - type: "overline", - names: ["\\overline"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - const body = args[0]; - return { - type: "overline", - mode: parser.mode, - body - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005F")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode( - "mover", - [buildGroup$1(group.body, style), operator] - ); - node.setAttribute("accent", "true"); - - return node; - } -}); - -defineFunction({ - type: "phantom", - names: ["\\phantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "phantom", - mode: parser.mode, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(group.body, style); - return new mathMLTree.MathNode("mphantom", inner); - } -}); - -defineFunction({ - type: "hphantom", - names: ["\\hphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "hphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("height", "0px"); - node.setAttribute("depth", "0px"); - return node; - } -}); - -defineFunction({ - type: "vphantom", - names: ["\\vphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "vphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("width", "0px"); - return node; - } -}); - -// \pmb is a simulation of bold font. -// The version of \pmb in ambsy.sty works by typesetting three copies of the argument -// with small offsets. We use CSS text-shadow. -// It's a hack. Not as good as a real bold font. Better than nothing. - -defineFunction({ - type: "pmb", - names: ["\\pmb"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "pmb", - mode: parser.mode, - body: ordargument(args[0]) - } - }, - mathmlBuilder(group, style) { - const inner = buildExpression(group.body, style); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px"); - return node - } -}); - -const sign = num => num >= 0 ? "+" : "-"; - -// \raise, \lower, and \raisebox - -const mathmlBuilder = (group, style) => { - const newStyle = style.withLevel(StyleLevel.TEXT); - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, newStyle)]); - const dy = calculateSize(group.dy, style); - node.setAttribute("voffset", dy.number + dy.unit); - const dyAbs = Math.abs(dy.number); - node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit); - node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit); - return node -}; - -defineFunction({ - type: "raise", - names: ["\\raise", "\\lower"], - props: { - numArgs: 2, - argTypes: ["size", "primitive"], - primitive: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - if (funcName === "\\lower") { amount.number *= -1; } - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder -}); - - -defineFunction({ - type: "raise", - names: ["\\raisebox"], - props: { - numArgs: 2, - argTypes: ["size", "hbox"], - allowedInText: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "ref", - names: ["\\ref", "\\eqref"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser, funcName }, args) { - return { - type: "ref", - mode: parser.mode, - funcName, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Create an empty text node. Set a class and an href. - // The post-processor will populate with the target's tag or equation number. - const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"]; - const node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("")], classes); - node.setAttribute("href", "#" + group.string); - return node - } -}); - -defineFunction({ - type: "internal", - names: ["\\relax"], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser }) { - return { - type: "internal", - mode: parser.mode - }; - } -}); - -defineFunction({ - type: "rule", - names: ["\\rule"], - props: { - numArgs: 2, - numOptionalArgs: 1, - argTypes: ["size", "size", "size"] - }, - handler({ parser }, args, optArgs) { - const shift = optArgs[0]; - const width = assertNodeType(args[0], "size"); - const height = assertNodeType(args[1], "size"); - return { - type: "rule", - mode: parser.mode, - shift: shift && assertNodeType(shift, "size").value, - width: width.value, - height: height.value - }; - }, - mathmlBuilder(group, style) { - const width = calculateSize(group.width, style); - const height = calculateSize(group.height, style); - const shift = group.shift - ? calculateSize(group.shift, style) - : { number: 0, unit: "em" }; - const color = (style.color && style.getColor()) || "black"; - - const rule = new mathMLTree.MathNode("mspace"); - if (width.number > 0 && height.number > 0) { - rule.setAttribute("mathbackground", color); - } - rule.setAttribute("width", width.number + width.unit); - rule.setAttribute("height", height.number + height.unit); - if (shift.number === 0) { return rule } - - const wrapper = new mathMLTree.MathNode("mpadded", [rule]); - if (shift.number >= 0) { - wrapper.setAttribute("height", "+" + shift.number + shift.unit); - } else { - wrapper.setAttribute("height", shift.number + shift.unit); - wrapper.setAttribute("depth", "+" + -shift.number + shift.unit); - } - wrapper.setAttribute("voffset", shift.number + shift.unit); - return wrapper; - } -}); - -// The size mappings are taken from TeX with \normalsize=10pt. -// We don't have to track script level. MathML does that. -const sizeMap = { - "\\tiny": 0.5, - "\\sixptsize": 0.6, - "\\Tiny": 0.6, - "\\scriptsize": 0.7, - "\\footnotesize": 0.8, - "\\small": 0.9, - "\\normalsize": 1.0, - "\\large": 1.2, - "\\Large": 1.44, - "\\LARGE": 1.728, - "\\huge": 2.074, - "\\Huge": 2.488 -}; - -defineFunction({ - type: "sizing", - names: [ - "\\tiny", - "\\sixptsize", - "\\Tiny", - "\\scriptsize", - "\\footnotesize", - "\\small", - "\\normalsize", - "\\large", - "\\Large", - "\\LARGE", - "\\huge", - "\\Huge" - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ breakOnTokenText, funcName, parser }, args) => { - if (parser.settings.strict && parser.mode === "math") { - // eslint-disable-next-line no-console - console.log(`Temml strict-mode warning: Command ${funcName} is invalid in math mode.`); - } - const body = parser.parseExpression(false, breakOnTokenText); - return { - type: "sizing", - mode: parser.mode, - funcName, - body - }; - }, - mathmlBuilder: (group, style) => { - const newStyle = style.withFontSize(sizeMap[group.funcName]); - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - const factor = (sizeMap[group.funcName] / style.fontSize).toFixed(4); - node.setAttribute("mathsize", factor + "em"); - return node; - } -}); - -// smash, with optional [tb], as in AMS - -defineFunction({ - type: "smash", - names: ["\\smash"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args, optArgs) => { - let smashHeight = false; - let smashDepth = false; - const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); - if (tbArg) { - // Optional [tb] argument is engaged. - // ref: amsmath: \renewcommand{\smash}[1][tb]{% - // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% - let letter = ""; - for (let i = 0; i < tbArg.body.length; ++i) { - const node = tbArg.body[i]; - // TODO: Write an AssertSymbolNode - letter = node.text; - if (letter === "t") { - smashHeight = true; - } else if (letter === "b") { - smashDepth = true; - } else { - smashHeight = false; - smashDepth = false; - break; - } - } - } else { - smashHeight = true; - smashDepth = true; - } - - const body = args[0]; - return { - type: "smash", - mode: parser.mode, - body, - smashHeight, - smashDepth - }; - }, - mathmlBuilder: (group, style) => { - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, style)]); - - if (group.smashHeight) { - node.setAttribute("height", "0px"); - } - - if (group.smashDepth) { - node.setAttribute("depth", "0px"); - } - - return node; - } -}); - -defineFunction({ - type: "sqrt", - names: ["\\sqrt"], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser }, args, optArgs) { - const index = optArgs[0]; - const body = args[0]; - return { - type: "sqrt", - mode: parser.mode, - body, - index - }; - }, - mathmlBuilder(group, style) { - const { body, index } = group; - return index - ? new mathMLTree.MathNode("mroot", [ - buildGroup$1(body, style), - buildGroup$1(index, style.incrementLevel()) - ]) - : new mathMLTree.MathNode("msqrt", [buildGroup$1(body, style)]); - } -}); - -const styleMap = { - display: 0, - text: 1, - script: 2, - scriptscript: 3 -}; - -const styleAttributes = { - display: ["0", "true"], - text: ["0", "false"], - script: ["1", "false"], - scriptscript: ["2", "false"] -}; - -defineFunction({ - type: "styling", - names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ breakOnTokenText, funcName, parser }, args) { - // parse out the implicit body - const body = parser.parseExpression(true, breakOnTokenText); - - const scriptLevel = funcName.slice(1, funcName.length - 5); - return { - type: "styling", - mode: parser.mode, - // Figure out what scriptLevel to use by pulling out the scriptLevel from - // the function name - scriptLevel, - body - }; - }, - mathmlBuilder(group, style) { - // Figure out what scriptLevel we're changing to. - const newStyle = style.withLevel(styleMap[group.scriptLevel]); - // The style argument in the next line does NOT directly set a MathML script level. - // It just tracks the style level, in case we need to know it for supsub or mathchoice. - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - - const attr = styleAttributes[group.scriptLevel]; - - // Here is where we set the MathML script level. - node.setAttribute("scriptlevel", attr[0]); - node.setAttribute("displaystyle", attr[1]); - - return node; - } -}); - -/** - * Sometimes, groups perform special rules when they have superscripts or - * subscripts attached to them. This function lets the `supsub` group know that - * Sometimes, groups perform special rules when they have superscripts or - * its inner element should handle the superscripts and subscripts instead of - * handling them itself. - */ - -// Helpers -const symbolRegEx = /^m(over|under|underover)$/; - -// Super scripts and subscripts, whose precise placement can depend on other -// functions that precede them. -defineFunctionBuilders({ - type: "supsub", - mathmlBuilder(group, style) { - // Is the inner group a relevant horizonal brace? - let isBrace = false; - let isOver; - let isSup; - let appendApplyFunction = false; - let needsLeadingSpace = false; - - if (group.base && group.base.type === "horizBrace") { - isSup = !!group.sup; - if (isSup === group.base.isOver) { - isBrace = true; - isOver = group.base.isOver; - } - } - - if (group.base && !group.base.stack && - (group.base.type === "op" || group.base.type === "operatorname")) { - group.base.parentIsSupSub = true; - appendApplyFunction = !group.base.symbol; - needsLeadingSpace = group.base.needsLeadingSpace; - } - - const children = group.base && group.base.stack - ? [buildGroup$1(group.base.body[0], style)] - : [buildGroup$1(group.base, style)]; - - const childStyle = style.inSubOrSup(); - if (group.sub) { - children.push(buildGroup$1(group.sub, childStyle)); - } - - if (group.sup) { - children.push(buildGroup$1(group.sup, childStyle)); - } - - let nodeType; - if (isBrace) { - nodeType = isOver ? "mover" : "munder"; - } else if (!group.sub) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "mover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "mover"; - } else { - nodeType = "msup"; - } - } else if (!group.sup) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munder"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "munder"; - } else { - nodeType = "msub"; - } - } else { - const base = group.base; - if (base && ((base.type === "op" && base.limits) || base.type === "multiscript") && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munderover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (style.level === StyleLevel.DISPLAY || base.limits) - ) { - nodeType = "munderover"; - } else { - nodeType = "msubsup"; - } - } - - let node = new mathMLTree.MathNode(nodeType, children); - if (appendApplyFunction) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (needsLeadingSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node = mathMLTree.newDocumentFragment([space, node, operator]); - } else { - node = mathMLTree.newDocumentFragment([node, operator]); - } - } else if (symbolRegEx.test(nodeType)) { - // Wrap in a . Otherwise Firefox stretchy parens will not stretch to include limits. - node = new mathMLTree.MathNode("mrow", [node]); - } - - return node - } -}); - -// Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js. - -const short = ["\\shortmid", "\\nshortmid", "\\shortparallel", - "\\nshortparallel", "\\smallsetminus"]; - -defineFunctionBuilders({ - type: "atom", - mathmlBuilder(group, style) { - const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]); - if (group.family === "punct") { - node.setAttribute("separator", "true"); - } else if (group.family === "open" || group.family === "close") { - // Delims built here should not stretch vertically. - // See delimsizing.js for stretchy delims. - if (group.family === "open") { - node.setAttribute("form", "prefix"); - // Set an explicit attribute for stretch. Otherwise Firefox may do it wrong. - node.setAttribute("stretchy", "false"); - } else if (group.family === "close") { - node.setAttribute("form", "postfix"); - node.setAttribute("stretchy", "false"); - } - } else if (group.text === "\\mid") { - // Firefox messes up this spacing if at the end of an . See it explicitly. - node.setAttribute("lspace", "0.22em"); // medium space - node.setAttribute("rspace", "0.22em"); - node.setAttribute("stretchy", "false"); - } else if (short.includes(group.text)) { - node.setAttribute("mathsize", "70%"); - } else if (group.text === ":") { - // ":" is not in the MathML operator dictionary. Give it BIN spacing. - node.attributes.lspace = "0.2222em"; - node.attributes.rspace = "0.2222em"; - } - return node; - } -}); - -/** - * Maps TeX font commands to "mathvariant" attribute in buildMathML.js - */ -const fontMap = { - // styles - mathbf: "bold", - mathrm: "normal", - textit: "italic", - mathit: "italic", - mathnormal: "italic", - - // families - mathbb: "double-struck", - mathcal: "script", - mathfrak: "fraktur", - mathscr: "script", - mathsf: "sans-serif", - mathtt: "monospace", - oldstylenums: "oldstylenums" -}; - -/** - * Returns the math variant as a string or null if none is required. - */ -const getVariant = function(group, style) { - // Handle font specifiers as best we can. - // Chromium does not support the MathML mathvariant attribute. - // So we'll use Unicode replacement characters instead. - // But first, determine the math variant. - - // Deal with the \textit, \textbf, etc., functions. - if (style.fontFamily === "texttt") { - return "monospace" - } else if (style.fontFamily === "textsc") { - return "normal"; // handled via character substitution in symbolsOrd.js. - } else if (style.fontFamily === "textsf") { - if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "sans-serif-bold-italic" - } else if (style.fontShape === "textit") { - return "sans-serif-italic" - } else if (style.fontWeight === "textbf") { - return "sans-serif-bold" - } else { - return "sans-serif" - } - } else if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "bold-italic" - } else if (style.fontShape === "textit") { - return "italic" - } else if (style.fontWeight === "textbf") { - return "bold" - } - - // Deal with the \mathit, mathbf, etc, functions. - const font = style.font; - if (!font || font === "mathnormal") { - return null - } - - const mode = group.mode; - switch (font) { - case "mathit": - return "italic" - case "mathrm": { - const codePoint = group.text.codePointAt(0); - // LaTeX \mathrm returns italic for Greek characters. - return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal" - } - case "greekItalic": - return "italic" - case "up@greek": - return "normal" - case "boldsymbol": - case "mathboldsymbol": - return "bold-italic" - case "mathbf": - return "bold" - case "mathbb": - return "double-struck" - case "mathfrak": - return "fraktur" - case "mathscr": - case "mathcal": - return "script" - case "mathsf": - return "sans-serif" - case "mathtt": - return "monospace" - case "oldstylenums": - return "oldstylenums" - } - - let text = group.text; - if (symbols[mode][text] && symbols[mode][text].replace) { - text = symbols[mode][text].replace; - } - - return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null -}; - -// Chromium does not support the MathML `mathvariant` attribute. -// Instead, we replace ASCII characters with Unicode characters that -// are defined in the font as bold, italic, double-struck, etc. -// This module identifies those Unicode code points. - -// First, a few helpers. -const script = Object.freeze({ - B: 0x20EA, // Offset from ASCII B to Unicode script B - E: 0x20EB, - F: 0x20EB, - H: 0x20C3, - I: 0x20C7, - L: 0x20C6, - M: 0x20E6, - R: 0x20C9, - e: 0x20CA, - g: 0x20A3, - o: 0x20C5 -}); - -const frak = Object.freeze({ - C: 0x20EA, - H: 0x20C4, - I: 0x20C8, - R: 0x20CA, - Z: 0x20CE -}); - -const bbb = Object.freeze({ - C: 0x20BF, // blackboard bold - H: 0x20C5, - N: 0x20C7, - P: 0x20C9, - Q: 0x20C9, - R: 0x20CB, - Z: 0x20CA -}); - -const bold = Object.freeze({ - "\u03f5": 0x1D2E7, // lunate epsilon - "\u03d1": 0x1D30C, // vartheta - "\u03f0": 0x1D2EE, // varkappa - "\u03c6": 0x1D319, // varphi - "\u03f1": 0x1D2EF, // varrho - "\u03d6": 0x1D30B // varpi -}); - -const boldItalic = Object.freeze({ - "\u03f5": 0x1D35B, // lunate epsilon - "\u03d1": 0x1D380, // vartheta - "\u03f0": 0x1D362, // varkappa - "\u03c6": 0x1D38D, // varphi - "\u03f1": 0x1D363, // varrho - "\u03d6": 0x1D37F // varpi -}); - -const boldsf = Object.freeze({ - "\u03f5": 0x1D395, // lunate epsilon - "\u03d1": 0x1D3BA, // vartheta - "\u03f0": 0x1D39C, // varkappa - "\u03c6": 0x1D3C7, // varphi - "\u03f1": 0x1D39D, // varrho - "\u03d6": 0x1D3B9 // varpi -}); - -const bisf = Object.freeze({ - "\u03f5": 0x1D3CF, // lunate epsilon - "\u03d1": 0x1D3F4, // vartheta - "\u03f0": 0x1D3D6, // varkappa - "\u03c6": 0x1D401, // varphi - "\u03f1": 0x1D3D7, // varrho - "\u03d6": 0x1D3F3 // varpi -}); - -// Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf -const offset = Object.freeze({ - upperCaseLatin: { // A-Z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3BF }, - "italic": ch => { return 0x1D3F3 }, - "bold-italic": ch => { return 0x1D427 }, - "script": ch => { return script[ch] || 0x1D45B }, - "script-bold": ch => { return 0x1D48F }, - "fraktur": ch => { return frak[ch] || 0x1D4C3 }, - "fraktur-bold": ch => { return 0x1D52B }, - "double-struck": ch => { return bbb[ch] || 0x1D4F7 }, - "sans-serif": ch => { return 0x1D55F }, - "sans-serif-bold": ch => { return 0x1D593 }, - "sans-serif-italic": ch => { return 0x1D5C7 }, - "sans-serif-bold-italic": ch => { return 0x1D63C }, - "monospace": ch => { return 0x1D62F } - }, - lowerCaseLatin: { // a-z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3B9 }, - "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED }, - "bold-italic": ch => { return 0x1D421 }, - "script": ch => { return script[ch] || 0x1D455 }, - "script-bold": ch => { return 0x1D489 }, - "fraktur": ch => { return 0x1D4BD }, - "fraktur-bold": ch => { return 0x1D525 }, - "double-struck": ch => { return 0x1D4F1 }, - "sans-serif": ch => { return 0x1D559 }, - "sans-serif-bold": ch => { return 0x1D58D }, - "sans-serif-italic": ch => { return 0x1D5C1 }, - "sans-serif-bold-italic": ch => { return 0x1D5F5 }, - "monospace": ch => { return 0x1D629 } - }, - upperCaseGreek: { // A-Ω ∇ - "normal": ch => { return 0 }, - "bold": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "italic": ch => { return ch === "∇" ? 0x1B4F4 : 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-bold": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return ch === "∇" ? 0x1B5A2 : 0x1D3FF }, - "monospace": ch => { return 0 } - }, - lowerCaseGreek: { // α-ω - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D311 }, - "italic": ch => { return 0x1D34B }, - "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return 0x1D3BF }, - "sans-serif-bold": ch => { return 0x1D3BF }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0x1D3F9 }, - "monospace": ch => { return 0 } - }, - varGreek: { // \varGamma, etc - "normal": ch => { return 0 }, - "bold": ch => { return bold[ch] || -51 }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return boldItalic[ch] || 0x3A }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - "sans-serif": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-bold": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE }, - "monospace": ch => { return 0 } - }, - numeral: { // 0-9 - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D79E }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return 0 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0x1D7A8 }, - "sans-serif": ch => { return 0x1D7B2 }, - "sans-serif-bold": ch => { return 0x1D7BC }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0 }, - "monospace": ch => { return 0x1D7C6 } - } -}); - -const variantChar = (ch, variant) => { - const codePoint = ch.codePointAt(0); - const block = 0x40 < codePoint && codePoint < 0x5b - ? "upperCaseLatin" - : 0x60 < codePoint && codePoint < 0x7b - ? "lowerCaseLatin" - : (0x390 < codePoint && codePoint < 0x3AA) || ch === "∇" - ? "upperCaseGreek" - : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5" - ? "lowerCaseGreek" - : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch] - ? "varGreek" - : (0x2F < codePoint && codePoint < 0x3A) - ? "numeral" - : "other"; - return block === "other" - ? ch - : String.fromCodePoint(codePoint + offset[block][variant](ch)) -}; - -const smallCaps = Object.freeze({ - a: "ᴀ", - b: "ʙ", - c: "ᴄ", - d: "ᴅ", - e: "ᴇ", - f: "ꜰ", - g: "ɢ", - h: "ʜ", - i: "ɪ", - j: "ᴊ", - k: "ᴋ", - l: "ʟ", - m: "ᴍ", - n: "ɴ", - o: "ᴏ", - p: "ᴘ", - q: "ǫ", - r: "ʀ", - s: "s", - t: "ᴛ", - u: "ᴜ", - v: "ᴠ", - w: "ᴡ", - x: "x", - y: "ʏ", - z: "ᴢ" -}); - -// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in -// src/symbols.js. - -const numberRegEx$1 = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in Parser.js - -const latinRegEx = /[A-Ba-z]/; - -const italicNumber = (text, variant) => { - const mn = new mathMLTree.MathNode("mn", [text]); - const wrapper = new mathMLTree.MathNode("mstyle", [mn]); - wrapper.style["font-style"] = "italic"; - wrapper.style["font-family"] = "Cambria, 'Times New Roman', serif"; - if (variant === "bold-italic") { wrapper.style["font-weight"] = "bold"; } - return wrapper -}; - -defineFunctionBuilders({ - type: "mathord", - mathmlBuilder(group, style) { - const text = makeText(group.text, group.mode, style); - const codePoint = text.text.codePointAt(0); - // Test for upper-case Greek - const defaultVariant = (0x0390 < codePoint && codePoint < 0x03aa) ? "normal" : "italic"; - const variant = getVariant(group, style) || defaultVariant; - if (variant === "script") { - text.text = variantChar(text.text, variant); - return new mathMLTree.MathNode("mi", [text], [style.font]) - } else if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - let node = new mathMLTree.MathNode("mi", [text]); - // TODO: Handle U+1D49C - U+1D4CF per https://www.unicode.org/charts/PDF/U1D400.pdf - if (variant === "normal") { - node.setAttribute("mathvariant", "normal"); - if (text.text.length === 1) { - // A Firefox bug will apply spacing here, but there should be none. Fix it. - node = new mathMLTree.MathNode("mpadded", [node]); - node.setAttribute("lspace", "0"); - node.setAttribute("width", "+0em"); - } - } - return node - } -}); - -defineFunctionBuilders({ - type: "textord", - mathmlBuilder(group, style) { - let ch = group.text; - const codePoint = ch.codePointAt(0); - if (style.fontFamily === "textsc") { - // Convert small latin letters to small caps. - if (96 < codePoint && codePoint < 123) { - ch = smallCaps[ch]; - } - } - const text = makeText(ch, group.mode, style); - const variant = getVariant(group, style) || "normal"; - - let node; - if (group.mode === "text") { - if (variant === "italic" || variant === "bold-italic") { - if (numberRegEx$1.test(group.text)) { - return italicNumber(text, variant) - } - } - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (numberRegEx$1.test(group.text)) { - if (variant === "oldstylenums") { - const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]); - node = new mathMLTree.MathNode("mn", [ms]); - } else if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode("mn", [text]); - } - } else if (group.text === "\\prime") { - node = new mathMLTree.MathNode("mo", [text]); - } else { - const origText = text.text; - if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mi", [text]); - if (text.text === origText && latinRegEx.test(origText)) { - node.setAttribute("mathvariant", "italic"); - } - } - return node - } -}); - -// A map of CSS-based spacing functions to their CSS class. -const cssSpace = { - "\\nobreak": "nobreak", - "\\allowbreak": "allowbreak" -}; - -// A lookup table to determine whether a spacing function/symbol should be -// treated like a regular space character. If a symbol or command is a key -// in this table, then it should be a regular space character. Furthermore, -// the associated value may have a `className` specifying an extra CSS class -// to add to the created `span`. -const regularSpace = { - " ": {}, - "\\ ": {}, - "~": { - className: "nobreak" - }, - "\\space": {}, - "\\nobreakspace": { - className: "nobreak" - } -}; - -// ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in -// src/symbols.js. -defineFunctionBuilders({ - type: "spacing", - mathmlBuilder(group, style) { - let node; - - if (Object.prototype.hasOwnProperty.call(regularSpace, group.text)) { - // Firefox does not render a space in a . So write a no-break space. - // TODO: If Firefox fixes that bug, uncomment the next line and write ch into the node. - //const ch = (regularSpace[group.text].className === "nobreak") ? "\u00a0" : " " - node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]); - } else if (Object.prototype.hasOwnProperty.call(cssSpace, group.text)) { - // MathML 3.0 calls for nobreak to occur in an , not an - // Ref: https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs - node = new mathMLTree.MathNode("mo"); - if (group.text === "\\nobreak") { - node.setAttribute("linebreak", "nobreak"); - } - } else { - throw new ParseError(`Unknown type of space "${group.text}"`) - } - - return node - } -}); - -defineFunctionBuilders({ - type: "tag" -}); - -// For a \tag, the work usually done in a mathmlBuilder is instead done in buildMathML.js. -// That way, a \tag can be pulled out of the parse tree and wrapped around the outer node. - -// Non-mathy text, possibly in a font -const textFontFamilies = { - "\\text": undefined, - "\\textrm": "textrm", - "\\textsf": "textsf", - "\\texttt": "texttt", - "\\textnormal": "textrm", - "\\textsc": "textsc" // small caps -}; - -const textFontWeights = { - "\\textbf": "textbf", - "\\textmd": "textmd" -}; - -const textFontShapes = { - "\\textit": "textit", - "\\textup": "textup" -}; - -const styleWithFont = (group, style) => { - const font = group.font; - // Checks if the argument is a font family or a font style. - if (!font) { - return style; - } else if (textFontFamilies[font]) { - return style.withTextFontFamily(textFontFamilies[font]); - } else if (textFontWeights[font]) { - return style.withTextFontWeight(textFontWeights[font]); - } else { - return style.withTextFontShape(textFontShapes[font]); - } -}; - -defineFunction({ - type: "text", - names: [ - // Font families - "\\text", - "\\textrm", - "\\textsf", - "\\texttt", - "\\textnormal", - "\\textsc", - // Font weights - "\\textbf", - "\\textmd", - // Font Shapes - "\\textit", - "\\textup" - ], - props: { - numArgs: 1, - argTypes: ["text"], - allowedInArgument: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "text", - mode: parser.mode, - body: ordargument(body), - font: funcName - }; - }, - mathmlBuilder(group, style) { - const newStyle = styleWithFont(group, style); - const mrow = buildExpressionRow(group.body, newStyle); - return utils.consolidateText(mrow) - } -}); - -// Two functions included to enable migration from Mathjax. - -defineFunction({ - type: "tip", - names: ["\\mathtip"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup$1(group.body, style); - const tip = buildGroup$1(group.tip, style); - // Browsers don't support the tooltip actiontype. - // TODO: Come back and fix \mathtip when it can be done via CSS w/o a JS event. - const node = new mathMLTree.MathNode("maction", [math, tip], ["tml-tip"]); - node.setAttribute("actiontype", "tooltip"); - return node - } -}); - -defineFunction({ - type: "tip", - names: ["\\texttip"], - props: { - numArgs: 2, - argTypes: ["math", "text"] - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup$1(group.body, style); - const tip = buildGroup$1(group.tip, style); - // args[1] only accepted text, so tip is a element or a of them. - let str = ""; - if (tip.type === "mtext") { - str = tip.children[0].text; - } else { - for (const child of tip.children) { - str += child.children[0].text; - } - } - // Implement \texttip via a title attribute. - math.setAttribute("title", str); - return math - } -}); - -defineFunctionBuilders({ - type: "toggle", - mathmlBuilder(group, style) { - const expression = buildExpression(group.body, style); - const node = new mathMLTree.MathNode("maction", expression, [], { cursor: "default" }); - node.setAttribute("actiontype", "toggle"); - return node - } -}); - -defineFunction({ - type: "underline", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "underline", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005f")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode("munder", - [buildGroup$1(group.body, style), operator] - ); - node.setAttribute("accentunder", "true"); - - return node; - } -}); - -defineFunction({ - type: "verb", - names: ["\\verb"], - props: { - numArgs: 0, - allowedInText: true - }, - handler(context, args, optArgs) { - // \verb and \verb* are dealt with directly in Parser.js. - // If we end up here, it's because of a failure to match the two delimiters - // in the regex in Lexer.js. LaTeX raises the following error when \verb is - // terminated by end of line (or file). - throw new ParseError("\\verb ended by end of line instead of matching delimiter"); - }, - mathmlBuilder(group, style) { - const text = new mathMLTree.TextNode(makeVerb(group)); - const node = new mathMLTree.MathNode("mtext", [text]); - node.setAttribute("mathvariant", "monospace"); - return node; - } -}); - -/** - * Converts verb group into body string. - * - * \verb* replaces each space with an open box \u2423 - * \verb replaces each space with a no-break space \xA0 - */ -const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0"); - -/** Include this to ensure that all functions are defined. */ - -const functions = _functions; - -/** - * Lexing or parsing positional information for error reporting. - * This object is immutable. - */ -class SourceLocation { - constructor(lexer, start, end) { - this.lexer = lexer; // Lexer holding the input string. - this.start = start; // Start offset, zero-based inclusive. - this.end = end; // End offset, zero-based exclusive. - } - - /** - * Merges two `SourceLocation`s from location providers, given they are - * provided in order of appearance. - * - Returns the first one's location if only the first is provided. - * - Returns a merged range of the first and the last if both are provided - * and their lexers match. - * - Otherwise, returns null. - */ - static range(first, second) { - if (!second) { - return first && first.loc; - } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { - return null; - } else { - return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); - } - } -} - -/** - * Interface required to break circular dependency between Token, Lexer, and - * ParseError. - */ - -/** - * The resulting token returned from `lex`. - * - * It consists of the token text plus some position information. - * The position information is essentially a range in an input string, - * but instead of referencing the bare input string, we refer to the lexer. - * That way it is possible to attach extra metadata to the input string, - * like for example a file name or similar. - * - * The position information is optional, so it is OK to construct synthetic - * tokens if appropriate. Not providing available position information may - * lead to degraded error reporting, though. - */ -class Token { - constructor( - text, // the text of this token - loc - ) { - this.text = text; - this.loc = loc; - } - - /** - * Given a pair of tokens (this and endToken), compute a `Token` encompassing - * the whole input range enclosed by these two. - */ - range( - endToken, // last token of the range, inclusive - text // the text of the newly constructed token - ) { - return new Token(text, SourceLocation.range(this, endToken)); - } -} - -/** - * The Lexer class handles tokenizing the input in various ways. Since our - * parser expects us to be able to backtrack, the lexer allows lexing from any - * given starting point. - * - * Its main exposed function is the `lex` function, which takes a position to - * lex from and a type of token to lex. It defers to the appropriate `_innerLex` - * function. - * - * The various `_innerLex` functions perform the actual lexing of different - * kinds. - */ - -/* The following tokenRegex - * - matches typical whitespace (but not NBSP etc.) using its first two groups - * - does not match any control character \x00-\x1f except whitespace - * - does not match a bare backslash - * - matches any ASCII character except those just mentioned - * - does not match the BMP private use area \uE000-\uF8FF - * - does not match bare surrogate code units - * - matches any BMP character except for those just described - * - matches any valid Unicode surrogate pair - * - mathches numerals - * - matches a backslash followed by one or more whitespace characters - * - matches a backslash followed by one or more letters then whitespace - * - matches a backslash followed by any BMP character - * Capturing groups: - * [1] regular whitespace - * [2] backslash followed by whitespace - * [3] anything else, which may include: - * [4] left character of \verb* - * [5] left character of \verb - * [6] backslash followed by word, excluding any trailing whitespace - * Just because the Lexer matches something doesn't mean it's valid input: - * If there is no matching function or symbol definition, the Parser will - * still reject the input. - */ -const spaceRegexString = "[ \r\n\t]"; -const controlWordRegexString = "\\\\[a-zA-Z@]+"; -const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; -const controlWordWhitespaceRegexString = `(${controlWordRegexString})${spaceRegexString}*`; -const controlSpaceRegexString = "\\\\(\n|[ \r\t]+\n?)[ \r\t]*"; -const combiningDiacriticalMarkString = "[\u0300-\u036f]"; -const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); -const tokenRegexString = - `(${spaceRegexString}+)|` + // whitespace - `${controlSpaceRegexString}|` + // whitespace - "(number" + // numbers (in non-strict mode) - "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|\\\\verb\\*([^]).*?\\4" + // \verb* - "|\\\\verb([^*a-zA-Z]).*?\\5" + // \verb unstarred - `|${controlWordWhitespaceRegexString}` + // \macroName + spaces - `|${controlSymbolRegexString})`; // \\, \', etc. - -/** Main Lexer class */ -class Lexer { - constructor(input, settings) { - // Separate accents from characters - this.input = input; - this.settings = settings; - this.tokenRegex = new RegExp( - // Strict Temml, like TeX, lexes one numeral at a time. - // Default Temml lexes contiguous numerals into a single element. - tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"), - "g" - ); - // Category codes. The lexer only supports comment characters (14) for now. - // MacroExpander additionally distinguishes active (13). - this.catcodes = { - "%": 14, // comment character - "~": 13 // active character - }; - } - - setCatcode(char, code) { - this.catcodes[char] = code; - } - - /** - * This function lexes a single token. - */ - lex() { - const input = this.input; - const pos = this.tokenRegex.lastIndex; - if (pos === input.length) { - return new Token("EOF", new SourceLocation(this, pos, pos)); - } - const match = this.tokenRegex.exec(input); - if (match === null || match.index !== pos) { - throw new ParseError( - `Unexpected character: '${input[pos]}'`, - new Token(input[pos], new SourceLocation(this, pos, pos + 1)) - ); - } - const text = match[6] || match[3] || (match[2] ? "\\ " : " "); - - if (this.catcodes[text] === 14) { - // comment character - const nlIndex = input.indexOf("\n", this.tokenRegex.lastIndex); - if (nlIndex === -1) { - this.tokenRegex.lastIndex = input.length; // EOF - if (this.settings.strict) { - throw new ParseError("% comment has no terminating newline; LaTeX would " + - "fail because of commenting the end of math mode") - } - } else { - this.tokenRegex.lastIndex = nlIndex + 1; - } - return this.lex(); - } - - return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); - } -} - -/** - * A `Namespace` refers to a space of nameable things like macros or lengths, - * which can be `set` either globally or local to a nested group, using an - * undo stack similar to how TeX implements this functionality. - * Performance-wise, `get` and `set` take constant time. - */ - -class Namespace { - /** - * Both arguments are optional. The first argument is an object of - * built-in mappings which never change. The second argument is an object - * of initial (global-level) mappings, which will constantly change - * according to any global/top-level `set`s done. - */ - constructor(builtins = {}, globalMacros = {}) { - this.current = globalMacros; - this.builtins = builtins; - this.undefStack = []; - } - - /** - * Start a new nested group, affecting future local `set`s. - */ - beginGroup() { - this.undefStack.push({}); - } - - /** - * End current nested group, restoring values before the group began. - */ - endGroup() { - if (this.undefStack.length === 0) { - throw new ParseError( - "Unbalanced namespace destruction: attempt " + - "to pop global namespace; please report this as a bug" - ); - } - const undefs = this.undefStack.pop(); - for (const undef in undefs) { - if (Object.prototype.hasOwnProperty.call(undefs, undef )) { - if (undefs[undef] === undefined) { - delete this.current[undef]; - } else { - this.current[undef] = undefs[undef]; - } - } - } - } - - /** - * Detect whether `name` has a definition. Equivalent to - * `get(name) != null`. - */ - has(name) { - return Object.prototype.hasOwnProperty.call(this.current, name ) || - Object.prototype.hasOwnProperty.call(this.builtins, name ); - } - - /** - * Get the current value of a name, or `undefined` if there is no value. - * - * Note: Do not use `if (namespace.get(...))` to detect whether a macro - * is defined, as the definition may be the empty string which evaluates - * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or - * `if (namespace.has(...))`. - */ - get(name) { - if (Object.prototype.hasOwnProperty.call(this.current, name )) { - return this.current[name]; - } else { - return this.builtins[name]; - } - } - - /** - * Set the current value of a name, and adds an undo - * operation to the undo stack. - */ - set(name, value) { - // Undo this set at end of this group (possibly to `undefined`), - // unless an undo is already in place, in which case that older - // value is the correct one. - const top = this.undefStack[this.undefStack.length - 1]; - if (top && !Object.prototype.hasOwnProperty.call(top, name )) { - top[name] = this.current[name]; - } - this.current[name] = value; - } -} - -/** - * Predefined macros for Temml. - * This can be used to define some commands in terms of others. - */ -const macros = _macros; - -////////////////////////////////////////////////////////////////////// -// macro tools - -defineMacro("\\noexpand", function(context) { - // The expansion is the token itself; but that token is interpreted - // as if its meaning were ‘\relax’ if it is a control sequence that - // would ordinarily be expanded by TeX’s expansion rules. - const t = context.popToken(); - if (context.isExpandable(t.text)) { - t.noexpand = true; - t.treatAsRelax = true; - } - return { tokens: [t], numArgs: 0 }; -}); - -defineMacro("\\expandafter", function(context) { - // TeX first reads the token that comes immediately after \expandafter, - // without expanding it; let’s call this token t. Then TeX reads the - // token that comes after t (and possibly more tokens, if that token - // has an argument), replacing it by its expansion. Finally TeX puts - // t back in front of that expansion. - const t = context.popToken(); - context.expandOnce(true); // expand only an expandable token - return { tokens: [t], numArgs: 0 }; -}); - -// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 -// TeX source: \long\def\@firstoftwo#1#2{#1} -defineMacro("\\@firstoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[0], numArgs: 0 }; -}); - -// LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 -// TeX source: \long\def\@secondoftwo#1#2{#2} -defineMacro("\\@secondoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[1], numArgs: 0 }; -}); - -// LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) -// symbol that isn't a space, consuming any spaces but not consuming the -// first nonspace character. If that nonspace character matches #1, then -// the macro expands to #2; otherwise, it expands to #3. -defineMacro("\\@ifnextchar", function(context) { - const args = context.consumeArgs(3); // symbol, if, else - context.consumeSpaces(); - const nextToken = context.future(); - if (args[0].length === 1 && args[0][0].text === nextToken.text) { - return { tokens: args[1], numArgs: 0 }; - } else { - return { tokens: args[2], numArgs: 0 }; - } -}); - -// LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. -// If it is `*`, then it consumes the symbol, and the macro expands to #1; -// otherwise, the macro expands to #2 (without consuming the symbol). -// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} -defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); - -// LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode -defineMacro("\\TextOrMath", function(context) { - const args = context.consumeArgs(2); - if (context.mode === "text") { - return { tokens: args[0], numArgs: 0 }; - } else { - return { tokens: args[1], numArgs: 0 }; - } -}); - -const stringFromArg = arg => { - // Reverse the order of the arg and return a string. - let str = ""; - for (let i = arg.length - 1; i > -1; i--) { - str += arg[i].text; - } - return str -}; - -// Lookup table for parsing numbers in base 8 through 16 -const digitToNumber = { - 0: 0, - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - a: 10, - A: 10, - b: 11, - B: 11, - c: 12, - C: 12, - d: 13, - D: 13, - e: 14, - E: 14, - f: 15, - F: 15 -}; - -const nextCharNumber = context => { - const numStr = context.future().text; - if (numStr === "EOF") { return [null, ""] } - return [digitToNumber[numStr.charAt(0)], numStr] -}; - -const appendCharNumbers = (number, numStr, base) => { - for (let i = 1; i < numStr.length; i++) { - const digit = digitToNumber[numStr.charAt(i)]; - number *= base; - number += digit; - } - return number -}; - -// TeX \char makes a literal character (catcode 12) using the following forms: -// (see The TeXBook, p. 43) -// \char123 -- decimal -// \char'123 -- octal -// \char"123 -- hex -// \char`x -- character that can be written (i.e. isn't active) -// \char`\x -- character that cannot be written (e.g. %) -// These all refer to characters from the font, so we turn them into special -// calls to a function \@char dealt with in the Parser. -defineMacro("\\char", function(context) { - let token = context.popToken(); - let base; - let number = ""; - if (token.text === "'") { - base = 8; - token = context.popToken(); - } else if (token.text === '"') { - base = 16; - token = context.popToken(); - } else if (token.text === "`") { - token = context.popToken(); - if (token.text[0] === "\\") { - number = token.text.charCodeAt(1); - } else if (token.text === "EOF") { - throw new ParseError("\\char` missing argument"); - } else { - number = token.text.charCodeAt(0); - } - } else { - base = 10; - } - if (base) { - // Parse a number in the given base, starting with first `token`. - let numStr = token.text; - number = digitToNumber[numStr.charAt(0)]; - if (number == null || number >= base) { - throw new ParseError(`Invalid base-${base} digit ${token.text}`); - } - number = appendCharNumbers(number, numStr, base); - let digit; - [digit, numStr] = nextCharNumber(context); - while (digit != null && digit < base) { - number *= base; - number += digit; - number = appendCharNumbers(number, numStr, base); - context.popToken(); - [digit, numStr] = nextCharNumber(context); - } - } - return `\\@char{${number}}`; -}); - -// The Latin Modern font renders at the wrong vertical alignment. -// This macro provides a better rendering. -defineMacro("\\surd", "\\sqrt{}"); - -defineMacro("\\hbox", "\\text{#1}"); - -// Per TeXbook p.122, "/" gets zero operator spacing. -// And MDN recommends using U+2044 instead of / for inline -defineMacro("/", "{\u2044}"); - -// Since Temml has no \par, ignore \long. -defineMacro("\\long", ""); - -////////////////////////////////////////////////////////////////////// -// Grouping -// \let\bgroup={ \let\egroup=} -defineMacro("\\bgroup", "{"); -defineMacro("\\egroup", "}"); - -// Symbols from latex.ltx: -// \def~{\nobreakspace{}} -// \def\lq{`} -// \def\rq{'} -// \def \aa {\r a} -defineMacro("~", "\\nobreakspace"); -defineMacro("\\lq", "`"); -defineMacro("\\rq", "'"); -defineMacro("\\aa", "\\r a"); - -defineMacro("\\Bbbk", "\\Bbb{k}"); - -// \mathstrut from the TeXbook, p 360 -defineMacro("\\mathstrut", "\\vphantom{(}"); - -// \underbar from TeXbook p 353 -defineMacro("\\underbar", "\\underline{\\text{#1}}"); - -////////////////////////////////////////////////////////////////////// -// LaTeX_2ε - -// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ -// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} -// We'll call \varvdots, which gets a glyph from symbols.js. -// The zero-width rule gets us an equivalent to the vertical 6pt kern. -defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); -defineMacro("\u22ee", "\\vdots"); - -////////////////////////////////////////////////////////////////////// -// amsmath.sty -// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf - -//\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} -defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); - -// \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} -defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); - -// \def\iff{\DOTSB\;\Longleftrightarrow\;} -// \def\implies{\DOTSB\;\Longrightarrow\;} -// \def\impliedby{\DOTSB\;\Longleftarrow\;} -defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); -defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); -defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); - -// AMSMath's automatic \dots, based on \mdots@@ macro. -const dotsByToken = { - ",": "\\dotsc", - "\\not": "\\dotsb", - // \keybin@ checks for the following: - "+": "\\dotsb", - "=": "\\dotsb", - "<": "\\dotsb", - ">": "\\dotsb", - "-": "\\dotsb", - "*": "\\dotsb", - ":": "\\dotsb", - // Symbols whose definition starts with \DOTSB: - "\\DOTSB": "\\dotsb", - "\\coprod": "\\dotsb", - "\\bigvee": "\\dotsb", - "\\bigwedge": "\\dotsb", - "\\biguplus": "\\dotsb", - "\\bigcap": "\\dotsb", - "\\bigcup": "\\dotsb", - "\\prod": "\\dotsb", - "\\sum": "\\dotsb", - "\\bigotimes": "\\dotsb", - "\\bigoplus": "\\dotsb", - "\\bigodot": "\\dotsb", - "\\bigsqcap": "\\dotsb", - "\\bigsqcup": "\\dotsb", - "\\And": "\\dotsb", - "\\longrightarrow": "\\dotsb", - "\\Longrightarrow": "\\dotsb", - "\\longleftarrow": "\\dotsb", - "\\Longleftarrow": "\\dotsb", - "\\longleftrightarrow": "\\dotsb", - "\\Longleftrightarrow": "\\dotsb", - "\\mapsto": "\\dotsb", - "\\longmapsto": "\\dotsb", - "\\hookrightarrow": "\\dotsb", - "\\doteq": "\\dotsb", - // Symbols whose definition starts with \mathbin: - "\\mathbin": "\\dotsb", - // Symbols whose definition starts with \mathrel: - "\\mathrel": "\\dotsb", - "\\relbar": "\\dotsb", - "\\Relbar": "\\dotsb", - "\\xrightarrow": "\\dotsb", - "\\xleftarrow": "\\dotsb", - // Symbols whose definition starts with \DOTSI: - "\\DOTSI": "\\dotsi", - "\\int": "\\dotsi", - "\\oint": "\\dotsi", - "\\iint": "\\dotsi", - "\\iiint": "\\dotsi", - "\\iiiint": "\\dotsi", - "\\idotsint": "\\dotsi", - // Symbols whose definition starts with \DOTSX: - "\\DOTSX": "\\dotsx" -}; - -defineMacro("\\dots", function(context) { - // TODO: If used in text mode, should expand to \textellipsis. - // However, in Temml, \textellipsis and \ldots behave the same - // (in text mode), and it's unlikely we'd see any of the math commands - // that affect the behavior of \dots when in text mode. So fine for now - // (until we support \ifmmode ... \else ... \fi). - let thedots = "\\dotso"; - const next = context.expandAfterFuture().text; - if (next in dotsByToken) { - thedots = dotsByToken[next]; - } else if (next.slice(0, 4) === "\\not") { - thedots = "\\dotsb"; - } else if (next in symbols.math) { - if (utils.contains(["bin", "rel"], symbols.math[next].group)) { - thedots = "\\dotsb"; - } - } - return thedots; -}); - -const spaceAfterDots = { - // \rightdelim@ checks for the following: - ")": true, - "]": true, - "\\rbrack": true, - "\\}": true, - "\\rbrace": true, - "\\rangle": true, - "\\rceil": true, - "\\rfloor": true, - "\\rgroup": true, - "\\rmoustache": true, - "\\right": true, - "\\bigr": true, - "\\biggr": true, - "\\Bigr": true, - "\\Biggr": true, - // \extra@ also tests for the following: - $: true, - // \extrap@ checks for the following: - ";": true, - ".": true, - ",": true -}; - -defineMacro("\\dotso", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\dotsc", function(context) { - const next = context.future().text; - // \dotsc uses \extra@ but not \extrap@, instead specially checking for - // ';' and '.', but doesn't check for ','. - if (next in spaceAfterDots && next !== ",") { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\cdots", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\@cdots\\,"; - } else { - return "\\@cdots"; - } -}); - -defineMacro("\\dotsb", "\\cdots"); -defineMacro("\\dotsm", "\\cdots"); -defineMacro("\\dotsi", "\\!\\cdots"); -defineMacro("\\idotsint", "\\dotsi"); -// amsmath doesn't actually define \dotsx, but \dots followed by a macro -// starting with \DOTSX implies \dotso, and then \extra@ detects this case -// and forces the added `\,`. -defineMacro("\\dotsx", "\\ldots\\,"); - -// \let\DOTSI\relax -// \let\DOTSB\relax -// \let\DOTSX\relax -defineMacro("\\DOTSI", "\\relax"); -defineMacro("\\DOTSB", "\\relax"); -defineMacro("\\DOTSX", "\\relax"); - -// Spacing, based on amsmath.sty's override of LaTeX defaults -// \DeclareRobustCommand{\tmspace}[3]{% -// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} -defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); -// \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\,", "{\\tmspace+{3mu}{.1667em}}"); -// \let\thinspace\, -defineMacro("\\thinspace", "\\,"); -// \def\>{\mskip\medmuskip} -// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} -// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\>", "\\mskip{4mu}"); -defineMacro("\\:", "{\\tmspace+{4mu}{.2222em}}"); -// \let\medspace\: -defineMacro("\\medspace", "\\:"); -// \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip = 5mu plus 5mu -defineMacro("\\;", "{\\tmspace+{5mu}{.2777em}}"); -// \let\thickspace\; -defineMacro("\\thickspace", "\\;"); -// \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\!", "{\\tmspace-{3mu}{.1667em}}"); -// \let\negthinspace\! -defineMacro("\\negthinspace", "\\!"); -// \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} -// TODO: math mode should use \medmuskip -defineMacro("\\negmedspace", "{\\tmspace-{4mu}{.2222em}}"); -// \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip -defineMacro("\\negthickspace", "{\\tmspace-{5mu}{.277em}}"); -// \def\enspace{\kern.5em } -defineMacro("\\enspace", "\\kern.5em "); -// \def\enskip{\hskip.5em\relax} -defineMacro("\\enskip", "\\hskip.5em\\relax"); -// \def\quad{\hskip1em\relax} -defineMacro("\\quad", "\\hskip1em\\relax"); -// \def\qquad{\hskip2em\relax} -defineMacro("\\qquad", "\\hskip2em\\relax"); - -// \tag@in@display form of \tag -defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); -defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); -defineMacro("\\tag@literal", (context) => { - if (context.macros.get("\\df@tag")) { - throw new ParseError("Multiple \\tag"); - } - return "\\def\\df@tag{\\text{#1}}"; -}); - -// \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin -// {\operator@font mod}\penalty900 -// \mkern5mu\nonscript\mskip-\medmuskip} -// \newcommand{\pod}[1]{\allowbreak -// \if@display\mkern18mu\else\mkern8mu\fi(#1)} -// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} -// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu -// \else\mkern12mu\fi{\operator@font mod}\,\,#1} -// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\bmod", "\\mathbin{\\text{mod}}"); -defineMacro( - "\\pod", - "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)" -); -defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); -defineMacro( - "\\mod", - "\\allowbreak" + - "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + - "{\\rm mod}\\,\\,#1" -); - -////////////////////////////////////////////////////////////////////// -// LaTeX source2e - -// \expandafter\let\expandafter\@normalcr -// \csname\expandafter\@gobble\string\\ \endcsname -// \DeclareRobustCommand\newline{\@normalcr\relax} -defineMacro("\\newline", "\\\\\\relax"); - -// \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} -// TODO: Doesn't normally work in math mode because \@ fails. -defineMacro("\\TeX", "\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"); - -defineMacro( - "\\LaTeX", - "\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX" -); - -defineMacro( - "\\Temml", - // eslint-disable-next-line max-len - "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}" -); - -// \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} -// \def\@hspace#1{\hskip #1\relax} -// \def\@hspacer#1{\vrule \@width\z@\nobreak -// \hskip #1\hskip \z@skip} -defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); -defineMacro("\\@hspace", "\\hskip #1\\relax"); -defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); - -defineMacro("\\colon", `\\mathpunct{\\char"3a}`); - -////////////////////////////////////////////////////////////////////// -// mathtools.sty - -defineMacro("\\prescript", "\\pres@cript{_{#1}^{#2}}{}{#3}"); - -//\providecommand\ordinarycolon{:} -defineMacro("\\ordinarycolon", `\\char"3a`); -// Raise to center on the math axis, as closely as possible. -defineMacro("\\vcentcolon", "\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}}"); -// \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\coloneq", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2212}'); -// \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\Coloneq", '\\mathrel{\\char"2237\\char"2212}'); -// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqqcolon", '\\mathrel{\\char"3d\\char"2237}'); -// \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqcolon", '\\mathrel{\\char"2212\\char"2237}'); -// \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\colonapprox", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2248}'); -// \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\Colonapprox", '\\mathrel{\\char"2237\\char"2248}'); -// \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); -// \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\Colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); - -////////////////////////////////////////////////////////////////////// -// colonequals.sty - -// Alternate names for mathtools's macros: -defineMacro("\\ratio", "\\vcentcolon"); -defineMacro("\\coloncolon", "\\dblcolon"); -defineMacro("\\colonequals", "\\coloneqq"); -defineMacro("\\coloncolonequals", "\\Coloneqq"); -defineMacro("\\equalscolon", "\\eqqcolon"); -defineMacro("\\equalscoloncolon", "\\Eqqcolon"); -defineMacro("\\colonminus", "\\coloneq"); -defineMacro("\\coloncolonminus", "\\Coloneq"); -defineMacro("\\minuscolon", "\\eqcolon"); -defineMacro("\\minuscoloncolon", "\\Eqcolon"); -// \colonapprox name is same in mathtools and colonequals. -defineMacro("\\coloncolonapprox", "\\Colonapprox"); -// \colonsim name is same in mathtools and colonequals. -defineMacro("\\coloncolonsim", "\\Colonsim"); - -// Present in newtxmath, pxfonts and txfonts -defineMacro("\\notni", "\\mathrel{\\char`\u220C}"); -defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); -defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); - -////////////////////////////////////////////////////////////////////// -// From amsopn.sty -defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}"); -defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}"); -defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"); -defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"); -defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"); -defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"); - -defineMacro("\\centerdot", "{\\medspace\\rule{0.167em}{0.189em}\\medspace}"); - -////////////////////////////////////////////////////////////////////// -// statmath.sty -// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf - -defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); -defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); -defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}"); - -////////////////////////////////////////////////////////////////////// -// braket.sty -// http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf - -defineMacro("\\bra", "\\mathinner{\\langle{#1}|}"); -defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}"); -defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}"); -defineMacro("\\Bra", "\\left\\langle#1\\right|"); -defineMacro("\\Ket", "\\left|#1\\right\\rangle"); -const braketHelper = (one) => (context) => { - const left = context.consumeArg().tokens; - const middle = context.consumeArg().tokens; - const middleDouble = context.consumeArg().tokens; - const right = context.consumeArg().tokens; - const oldMiddle = context.macros.get("|"); - const oldMiddleDouble = context.macros.get("\\|"); - context.macros.beginGroup(); - const midMacro = (double) => (context) => { - if (one) { - // Only modify the first instance of | or \| - context.macros.set("|", oldMiddle); - if (middleDouble.length) { - context.macros.set("\\|", oldMiddleDouble); - } - } - let doubled = double; - if (!double && middleDouble.length) { - // Mimic \@ifnextchar - const nextToken = context.future(); - if (nextToken.text === "|") { - context.popToken(); - doubled = true; - } - } - return { - tokens: doubled ? middleDouble : middle, - numArgs: 0 - }; - }; - context.macros.set("|", midMacro(false)); - if (middleDouble.length) { - context.macros.set("\\|", midMacro(true)); - } - const arg = context.consumeArg().tokens; - const expanded = context.expandTokens([...right, ...arg, ...left]); // reversed - context.macros.endGroup(); - return { - tokens: expanded.reverse(), - numArgs: 0 - }; -}; -defineMacro("\\bra@ket", braketHelper(false)); -defineMacro("\\bra@set", braketHelper(true)); -defineMacro("\\Braket", "\\bra@ket{\\left\\langle}" + - "{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"); -defineMacro("\\Set", "\\bra@set{\\left\\{\\:}" + - "{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"); -defineMacro("\\set", "\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"); - // has no support for special || or \| - -////////////////////////////////////////////////////////////////////// -// actuarialangle.dtx -defineMacro("\\angln", "{\\angl n}"); - -////////////////////////////////////////////////////////////////////// -// derivative.sty -defineMacro("\\odv", "\\@ifstar\\odv@next\\odv@numerator"); -defineMacro("\\odv@numerator", "\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}"); -defineMacro("\\odv@next", "\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1"); -defineMacro("\\pdv", "\\@ifstar\\pdv@next\\pdv@numerator"); - -const pdvHelper = args => { - const numerator = args[0][0].text; - const denoms = stringFromArg(args[1]).split(","); - const power = String(denoms.length); - const numOp = power === "1" ? "\\partial" : `\\partial^${power}`; - let denominator = ""; - denoms.map(e => { denominator += "\\partial " + e.trim() + "\\,";}); - return [numerator, numOp, denominator.replace(/\\,$/, "")] -}; -defineMacro("\\pdv@numerator", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp} ${numerator}}{${denominator}}` -}); -defineMacro("\\pdv@next", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp}}{${denominator}} ${numerator}` -}); - -////////////////////////////////////////////////////////////////////// -// upgreek.dtx -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\upbeta", "\\up@greek{\\beta}"); -defineMacro("\\upgamma", "\\up@greek{\\gamma}"); -defineMacro("\\updelta", "\\up@greek{\\delta}"); -defineMacro("\\upepsilon", "\\up@greek{\\epsilon}"); -defineMacro("\\upzeta", "\\up@greek{\\zeta}"); -defineMacro("\\upeta", "\\up@greek{\\eta}"); -defineMacro("\\uptheta", "\\up@greek{\\theta}"); -defineMacro("\\upiota", "\\up@greek{\\iota}"); -defineMacro("\\upkappa", "\\up@greek{\\kappa}"); -defineMacro("\\uplambda", "\\up@greek{\\lambda}"); -defineMacro("\\upmu", "\\up@greek{\\mu}"); -defineMacro("\\upnu", "\\up@greek{\\nu}"); -defineMacro("\\upxi", "\\up@greek{\\xi}"); -defineMacro("\\upomicron", "\\up@greek{\\omicron}"); -defineMacro("\\uppi", "\\up@greek{\\pi}"); -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\uprho", "\\up@greek{\\rho}"); -defineMacro("\\upsigma", "\\up@greek{\\sigma}"); -defineMacro("\\uptau", "\\up@greek{\\tau}"); -defineMacro("\\upupsilon", "\\up@greek{\\upsilon}"); -defineMacro("\\upphi", "\\up@greek{\\phi}"); -defineMacro("\\upchi", "\\up@greek{\\chi}"); -defineMacro("\\uppsi", "\\up@greek{\\psi}"); -defineMacro("\\upomega", "\\up@greek{\\omega}"); - -////////////////////////////////////////////////////////////////////// -// cmll package -defineMacro("\\invamp", '\\mathbin{\\char"214b}'); -defineMacro("\\parr", '\\mathbin{\\char"214b}'); -defineMacro("\\with", '\\mathbin{\\char"26}'); -defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}'); -defineMacro("\\multimapboth", '\\mathrel{\\char"29df}'); -defineMacro("\\scoh", '{\\mkern5mu\\char"2322\\mkern5mu}'); -defineMacro("\\sincoh", '{\\mkern5mu\\char"2323\\mkern5mu}'); -defineMacro("\\coh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2322}}} -{\\smash{\\lower4mu{\\char"2323}}}\\mkern5mu}`); -defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2323}}} -{\\smash{\\lower4mu{\\char"2322}}}\\mkern5mu}`); - - -////////////////////////////////////////////////////////////////////// -// chemstyle package -defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}"); - -/* eslint-disable */ -/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ - -/************************************************************* - * - * Temml mhchem.js - * - * This file implements a Temml version of mhchem version 3.3.0. - * It is adapted from MathJax/extensions/TeX/mhchem.js - * It differs from the MathJax version as follows: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. - * 3. The reaction arrow code is simplified. All reaction arrows are rendered - * using Temml extensible arrows instead of building non-extensible arrows. - * 4. The ~bond forms are composed entirely of \rule elements. - * 5. Two dashes in _getBond are wrapped in braces to suppress spacing. i.e., {-} - * 6. The electron dot uses \textbullet instead of \bullet. - * - * This code, as other Temml code, is released under the MIT license. - * - * /************************************************************* - * - * MathJax/extensions/TeX/mhchem.js - * - * Implements the \ce command for handling chemical formulas - * from the mhchem LaTeX package. - * - * --------------------------------------------------------------------- - * - * Copyright (c) 2011-2015 The MathJax Consortium - * Copyright (c) 2015-2018 Martin Hensel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Coding Style -// - use '' for identifiers that can by minified/uglified -// - use "" for strings that need to stay untouched - -// version: "3.3.0" for MathJax and Temml - - -// Add \ce, \pu, and \tripleDash to the Temml macros. - -defineMacro("\\ce", function(context) { - return chemParse(context.consumeArgs(1)[0], "ce") -}); - -defineMacro("\\pu", function(context) { - return chemParse(context.consumeArgs(1)[0], "pu"); -}); - -// Math fonts do not include glyphs for the ~ form of bonds. So we'll send path geometry -// So we'll compose characters built from \rule elements. -defineMacro("\\uniDash", `{\\rule{0.672em}{0.06em}}`) -defineMacro("\\triDash", `{\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}}`) -defineMacro("\\tripleDash", `\\kern0.075em\\raise0.25em{\\triDash}\\kern0.075em`) -defineMacro("\\tripleDashOverLine", `\\kern0.075em\\mathrlap{\\raise0.125em{\\uniDash}}\\raise0.34em{\\triDash}\\kern0.075em`) -defineMacro("\\tripleDashOverDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\triDash}}\\raise0.27em{\\uniDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`) -defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\uniDash}}\\raise0.27em{\\triDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`) - - // - // This is the main function for handing the \ce and \pu commands. - // It takes the argument to \ce or \pu and returns the corresponding TeX string. - // - - var chemParse = function (tokens, stateMachine) { - // Recreate the argument string from Temml's array of tokens. - var str = ""; - var expectedLoc = tokens.length && tokens[tokens.length - 1].loc.start - for (var i = tokens.length - 1; i >= 0; i--) { - if(tokens[i].loc.start > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = tokens[i].loc.start; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - // Call the mhchem core parser. - var tex = texify.go(mhchemParser.go(str, stateMachine)); - return tex; - }; - - // - // Core parser for mhchem syntax (recursive) - // - /** @type {MhchemParser} */ - var mhchemParser = { - // - // Parses mchem \ce syntax - // - // Call like - // go("H2O"); - // - go: function (input, stateMachine) { - if (!input) { return []; } - if (stateMachine === undefined) { stateMachine = 'ce'; } - var state = '0'; - - // - // String buffers for parsing: - // - // buffer.a == amount - // buffer.o == element - // buffer.b == left-side superscript - // buffer.p == left-side subscript - // buffer.q == right-side subscript - // buffer.d == right-side superscript - // - // buffer.r == arrow - // buffer.rdt == arrow, script above, type - // buffer.rd == arrow, script above, content - // buffer.rqt == arrow, script below, type - // buffer.rq == arrow, script below, content - // - // buffer.text_ - // buffer.rm - // etc. - // - // buffer.parenthesisLevel == int, starting at 0 - // buffer.sb == bool, space before - // buffer.beginsWithBond == bool - // - // These letters are also used as state names. - // - // Other states: - // 0 == begin of main part (arrow/operator unlikely) - // 1 == next entity - // 2 == next entity (arrow/operator unlikely) - // 3 == next atom - // c == macro - // - /** @type {Buffer} */ - var buffer = {}; - buffer['parenthesisLevel'] = 0; - - input = input.replace(/\n/g, " "); - input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); - input = input.replace(/[\u2026]/g, "..."); - - // - // Looks through mhchemParser.transitions, to execute a matching action - // (recursive) - // - var lastInput; - var watchdog = 10; - /** @type {ParserOutput[]} */ - var output = []; - while (true) { - if (lastInput !== input) { - watchdog = 10; - lastInput = input; - } else { - watchdog--; - } - // - // Find actions in transition table - // - var machine = mhchemParser.stateMachines[stateMachine]; - var t = machine.transitions[state] || machine.transitions['*']; - iterateTransitions: - for (var i=0; i 0) { - if (!task.revisit) { - input = matches.remainder; - } - if (!task.toContinue) { - break iterateTransitions; - } - } else { - return output; - } - } - } - // - // Prevent infinite loop - // - if (watchdog <= 0) { - throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character - } - } - }, - concatArray: function (a, b) { - if (b) { - if (Array.isArray(b)) { - for (var iB=0; iB': /^[=<>]/, - '#': /^[#\u2261]/, - '+': /^\+/, - '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation - '-9': /^-(?=[0-9])/, - '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, - '-': /^-/, - 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, - 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, - 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, - '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, - '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, - 'CMT': /^[CMT](?=\[)/, - '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, - '1st-level escape': /^(&|\\\\|\\hline)\s*/, - '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before - '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, - '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, - '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, - '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, - 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway - 'others': /^[\/~|]/, - '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, - '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, - '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, - '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, - '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, - '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); }, - '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, - '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, - 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, - 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge - 'roman numeral': /^[IVX]+/, - '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, - 'amount': function (input) { - var match; - // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing - match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); - if (a) { // e.g. $2n-1$, $-$ - match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - } - return null; - }, - 'amount2': function (input) { return this['amount'](input); }, - '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, - 'formula$': function (input) { - if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula - var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - return null; - }, - 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, - '/': /^\s*(\/)\s*/, - '//': /^\s*(\/\/)\s*/, - '*': /^\s*[*.]\s*/ - }, - findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { - /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ - var _match = function (input, pattern) { - if (typeof pattern === "string") { - if (input.indexOf(pattern) !== 0) { return null; } - return pattern; - } else { - var match = input.match(pattern); - if (!match) { return null; } - return match[0]; - } - }; - /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ - var _findObserveGroups = function (input, i, endChars) { - var braces = 0; - while (i < input.length) { - var a = input.charAt(i); - var match = _match(input.substr(i), endChars); - if (match !== null && braces === 0) { - return { endMatchBegin: i, endMatchEnd: i + match.length }; - } else if (a === "{") { - braces++; - } else if (a === "}") { - if (braces === 0) { - throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; - } else { - braces--; - } - } - i++; - } - if (braces > 0) { - return null; - } - return null; - }; - var match = _match(input, begExcl); - if (match === null) { return null; } - input = input.substr(match.length); - match = _match(input, begIncl); - if (match === null) { return null; } - var e = _findObserveGroups(input, match.length, endIncl || endExcl); - if (e === null) { return null; } - var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); - if (!(beg2Excl || beg2Incl)) { - return { - match_: match1, - remainder: input.substr(e.endMatchEnd) - }; - } else { - var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); - if (group2 === null) { return null; } - /** @type {string[]} */ - var matchRet = [match1, group2.match_]; - return { - match_: (combine ? matchRet.join("") : matchRet), - remainder: group2.remainder - }; - } - }, - - // - // Matching function - // e.g. match("a", input) will look for the regexp called "a" and see if it matches - // returns null or {match_:"a", remainder:"bc"} - // - match_: function (m, input) { - var pattern = mhchemParser.patterns.patterns[m]; - if (pattern === undefined) { - throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern - } else if (typeof pattern === "function") { - return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser - } else { // RegExp - var match = input.match(pattern); - if (match) { - var mm; - if (match[2]) { - mm = [ match[1], match[2] ]; - } else if (match[1]) { - mm = match[1]; - } else { - mm = match[0]; - } - return { match_: mm, remainder: input.substr(match[0].length) }; - } - return null; - } - } - }, - - // - // Generic state machine actions - // - actions: { - 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; }, - 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; }, - 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; }, - 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; }, - 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; }, - 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; }, - 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; }, - 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; }, - 'insert': function (buffer, m, a) { return { type_: a }; }, - 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; }, - 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, - 'copy': function (buffer, m) { return m; }, - 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; }, - 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); }, - '{text}': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); - ret.push("}"); - return ret; - }, - 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); }, - 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); }, - 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, - 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; }, - 'ce': function (buffer, m) { return mhchemParser.go(m); }, - '1/2': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m.match(/^[+\-]/)) { - ret.push(m.substr(0, 1)); - m = m.substr(1); - } - var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); - n[1] = n[1].replace(/\$/g, ""); - ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); - if (n[3]) { - n[3] = n[3].replace(/\$/g, ""); - ret.push({ type_: 'tex-math', p1: n[3] }); - } - return ret; - }, - '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); } - }, - // - // createTransitions - // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } - // with expansion of 'a|b' to 'a' and 'b' (at 2 places) - // - createTransitions: function (o) { - var pattern, state; - /** @type {string[]} */ - var stateArray; - var i; - // - // 1. Collect all states - // - /** @type {Transitions} */ - var transitions = {}; - for (pattern in o) { - for (state in o[pattern]) { - stateArray = state.split("|"); - o[pattern][state].stateArray = stateArray; - for (i=0; i': { - '0|1|2|3': { action_: 'r=', nextState: 'r' }, - 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' }, - '*': { action_: [ 'output', 'r=' ], nextState: 'r' } }, - '+': { - 'o': { action_: 'd= kv', nextState: 'd' }, - 'd|D': { action_: 'd=', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd|qD': { action_: 'd=', nextState: 'qd' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' }, - '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - 'amount': { - '0|2': { action_: 'a=', nextState: 'a' } }, - 'pm-operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } }, - 'operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - '-$': { - 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' }, - 'd': { action_: 'd=', nextState: 'd' }, - 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd': { action_: 'd=', nextState: 'qd' }, - 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - '-9': { - '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } }, - '- orbital overlap': { - 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } }, - '-': { - '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' }, - '3': { action_: { type_: 'bond', option: "-" } }, - 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' }, - 'b': { action_: 'b=' }, - 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, - 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - 'amount2': { - '1|3': { action_: 'a=', nextState: 'a' } }, - 'letters': { - '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, - 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, - 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, - 'digits': { - 'o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q': { action_: [ 'output', 'o=' ], nextState: 'o' }, - 'a': { action_: 'o=', nextState: 'o' } }, - 'space A': { - 'b|p|bp': {} }, - 'space': { - 'a': { nextState: 'as' }, - '0': { action_: 'sb=false' }, - '1|2': { action_: 'sb=true' }, - 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, - '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} }, - '1st-level escape': { - '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] }, - '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } }, - '[(...)]': { - 'r|rt': { action_: 'rd=', nextState: 'rd' }, - 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, - '...': { - 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' }, - '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } }, - '. |* ': { - '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } }, - 'state of aggregation $': { - '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } }, - '{[(': { - 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } }, - ')]}': { - '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' }, - 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } }, - ', ': { - '*': { action_: [ 'output', 'comma' ], nextState: '0' } }, - '^_': { // ^ and _ without a sensible argument - '*': { } }, - '^{(...)}|^($...$)': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'D' }, - 'q': { action_: 'd=', nextState: 'qD' }, - 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } }, - '^a|^\\x{}{}|^\\x{}|^\\x|\'': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'd|qd|D|qD': { action_: 'd=' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } }, - '_{(state of aggregation)}$': { - 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { - '0|1|2|as': { action_: 'p=', nextState: 'p' }, - 'b': { action_: 'p=', nextState: 'bp' }, - '3|o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '=<>': { - '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } }, - '#': { - '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } }, - '{}': { - '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, - '{...}': { - '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, - 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '$...$': { - 'a': { action_: 'a=' }, // 2$n$ - '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount' - 'as|o': { action_: 'o=' }, - 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '\\bond{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } }, - '\\frac{(...)}': { - '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } }, - '\\overset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } }, - '\\underset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } }, - '\\underbrace{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } }, - '\\color{(...)}0': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } }, - '\\ce{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } }, - '\\,': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } }, - '\\x{}{}|\\x{}|\\x': { - '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' }, - '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } }, - 'others': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } }, - 'else2': { - 'a': { action_: 'a to o', nextState: 'o', revisit: true }, - 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true }, - 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true }, - '*': { action_: [ 'output', 'copy' ], nextState: '3' } } - }), - actions: { - 'o after d': function (buffer, m) { - var ret; - if ((buffer.d || "").match(/^[0-9]+$/)) { - var tmp = buffer.d; - buffer.d = undefined; - ret = this['output'](buffer); - buffer.b = tmp; - } else { - ret = this['output'](buffer); - } - mhchemParser.actions['o='](buffer, m); - return ret; - }, - 'd= kv': function (buffer, m) { - buffer.d = m; - buffer.dType = 'kv'; - }, - 'charge or bond': function (buffer, m) { - if (buffer['beginsWithBond']) { - /** @type {ParserOutput[]} */ - var ret = []; - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - return ret; - } else { - buffer.d = m; - } - }, - '- after o/d': function (buffer, m, isAfterD) { - var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); - var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); - var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); - var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); - var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 ); - if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { - buffer.o = '$' + buffer.o + '$'; - } - /** @type {ParserOutput[]} */ - var ret = []; - if (hyphenFollows) { - mhchemParser.concatArray(ret, this['output'](buffer)); - ret.push({ type_: 'hyphen' }); - } else { - c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); - if (isAfterD && c1 && c1.remainder==='') { - mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); - mhchemParser.concatArray(ret, this['output'](buffer)); - } else { - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - } - } - return ret; - }, - 'a to o': function (buffer) { - buffer.o = buffer.a; - buffer.a = undefined; - }, - 'sb=true': function (buffer) { buffer.sb = true; }, - 'sb=false': function (buffer) { buffer.sb = false; }, - 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; }, - 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; }, - 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; }, - 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; }, - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') }; - }, - 'comma': function (buffer, m) { - var a = m.replace(/\s*$/, ''); - var withSpace = (a !== m); - if (withSpace && buffer['parenthesisLevel'] === 0) { - return { type_: 'comma enumeration L', p1: a }; - } else { - return { type_: 'comma enumeration M', p1: a }; - } - }, - 'output': function (buffer, m, entityFollows) { - // entityFollows: - // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) - // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) - // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - if (!buffer.r) { - ret = []; - if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { - //ret = []; - } else { - if (buffer.sb) { - ret.push({ type_: 'entitySkip' }); - } - if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) { - buffer.o = buffer.a; - buffer.a = undefined; - } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { - buffer.o = buffer.a; - buffer.d = buffer.b; - buffer.q = buffer.p; - buffer.a = buffer.b = buffer.p = undefined; - } else { - if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { - buffer.dType = 'oxidation'; - } else if (buffer.o && buffer.dType==='kv' && !buffer.q) { - buffer.dType = undefined; - } - } - ret.push({ - type_: 'chemfive', - a: mhchemParser.go(buffer.a, 'a'), - b: mhchemParser.go(buffer.b, 'bd'), - p: mhchemParser.go(buffer.p, 'pq'), - o: mhchemParser.go(buffer.o, 'o'), - q: mhchemParser.go(buffer.q, 'pq'), - d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), - dType: buffer.dType - }); - } - } else { // r - /** @type {ParserOutput[]} */ - var rd; - if (buffer.rdt === 'M') { - rd = mhchemParser.go(buffer.rd, 'tex-math'); - } else if (buffer.rdt === 'T') { - rd = [ { type_: 'text', p1: buffer.rd || "" } ]; - } else { - rd = mhchemParser.go(buffer.rd); - } - /** @type {ParserOutput[]} */ - var rq; - if (buffer.rqt === 'M') { - rq = mhchemParser.go(buffer.rq, 'tex-math'); - } else if (buffer.rqt === 'T') { - rq = [ { type_: 'text', p1: buffer.rq || ""} ]; - } else { - rq = mhchemParser.go(buffer.rq); - } - ret = { - type_: 'arrow', - r: buffer.r, - rd: rd, - rq: rq - }; - } - for (var p in buffer) { - if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { - delete buffer[p]; - } - } - return ret; - }, - 'oxidation-output': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); - ret.push("}"); - return ret; - }, - 'frac-output': function (buffer, m) { - return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'overset-output': function (buffer, m) { - return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underset-output': function (buffer, m) { - return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underbrace-output': function (buffer, m) { - return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) }; - }, - 'r=': function (buffer, m) { buffer.r = m; }, - 'rdt=': function (buffer, m) { buffer.rdt = m; }, - 'rd=': function (buffer, m) { buffer.rd = m; }, - 'rqt=': function (buffer, m) { buffer.rqt = m; }, - 'rq=': function (buffer, m) { buffer.rq = m; }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } - } - }, - 'a': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - '$(...)$': { - '*': { action_: 'tex-math tight', nextState: '1' } }, - ',': { - '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'o': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - 'letters': { - '*': { action_: 'rm' } }, - '\\ca': { - '*': { action_: { type_: 'insert', option: 'circa' } } }, - '\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: '{text}' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'text': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '{...}': { - '*': { action_: 'text=' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '\\greek': { - '*': { action_: [ 'output', 'rm' ] } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: [ 'output', 'copy' ] } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.text_) { - /** @type {ParserOutput} */ - var ret = { type_: 'text', p1: buffer.text_ }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'pq': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'state of aggregation $': { - '*': { action_: 'state of aggregation' } }, - 'i$': { - '0': { nextState: '!f', revisit: true } }, - '(KV letters),': { - '0': { action_: 'rm', nextState: '0' } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'letters': { - '*': { action_: 'rm' } }, - '-9.,9': { - '*': { action_: '9,9' } }, - ',': { - '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') }; - } - } - }, - 'bd': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'x$': { - '0': { nextState: '!f', revisit: true } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '-9.,9 no missing 0': { - '*': { action_: '9,9' } }, - '.': { - '*': { action_: { type_: 'insert', option: 'electron dot' } } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'x': { - '*': { action_: { type_: 'insert', option: 'KV x' } } }, - 'letters': { - '*': { action_: 'rm' } }, - '\'': { - '*': { action_: { type_: 'insert', option: 'prime' } } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') }; - } - } - }, - 'oxidation': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'roman numeral': { - '*': { action_: 'roman-numeral' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; } - } - }, - 'tex-math': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'tex-math tight': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - '-|+': { - '*': { action_: 'tight operator' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; }, - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - '9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - ',': { - '*': { action_: 'comma' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; } - } - }, - //#endregion - // - // \pu state machines - // - //#region pu - 'pu': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - 'space$': { - '*': { action_: [ 'output', 'space' ] } }, - '{[(|)]}': { - '0|a': { action_: 'copy' } }, - '(-)(9)^(-9)': { - '0': { action_: 'number^', nextState: 'a' } }, - '(-)(9.,9)(e)(99)': { - '0': { action_: 'enumber', nextState: 'a' } }, - 'space': { - '0|a': {} }, - 'pm-operator': { - '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } }, - 'operator': { - '0|a': { action_: 'copy', nextState: '0' } }, - '//': { - 'd': { action_: 'o=', nextState: '/' } }, - '/': { - 'd': { action_: 'o=', nextState: '/' } }, - '{...}|else': { - '0|d': { action_: 'd=', nextState: 'd' }, - 'a': { action_: [ 'space', 'd=' ], nextState: 'd' }, - '/|q': { action_: 'q=', nextState: 'q' } } - }), - actions: { - 'enumber': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - if (m[1]) { - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - if (m[2]) { - if (m[2].match(/[,.]/)) { - mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); - } else { - ret.push(m[2]); - } - } - m[3] = m[4] || m[3]; - if (m[3]) { - m[3] = m[3].trim(); - if (m[3] === "e" || m[3].substr(0, 1) === "*") { - ret.push({ type_: 'cdot' }); - } else { - ret.push({ type_: 'times' }); - } - } - } - if (m[3]) { - ret.push("10^{"+m[5]+"}"); - } - return ret; - }, - 'number^': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - ret.push("^{"+m[2]+"}"); - return ret; - }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }, - 'space': function () { return { type_: 'pu-space-1' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); - if (md && md.remainder === '') { buffer.d = md.match_; } - var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); - if (mq && mq.remainder === '') { buffer.q = mq.match_; } - if (buffer.d) { - buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - } - if (buffer.q) { // fraction - buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - var b5 = { - d: mhchemParser.go(buffer.d, 'pu'), - q: mhchemParser.go(buffer.q, 'pu') - }; - if (buffer.o === '//') { - ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q }; - } else { - ret = b5.d; - if (b5.d.length > 1 || b5.q.length > 1) { - ret.push({ type_: ' / ' }); - } else { - ret.push({ type_: '/' }); - } - mhchemParser.concatArray(ret, b5.q); - } - } else { // no fraction - ret = mhchemParser.go(buffer.d, 'pu-2'); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-2': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '*': { - '*': { action_: [ 'output', 'cdot' ], nextState: '0' } }, - '\\x': { - '*': { action_: 'rm=' } }, - 'space': { - '*': { action_: [ 'output', 'space' ], nextState: '0' } }, - '^{(...)}|^(-1)': { - '1': { action_: '^(-1)' } }, - '-9.,9': { - '0': { action_: 'rm=', nextState: '0' }, - '1': { action_: '^(-1)', nextState: '0' } }, - '{...}|else': { - '*': { action_: 'rm=', nextState: '1' } } - }), - actions: { - 'cdot': function () { return { type_: 'tight cdot' }; }, - '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; }, - 'space': function () { return { type_: 'pu-space-2' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret = []; - if (buffer.rm) { - var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); - if (mrm && mrm.remainder === '') { - ret = mhchemParser.go(mrm.match_, 'pu'); - } else { - ret = { type_: 'rm', p1: buffer.rm }; - } - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '0': { action_: 'output-0' }, - 'o': { action_: 'output-o' } }, - ',': { - '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } }, - '.': { - '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; }, - 'output-0': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length % 3; - if (a === 0) { a = 3; } - for (var i=buffer.text_.length-3; i>0; i-=3) { - ret.push(buffer.text_.substr(i, 3)); - ret.push({ type_: '1000 separator' }); - } - ret.push(buffer.text_.substr(0, a)); - ret.reverse(); - } else { - ret.push(buffer.text_); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - }, - 'output-o': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length - 3; - for (var i=0; i, so we change \vphantom{X} to {} - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - } else { - if (b5.q) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - if (b5.d) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "^{"+b5.d+"}"; - } - } - break; - case 'rm': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'text': - if (buf.p1.match(/[\^_]/)) { - buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}"); - res = "\\mathrm{"+buf.p1+"}"; - } else { - res = "\\text{"+buf.p1+"}"; - } - break; - case 'roman numeral': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'state of aggregation': - res = "\\mskip2mu "+texify._goInner(buf.p1); - break; - case 'state of aggregation subscript': - res = "\\mskip1mu "+texify._goInner(buf.p1); - break; - case 'bond': - res = texify._getBond(buf.kind_); - if (!res) { - throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"]; - } - break; - case 'frac': - var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}"; - res = "\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}"; - break; - case 'pu-frac': - var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - res = "\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}"; - break; - case 'tex-math': - res = buf.p1 + " "; - break; - case 'frac-ce': - res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'overset': - res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underset': - res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underbrace': - res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}"; - break; - case 'color': - res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}"; - break; - case 'color0': - res = "\\color{" + buf.color + "}"; - break; - case 'arrow': - var b6 = { - rd: texify._goInner(buf.rd), - rq: texify._goInner(buf.rq) - }; - var arrow = texify._getArrow(buf.r); - if (b6.rq) { arrow += "[{\\rm " + b6.rq + "}]"; } - if (b6.rd) { - arrow += "{\\rm " + b6.rd + "}"; - } else { - arrow += "{}"; - } - res = arrow; - break; - case 'operator': - res = texify._getOperator(buf.kind_); - break; - case '1st-level escape': - res = buf.p1+" "; // &, \\\\, \\hlin - break; - case 'space': - res = " "; - break; - case 'entitySkip': - res = "~"; - break; - case 'pu-space-1': - res = "~"; - break; - case 'pu-space-2': - res = "\\mkern3mu "; - break; - case '1000 separator': - res = "\\mkern2mu "; - break; - case 'commaDecimal': - res = "{,}"; - break; - case 'comma enumeration L': - res = "{"+buf.p1+"}\\mkern6mu "; - break; - case 'comma enumeration M': - res = "{"+buf.p1+"}\\mkern3mu "; - break; - case 'comma enumeration S': - res = "{"+buf.p1+"}\\mkern1mu "; - break; - case 'hyphen': - res = "\\text{-}"; - break; - case 'addition compound': - res = "\\,{\\cdot}\\,"; - break; - case 'electron dot': - res = "\\mkern1mu \\text{\\textbullet}\\mkern1mu "; - break; - case 'KV x': - res = "{\\times}"; - break; - case 'prime': - res = "\\prime "; - break; - case 'cdot': - res = "\\cdot "; - break; - case 'tight cdot': - res = "\\mkern1mu{\\cdot}\\mkern1mu "; - break; - case 'times': - res = "\\times "; - break; - case 'circa': - res = "{\\sim}"; - break; - case '^': - res = "uparrow"; - break; - case 'v': - res = "downarrow"; - break; - case 'ellipsis': - res = "\\ldots "; - break; - case '/': - res = "/"; - break; - case ' / ': - res = "\\,/\\,"; - break; - default: - assertNever(buf); - throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output - } - assertString(res); - return res; - }, - _getArrow: function (a) { - switch (a) { - case "->": return "\\yields"; - case "\u2192": return "\\yields"; - case "\u27F6": return "\\yields"; - case "<-": return "\\yieldsLeft"; - case "<->": return "\\mesomerism"; - case "<-->": return "\\yieldsLeftRight"; - case "<=>": return "\\equilibrium"; - case "\u21CC": return "\\equilibrium"; - case "<=>>": return "\\equilibriumRight"; - case "<<=>": return "\\equilibriumLeft"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getBond: function (a) { - switch (a) { - case "-": return "{-}"; - case "1": return "{-}"; - case "=": return "{=}"; - case "2": return "{=}"; - case "#": return "{\\equiv}"; - case "3": return "{\\equiv}"; - case "~": return "{\\tripleDash}"; - case "~-": return "{\\tripleDashOverLine}"; - case "~=": return "{\\tripleDashOverDoubleLine}"; - case "~--": return "{\\tripleDashOverDoubleLine}"; - case "-~-": return "{\\tripleDashBetweenDoubleLine}"; - case "...": return "{{\\cdot}{\\cdot}{\\cdot}}"; - case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; - case "->": return "{\\rightarrow}"; - case "<-": return "{\\leftarrow}"; - case "<": return "{<}"; - case ">": return "{>}"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getOperator: function (a) { - switch (a) { - case "+": return " {}+{} "; - case "-": return " {}-{} "; - case "=": return " {}={} "; - case "<": return " {}<{} "; - case ">": return " {}>{} "; - case "<<": return " {}\\ll{} "; - case ">>": return " {}\\gg{} "; - case "\\pm": return " {}\\pm{} "; - case "\\approx": return " {}\\approx{} "; - case "$\\approx$": return " {}\\approx{} "; - case "v": return " \\downarrow{} "; - case "(v)": return " \\downarrow{} "; - case "^": return " \\uparrow{} "; - case "(^)": return " \\uparrow{} "; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - - // - // Helpers for code anaylsis - // Will show type error at calling position - // - /** @param {number} a */ - function assertNever(a) {} - /** @param {string} a */ - function assertString(a) {} - -/* eslint-disable no-undef */ - -////////////////////////////////////////////////////////////////////// -// texvc.sty - -// The texvc package contains macros available in mediawiki pages. -// We omit the functions deprecated at -// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax - -// We also omit texvc's \O, which conflicts with \text{\O} - -defineMacro("\\darr", "\\downarrow"); -defineMacro("\\dArr", "\\Downarrow"); -defineMacro("\\Darr", "\\Downarrow"); -defineMacro("\\lang", "\\langle"); -defineMacro("\\rang", "\\rangle"); -defineMacro("\\uarr", "\\uparrow"); -defineMacro("\\uArr", "\\Uparrow"); -defineMacro("\\Uarr", "\\Uparrow"); -defineMacro("\\N", "\\mathbb{N}"); -defineMacro("\\R", "\\mathbb{R}"); -defineMacro("\\Z", "\\mathbb{Z}"); -defineMacro("\\alef", "\\aleph"); -defineMacro("\\alefsym", "\\aleph"); -defineMacro("\\bull", "\\bullet"); -defineMacro("\\clubs", "\\clubsuit"); -defineMacro("\\cnums", "\\mathbb{C}"); -defineMacro("\\Complex", "\\mathbb{C}"); -defineMacro("\\Dagger", "\\ddagger"); -defineMacro("\\diamonds", "\\diamondsuit"); -defineMacro("\\empty", "\\emptyset"); -defineMacro("\\exist", "\\exists"); -defineMacro("\\harr", "\\leftrightarrow"); -defineMacro("\\hArr", "\\Leftrightarrow"); -defineMacro("\\Harr", "\\Leftrightarrow"); -defineMacro("\\hearts", "\\heartsuit"); -defineMacro("\\image", "\\Im"); -defineMacro("\\infin", "\\infty"); -defineMacro("\\isin", "\\in"); -defineMacro("\\larr", "\\leftarrow"); -defineMacro("\\lArr", "\\Leftarrow"); -defineMacro("\\Larr", "\\Leftarrow"); -defineMacro("\\lrarr", "\\leftrightarrow"); -defineMacro("\\lrArr", "\\Leftrightarrow"); -defineMacro("\\Lrarr", "\\Leftrightarrow"); -defineMacro("\\natnums", "\\mathbb{N}"); -defineMacro("\\plusmn", "\\pm"); -defineMacro("\\rarr", "\\rightarrow"); -defineMacro("\\rArr", "\\Rightarrow"); -defineMacro("\\Rarr", "\\Rightarrow"); -defineMacro("\\real", "\\Re"); -defineMacro("\\reals", "\\mathbb{R}"); -defineMacro("\\Reals", "\\mathbb{R}"); -defineMacro("\\sdot", "\\cdot"); -defineMacro("\\sect", "\\S"); -defineMacro("\\spades", "\\spadesuit"); -defineMacro("\\sub", "\\subset"); -defineMacro("\\sube", "\\subseteq"); -defineMacro("\\supe", "\\supseteq"); -defineMacro("\\thetasym", "\\vartheta"); -defineMacro("\\weierp", "\\wp"); - -/* eslint-disable no-undef */ - -/**************************************************** - * - * physics.js - * - * Implements the Physics Package for LaTeX input. - * - * --------------------------------------------------------------------- - * - * The original version of this file is licensed as follows: - * Copyright (c) 2015-2016 Kolen Cheung . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * --------------------------------------------------------------------- - * - * This file has been revised from the original in the following ways: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \Re and \Im are not used, to avoid conflict with existing LaTeX letters. - * - * This revision of the file is released under the MIT license. - * https://mit-license.org/ - */ -defineMacro("\\quantity", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\qty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\pqty", "{\\left( #1 \\right)}"); -defineMacro("\\bqty", "{\\left[ #1 \\right]}"); -defineMacro("\\vqty", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\Bqty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\absolutevalue", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\abs", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\norm", "{\\left\\Vert #1 \\right\\Vert}"); -defineMacro("\\evaluated", "{\\left.#1 \\right\\vert}"); -defineMacro("\\eval", "{\\left.#1 \\right\\vert}"); -defineMacro("\\order", "{\\mathcal{O} \\left( #1 \\right)}"); -defineMacro("\\commutator", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\comm", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\anticommutator", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\acomm", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\poissonbracket", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\pb", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\vectorbold", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vb", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vectorarrow", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\va", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\vectorunit", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\vu", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\dotproduct", "\\mathbin{\\boldsymbol\\cdot}"); -defineMacro("\\vdot", "{\\boldsymbol\\cdot}"); -defineMacro("\\crossproduct", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cross", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cp", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\gradient", "{\\boldsymbol\\nabla}"); -defineMacro("\\grad", "{\\boldsymbol\\nabla}"); -defineMacro("\\divergence", "{\\grad\\vdot}"); -//defineMacro("\\div", "{\\grad\\vdot}"); Not included in Temml. Conflicts w/LaTeX \div -defineMacro("\\curl", "{\\grad\\cross}"); -defineMacro("\\laplacian", "\\nabla^2"); -defineMacro("\\tr", "{\\operatorname{tr}}"); -defineMacro("\\Tr", "{\\operatorname{Tr}}"); -defineMacro("\\rank", "{\\operatorname{rank}}"); -defineMacro("\\erf", "{\\operatorname{erf}}"); -defineMacro("\\Res", "{\\operatorname{Res}}"); -defineMacro("\\principalvalue", "{\\mathcal{P}}"); -defineMacro("\\pv", "{\\mathcal{P}}"); -defineMacro("\\PV", "{\\operatorname{P.V.}}"); -// Temml does not use the next two lines. They conflict with LaTeX letters. -//defineMacro("\\Re", "{\\operatorname{Re} \\left\\{ #1 \\right\\}}"); -//defineMacro("\\Im", "{\\operatorname{Im} \\left\\{ #1 \\right\\}}"); -defineMacro("\\qqtext", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qq", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qcomma", "{\\text{,}\\quad}"); -defineMacro("\\qc", "{\\text{,}\\quad}"); -defineMacro("\\qcc", "{\\quad\\text{c.c.}\\quad}"); -defineMacro("\\qif", "{\\quad\\text{if}\\quad}"); -defineMacro("\\qthen", "{\\quad\\text{then}\\quad}"); -defineMacro("\\qelse", "{\\quad\\text{else}\\quad}"); -defineMacro("\\qotherwise", "{\\quad\\text{otherwise}\\quad}"); -defineMacro("\\qunless", "{\\quad\\text{unless}\\quad}"); -defineMacro("\\qgiven", "{\\quad\\text{given}\\quad}"); -defineMacro("\\qusing", "{\\quad\\text{using}\\quad}"); -defineMacro("\\qassume", "{\\quad\\text{assume}\\quad}"); -defineMacro("\\qsince", "{\\quad\\text{since}\\quad}"); -defineMacro("\\qlet", "{\\quad\\text{let}\\quad}"); -defineMacro("\\qfor", "{\\quad\\text{for}\\quad}"); -defineMacro("\\qall", "{\\quad\\text{all}\\quad}"); -defineMacro("\\qeven", "{\\quad\\text{even}\\quad}"); -defineMacro("\\qodd", "{\\quad\\text{odd}\\quad}"); -defineMacro("\\qinteger", "{\\quad\\text{integer}\\quad}"); -defineMacro("\\qand", "{\\quad\\text{and}\\quad}"); -defineMacro("\\qor", "{\\quad\\text{or}\\quad}"); -defineMacro("\\qas", "{\\quad\\text{as}\\quad}"); -defineMacro("\\qin", "{\\quad\\text{in}\\quad}"); -defineMacro("\\differential", "{\\text{d}}"); -defineMacro("\\dd", "{\\text{d}}"); -defineMacro("\\derivative", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\dv", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\partialderivative", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}"); -defineMacro("\\variation", "{\\delta}"); -defineMacro("\\var", "{\\delta}"); -defineMacro("\\functionalderivative", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\fdv", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\innerproduct", "{\\left\\langle {#1} \\mid { #2} \\right\\rangle}"); -defineMacro("\\outerproduct", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\dyad", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\ketbra", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\op", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\expectationvalue", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\expval", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\ev", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\matrixelement", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\matrixel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\mel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); - -/** - * This file contains the “gullet” where macros are expanded - * until only non-macro tokens remain. - */ - -// List of commands that act like macros but aren't defined as a macro, -// function, or symbol. Used in `isDefined`. -const implicitCommands = { - "^": true, // Parser.js - _: true, // Parser.js - "\\limits": true, // Parser.js - "\\nolimits": true // Parser.js -}; - -class MacroExpander { - constructor(input, settings, mode) { - this.settings = settings; - this.expansionCount = 0; - this.feed(input); - // Make new global namespace - this.macros = new Namespace(macros, settings.macros); - this.mode = mode; - this.stack = []; // contains tokens in REVERSE order - } - - /** - * Feed a new input string to the same MacroExpander - * (with existing macros etc.). - */ - feed(input) { - this.lexer = new Lexer(input, this.settings); - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - } - - /** - * Start a new group nesting within all namespaces. - */ - beginGroup() { - this.macros.beginGroup(); - } - - /** - * End current group nesting within all namespaces. - */ - endGroup() { - this.macros.endGroup(); - } - - /** - * Returns the topmost token on the stack, without expanding it. - * Similar in behavior to TeX's `\futurelet`. - */ - future() { - if (this.stack.length === 0) { - this.pushToken(this.lexer.lex()); - } - return this.stack[this.stack.length - 1] - } - - /** - * Remove and return the next unexpanded token. - */ - popToken() { - this.future(); // ensure non-empty stack - return this.stack.pop(); - } - - /** - * Add a given token to the token stack. In particular, this get be used - * to put back a token returned from one of the other methods. - */ - pushToken(token) { - this.stack.push(token); - } - - /** - * Append an array of tokens to the token stack. - */ - pushTokens(tokens) { - this.stack.push(...tokens); - } - - /** - * Find an macro argument without expanding tokens and append the array of - * tokens to the token stack. Uses Token as a container for the result. - */ - scanArgument(isOptional) { - let start; - let end; - let tokens; - if (isOptional) { - this.consumeSpaces(); // \@ifnextchar gobbles any space following it - if (this.future().text !== "[") { - return null; - } - start = this.popToken(); // don't include [ in tokens - ({ tokens, end } = this.consumeArg(["]"])); - } else { - ({ tokens, start, end } = this.consumeArg()); - } - - // indicate the end of an argument - this.pushToken(new Token("EOF", end.loc)); - - this.pushTokens(tokens); - return start.range(end, ""); - } - - /** - * Consume all following space tokens, without expansion. - */ - consumeSpaces() { - for (;;) { - const token = this.future(); - if (token.text === " ") { - this.stack.pop(); - } else { - break; - } - } - } - - /** - * Consume an argument from the token stream, and return the resulting array - * of tokens and start/end token. - */ - consumeArg(delims) { - // The argument for a delimited parameter is the shortest (possibly - // empty) sequence of tokens with properly nested {...} groups that is - // followed ... by this particular list of non-parameter tokens. - // The argument for an undelimited parameter is the next nonblank - // token, unless that token is ‘{’, when the argument will be the - // entire {...} group that follows. - const tokens = []; - const isDelimited = delims && delims.length > 0; - if (!isDelimited) { - // Ignore spaces between arguments. As the TeXbook says: - // "After you have said ‘\def\row#1#2{...}’, you are allowed to - // put spaces between the arguments (e.g., ‘\row x n’), because - // TeX doesn’t use single spaces as undelimited arguments." - this.consumeSpaces(); - } - const start = this.future(); - let tok; - let depth = 0; - let match = 0; - do { - tok = this.popToken(); - tokens.push(tok); - if (tok.text === "{") { - ++depth; - } else if (tok.text === "}") { - --depth; - if (depth === -1) { - throw new ParseError("Extra }", tok); - } - } else if (tok.text === "EOF") { - throw new ParseError( - "Unexpected end of input in a macro argument" + - ", expected '" + - (delims && isDelimited ? delims[match] : "}") + - "'", - tok - ); - } - if (delims && isDelimited) { - if ((depth === 0 || (depth === 1 && delims[match] === "{")) && tok.text === delims[match]) { - ++match; - if (match === delims.length) { - // don't include delims in tokens - tokens.splice(-match, match); - break; - } - } else { - match = 0; - } - } - } while (depth !== 0 || isDelimited); - // If the argument found ... has the form ‘{}’, - // ... the outermost braces enclosing the argument are removed - if (start.text === "{" && tokens[tokens.length - 1].text === "}") { - tokens.pop(); - tokens.shift(); - } - tokens.reverse(); // to fit in with stack order - return { tokens, start, end: tok }; - } - - /** - * Consume the specified number of (delimited) arguments from the token - * stream and return the resulting array of arguments. - */ - consumeArgs(numArgs, delimiters) { - if (delimiters) { - if (delimiters.length !== numArgs + 1) { - throw new ParseError("The length of delimiters doesn't match the number of args!"); - } - const delims = delimiters[0]; - for (let i = 0; i < delims.length; i++) { - const tok = this.popToken(); - if (delims[i] !== tok.text) { - throw new ParseError("Use of the macro doesn't match its definition", tok); - } - } - } - - const args = []; - for (let i = 0; i < numArgs; i++) { - args.push(this.consumeArg(delimiters && delimiters[i + 1]).tokens); - } - return args; - } - - /** - * Expand the next token only once if possible. - * - * If the token is expanded, the resulting tokens will be pushed onto - * the stack in reverse order and will be returned as an array, - * also in reverse order. - * - * If not, the next token will be returned without removing it - * from the stack. This case can be detected by a `Token` return value - * instead of an `Array` return value. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty. - * - * Used to implement `expandAfterFuture` and `expandNextToken`. - * - * If expandableOnly, only expandable tokens are expanded and - * an undefined control sequence results in an error. - */ - expandOnce(expandableOnly) { - const topToken = this.popToken(); - const name = topToken.text; - const expansion = !topToken.noexpand ? this._getExpansion(name) : null; - if (expansion == null || (expandableOnly && expansion.unexpandable)) { - if (expandableOnly && expansion == null && name[0] === "\\" && !this.isDefined(name)) { - throw new ParseError("Undefined control sequence: " + name); - } - this.pushToken(topToken); - return topToken; - } - this.expansionCount++; - if (this.expansionCount > this.settings.maxExpand) { - throw new ParseError( - "Too many expansions: infinite loop or " + "need to increase maxExpand setting" - ); - } - let tokens = expansion.tokens; - const args = this.consumeArgs(expansion.numArgs, expansion.delimiters); - if (expansion.numArgs) { - // paste arguments in place of the placeholders - tokens = tokens.slice(); // make a shallow copy - for (let i = tokens.length - 1; i >= 0; --i) { - let tok = tokens[i]; - if (tok.text === "#") { - if (i === 0) { - throw new ParseError("Incomplete placeholder at end of macro body", tok); - } - tok = tokens[--i]; // next token on stack - if (tok.text === "#") { - // ## → # - tokens.splice(i + 1, 1); // drop first # - } else if (/^[1-9]$/.test(tok.text)) { - // replace the placeholder with the indicated argument - tokens.splice(i, 2, ...args[+tok.text - 1]); - } else { - throw new ParseError("Not a valid argument number", tok); - } - } - } - } - // Concatenate expansion onto top of stack. - this.pushTokens(tokens); - return tokens; - } - - /** - * Expand the next token only once (if possible), and return the resulting - * top token on the stack (without removing anything from the stack). - * Similar in behavior to TeX's `\expandafter\futurelet`. - * Equivalent to expandOnce() followed by future(). - */ - expandAfterFuture() { - this.expandOnce(); - return this.future(); - } - - /** - * Recursively expand first token, then return first non-expandable token. - */ - expandNextToken() { - for (;;) { - const expanded = this.expandOnce(); - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (expanded.treatAsRelax) { - expanded.text = "\\relax"; - } - return this.stack.pop(); // === expanded - } - } - - // This pathway is impossible. - throw new Error(); // eslint-disable-line no-unreachable - } - - /** - * Fully expand the given macro name and return the resulting list of - * tokens, or return `undefined` if no such macro is defined. - */ - expandMacro(name) { - return this.macros.has(name) ? this.expandTokens([new Token(name)]) : undefined; - } - - /** - * Fully expand the given token stream and return the resulting list of - * tokens. Note that the input tokens are in reverse order, but the - * output tokens are in forward order. - */ - expandTokens(tokens) { - const output = []; - const oldStackLength = this.stack.length; - this.pushTokens(tokens); - while (this.stack.length > oldStackLength) { - const expanded = this.expandOnce(true); // expand only expandable tokens - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - if (expanded.treatAsRelax) { - // the expansion of \noexpand is the token itself - expanded.noexpand = false; - expanded.treatAsRelax = false; - } - output.push(this.stack.pop()); - } - } - return output; - } - - /** - * Fully expand the given macro name and return the result as a string, - * or return `undefined` if no such macro is defined. - */ - expandMacroAsText(name) { - const tokens = this.expandMacro(name); - if (tokens) { - return tokens.map((token) => token.text).join(""); - } else { - return tokens; - } - } - - /** - * Returns the expanded macro as a reversed array of tokens and a macro - * argument count. Or returns `null` if no such macro. - */ - _getExpansion(name) { - const definition = this.macros.get(name); - if (definition == null) { - // mainly checking for undefined here - return definition; - } - // If a single character has an associated catcode other than 13 - // (active character), then don't expand it. - if (name.length === 1) { - const catcode = this.lexer.catcodes[name]; - if (catcode != null && catcode !== 13) { - return - } - } - const expansion = typeof definition === "function" ? definition(this) : definition; - if (typeof expansion === "string") { - let numArgs = 0; - if (expansion.indexOf("#") !== -1) { - const stripped = expansion.replace(/##/g, ""); - while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { - ++numArgs; - } - } - const bodyLexer = new Lexer(expansion, this.settings); - const tokens = []; - let tok = bodyLexer.lex(); - while (tok.text !== "EOF") { - tokens.push(tok); - tok = bodyLexer.lex(); - } - tokens.reverse(); // to fit in with stack using push and pop - const expanded = { tokens, numArgs }; - return expanded; - } - - return expansion; - } - - /** - * Determine whether a command is currently "defined" (has some - * functionality), meaning that it's a macro (in the current group), - * a function, a symbol, or one of the special commands listed in - * `implicitCommands`. - */ - isDefined(name) { - return ( - this.macros.has(name) || - Object.prototype.hasOwnProperty.call(functions, name ) || - Object.prototype.hasOwnProperty.call(symbols.math, name ) || - Object.prototype.hasOwnProperty.call(symbols.text, name ) || - Object.prototype.hasOwnProperty.call(implicitCommands, name ) - ); - } - - /** - * Determine whether a command is expandable. - */ - isExpandable(name) { - const macro = this.macros.get(name); - return macro != null - ? typeof macro === "string" || typeof macro === "function" || !macro.unexpandable - : Object.prototype.hasOwnProperty.call(functions, name ) && !functions[name].primitive; - } -} - -/* - * This file defines the Unicode scripts and script families that we - * support. To add new scripts or families, just add a new entry to the - * scriptData array below. Adding scripts to the scriptData array allows - * characters from that script to appear in \text{} environments. - */ - -/** - * Each script or script family has a name and an array of blocks. - * Each block is an array of two numbers which specify the start and - * end points (inclusive) of a block of Unicode codepoints. - -/** - * Unicode block data for the families of scripts we support in \text{}. - * Scripts only need to appear here if they do not have font metrics. - */ -const scriptData = [ - { - // Latin characters beyond the Latin-1 characters we have metrics for. - // Needed for Czech, Hungarian and Turkish text, for example. - name: "latin", - blocks: [ - [0x0100, 0x024f], // Latin Extended-A and Latin Extended-B - [0x0300, 0x036f] // Combining Diacritical marks - ] - }, - { - // The Cyrillic script used by Russian and related languages. - // A Cyrillic subset used to be supported as explicitly defined - // symbols in symbols.js - name: "cyrillic", - blocks: [[0x0400, 0x04ff]] - }, - { - // Armenian - name: "armenian", - blocks: [[0x0530, 0x058f]] - }, - { - // The Brahmic scripts of South and Southeast Asia - // Devanagari (0900–097F) - // Bengali (0980–09FF) - // Gurmukhi (0A00–0A7F) - // Gujarati (0A80–0AFF) - // Oriya (0B00–0B7F) - // Tamil (0B80–0BFF) - // Telugu (0C00–0C7F) - // Kannada (0C80–0CFF) - // Malayalam (0D00–0D7F) - // Sinhala (0D80–0DFF) - // Thai (0E00–0E7F) - // Lao (0E80–0EFF) - // Tibetan (0F00–0FFF) - // Myanmar (1000–109F) - name: "brahmic", - blocks: [[0x0900, 0x109f]] - }, - { - name: "georgian", - blocks: [[0x10a0, 0x10ff]] - }, - { - // Chinese and Japanese. - // The "k" in cjk is for Korean, but we've separated Korean out - name: "cjk", - blocks: [ - [0x3000, 0x30ff], // CJK symbols and punctuation, Hiragana, Katakana - [0x4e00, 0x9faf], // CJK ideograms - [0xff00, 0xff60] // Fullwidth punctuation - // TODO: add halfwidth Katakana and Romanji glyphs - ] - }, - { - // Korean - name: "hangul", - blocks: [[0xac00, 0xd7af]] - } -]; - -/** - * A flattened version of all the supported blocks in a single array. - * This is an optimization to make supportedCodepoint() fast. - */ -const allBlocks = []; -scriptData.forEach((s) => s.blocks.forEach((b) => allBlocks.push(...b))); - -/** - * Given a codepoint, return true if it falls within one of the - * scripts or script families defined above and false otherwise. - * - * Micro benchmarks shows that this is faster than - * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() - * in Firefox, Chrome and Node. - */ -function supportedCodepoint(codepoint) { - for (let i = 0; i < allBlocks.length; i += 2) { - if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { - return true; - } - } - return false; -} - -// Helpers for Parser.js handling of Unicode (sub|super)script characters. - -const unicodeSubRegEx = /^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/; - -const uSubsAndSups = Object.freeze({ - '₊': '+', - '₋': '-', - '₌': '=', - '₍': '(', - '₎': ')', - '₀': '0', - '₁': '1', - '₂': '2', - '₃': '3', - '₄': '4', - '₅': '5', - '₆': '6', - '₇': '7', - '₈': '8', - '₉': '9', - '\u2090': 'a', - '\u2091': 'e', - '\u2095': 'h', - '\u1D62': 'i', - '\u2C7C': 'j', - '\u2096': 'k', - '\u2097': 'l', - '\u2098': 'm', - '\u2099': 'n', - '\u2092': 'o', - '\u209A': 'p', - '\u1D63': 'r', - '\u209B': 's', - '\u209C': 't', - '\u1D64': 'u', - '\u1D65': 'v', - '\u2093': 'x', - '\u1D66': 'β', - '\u1D67': 'γ', - '\u1D68': 'ρ', - '\u1D69': '\u03d5', - '\u1D6A': 'χ', - '⁺': '+', - '⁻': '-', - '⁼': '=', - '⁽': '(', - '⁾': ')', - '⁰': '0', - '¹': '1', - '²': '2', - '³': '3', - '⁴': '4', - '⁵': '5', - '⁶': '6', - '⁷': '7', - '⁸': '8', - '⁹': '9', - '\u1D2C': 'A', - '\u1D2E': 'B', - '\u1D30': 'D', - '\u1D31': 'E', - '\u1D33': 'G', - '\u1D34': 'H', - '\u1D35': 'I', - '\u1D36': 'J', - '\u1D37': 'K', - '\u1D38': 'L', - '\u1D39': 'M', - '\u1D3A': 'N', - '\u1D3C': 'O', - '\u1D3E': 'P', - '\u1D3F': 'R', - '\u1D40': 'T', - '\u1D41': 'U', - '\u2C7D': 'V', - '\u1D42': 'W', - '\u1D43': 'a', - '\u1D47': 'b', - '\u1D9C': 'c', - '\u1D48': 'd', - '\u1D49': 'e', - '\u1DA0': 'f', - '\u1D4D': 'g', - '\u02B0': 'h', - '\u2071': 'i', - '\u02B2': 'j', - '\u1D4F': 'k', - '\u02E1': 'l', - '\u1D50': 'm', - '\u207F': 'n', - '\u1D52': 'o', - '\u1D56': 'p', - '\u02B3': 'r', - '\u02E2': 's', - '\u1D57': 't', - '\u1D58': 'u', - '\u1D5B': 'v', - '\u02B7': 'w', - '\u02E3': 'x', - '\u02B8': 'y', - '\u1DBB': 'z', - '\u1D5D': 'β', - '\u1D5E': 'γ', - '\u1D5F': 'δ', - '\u1D60': '\u03d5', - '\u1D61': 'χ', - '\u1DBF': 'θ' -}); - -// Mapping of Unicode accent characters to their LaTeX equivalent in text and -// math mode (when they exist). -var unicodeAccents = { - "\u0301": { text: "\\'", math: "\\acute" }, - "\u0300": { text: "\\`", math: "\\grave" }, - "\u0308": { text: '\\"', math: "\\ddot" }, - "\u0303": { text: "\\~", math: "\\tilde" }, - "\u0304": { text: "\\=", math: "\\bar" }, - "\u0306": { text: "\\u", math: "\\breve" }, - "\u030c": { text: "\\v", math: "\\check" }, - "\u0302": { text: "\\^", math: "\\hat" }, - "\u0307": { text: "\\.", math: "\\dot" }, - "\u030a": { text: "\\r", math: "\\mathring" }, - "\u030b": { text: "\\H" }, - '\u0327': { text: '\\c' } -}; - -var unicodeSymbols = { - "á": "á", - "à": "à", - "ä": "ä", - "ǟ": "ǟ", - "ã": "ã", - "ā": "ā", - "ă": "ă", - "ắ": "ắ", - "ằ": "ằ", - "ẵ": "ẵ", - "ǎ": "ǎ", - "â": "â", - "ấ": "ấ", - "ầ": "ầ", - "ẫ": "ẫ", - "ȧ": "ȧ", - "ǡ": "ǡ", - "å": "å", - "ǻ": "ǻ", - "ḃ": "ḃ", - "ć": "ć", - "č": "č", - "ĉ": "ĉ", - "ċ": "ċ", - "ď": "ď", - "ḋ": "ḋ", - "é": "é", - "è": "è", - "ë": "ë", - "ẽ": "ẽ", - "ē": "ē", - "ḗ": "ḗ", - "ḕ": "ḕ", - "ĕ": "ĕ", - "ě": "ě", - "ê": "ê", - "ế": "ế", - "ề": "ề", - "ễ": "ễ", - "ė": "ė", - "ḟ": "ḟ", - "ǵ": "ǵ", - "ḡ": "ḡ", - "ğ": "ğ", - "ǧ": "ǧ", - "ĝ": "ĝ", - "ġ": "ġ", - "ḧ": "ḧ", - "ȟ": "ȟ", - "ĥ": "ĥ", - "ḣ": "ḣ", - "í": "í", - "ì": "ì", - "ï": "ï", - "ḯ": "ḯ", - "ĩ": "ĩ", - "ī": "ī", - "ĭ": "ĭ", - "ǐ": "ǐ", - "î": "î", - "ǰ": "ǰ", - "ĵ": "ĵ", - "ḱ": "ḱ", - "ǩ": "ǩ", - "ĺ": "ĺ", - "ľ": "ľ", - "ḿ": "ḿ", - "ṁ": "ṁ", - "ń": "ń", - "ǹ": "ǹ", - "ñ": "ñ", - "ň": "ň", - "ṅ": "ṅ", - "ó": "ó", - "ò": "ò", - "ö": "ö", - "ȫ": "ȫ", - "õ": "õ", - "ṍ": "ṍ", - "ṏ": "ṏ", - "ȭ": "ȭ", - "ō": "ō", - "ṓ": "ṓ", - "ṑ": "ṑ", - "ŏ": "ŏ", - "ǒ": "ǒ", - "ô": "ô", - "ố": "ố", - "ồ": "ồ", - "ỗ": "ỗ", - "ȯ": "ȯ", - "ȱ": "ȱ", - "ő": "ő", - "ṕ": "ṕ", - "ṗ": "ṗ", - "ŕ": "ŕ", - "ř": "ř", - "ṙ": "ṙ", - "ś": "ś", - "ṥ": "ṥ", - "š": "š", - "ṧ": "ṧ", - "ŝ": "ŝ", - "ṡ": "ṡ", - "ẗ": "ẗ", - "ť": "ť", - "ṫ": "ṫ", - "ú": "ú", - "ù": "ù", - "ü": "ü", - "ǘ": "ǘ", - "ǜ": "ǜ", - "ǖ": "ǖ", - "ǚ": "ǚ", - "ũ": "ũ", - "ṹ": "ṹ", - "ū": "ū", - "ṻ": "ṻ", - "ŭ": "ŭ", - "ǔ": "ǔ", - "û": "û", - "ů": "ů", - "ű": "ű", - "ṽ": "ṽ", - "ẃ": "ẃ", - "ẁ": "ẁ", - "ẅ": "ẅ", - "ŵ": "ŵ", - "ẇ": "ẇ", - "ẘ": "ẘ", - "ẍ": "ẍ", - "ẋ": "ẋ", - "ý": "ý", - "ỳ": "ỳ", - "ÿ": "ÿ", - "ỹ": "ỹ", - "ȳ": "ȳ", - "ŷ": "ŷ", - "ẏ": "ẏ", - "ẙ": "ẙ", - "ź": "ź", - "ž": "ž", - "ẑ": "ẑ", - "ż": "ż", - "Á": "Á", - "À": "À", - "Ä": "Ä", - "Ǟ": "Ǟ", - "Ã": "Ã", - "Ā": "Ā", - "Ă": "Ă", - "Ắ": "Ắ", - "Ằ": "Ằ", - "Ẵ": "Ẵ", - "Ǎ": "Ǎ", - "Â": "Â", - "Ấ": "Ấ", - "Ầ": "Ầ", - "Ẫ": "Ẫ", - "Ȧ": "Ȧ", - "Ǡ": "Ǡ", - "Å": "Å", - "Ǻ": "Ǻ", - "Ḃ": "Ḃ", - "Ć": "Ć", - "Č": "Č", - "Ĉ": "Ĉ", - "Ċ": "Ċ", - "Ď": "Ď", - "Ḋ": "Ḋ", - "É": "É", - "È": "È", - "Ë": "Ë", - "Ẽ": "Ẽ", - "Ē": "Ē", - "Ḗ": "Ḗ", - "Ḕ": "Ḕ", - "Ĕ": "Ĕ", - "Ě": "Ě", - "Ê": "Ê", - "Ế": "Ế", - "Ề": "Ề", - "Ễ": "Ễ", - "Ė": "Ė", - "Ḟ": "Ḟ", - "Ǵ": "Ǵ", - "Ḡ": "Ḡ", - "Ğ": "Ğ", - "Ǧ": "Ǧ", - "Ĝ": "Ĝ", - "Ġ": "Ġ", - "Ḧ": "Ḧ", - "Ȟ": "Ȟ", - "Ĥ": "Ĥ", - "Ḣ": "Ḣ", - "Í": "Í", - "Ì": "Ì", - "Ï": "Ï", - "Ḯ": "Ḯ", - "Ĩ": "Ĩ", - "Ī": "Ī", - "Ĭ": "Ĭ", - "Ǐ": "Ǐ", - "Î": "Î", - "İ": "İ", - "Ĵ": "Ĵ", - "Ḱ": "Ḱ", - "Ǩ": "Ǩ", - "Ĺ": "Ĺ", - "Ľ": "Ľ", - "Ḿ": "Ḿ", - "Ṁ": "Ṁ", - "Ń": "Ń", - "Ǹ": "Ǹ", - "Ñ": "Ñ", - "Ň": "Ň", - "Ṅ": "Ṅ", - "Ó": "Ó", - "Ò": "Ò", - "Ö": "Ö", - "Ȫ": "Ȫ", - "Õ": "Õ", - "Ṍ": "Ṍ", - "Ṏ": "Ṏ", - "Ȭ": "Ȭ", - "Ō": "Ō", - "Ṓ": "Ṓ", - "Ṑ": "Ṑ", - "Ŏ": "Ŏ", - "Ǒ": "Ǒ", - "Ô": "Ô", - "Ố": "Ố", - "Ồ": "Ồ", - "Ỗ": "Ỗ", - "Ȯ": "Ȯ", - "Ȱ": "Ȱ", - "Ő": "Ő", - "Ṕ": "Ṕ", - "Ṗ": "Ṗ", - "Ŕ": "Ŕ", - "Ř": "Ř", - "Ṙ": "Ṙ", - "Ś": "Ś", - "Ṥ": "Ṥ", - "Š": "Š", - "Ṧ": "Ṧ", - "Ŝ": "Ŝ", - "Ṡ": "Ṡ", - "Ť": "Ť", - "Ṫ": "Ṫ", - "Ú": "Ú", - "Ù": "Ù", - "Ü": "Ü", - "Ǘ": "Ǘ", - "Ǜ": "Ǜ", - "Ǖ": "Ǖ", - "Ǚ": "Ǚ", - "Ũ": "Ũ", - "Ṹ": "Ṹ", - "Ū": "Ū", - "Ṻ": "Ṻ", - "Ŭ": "Ŭ", - "Ǔ": "Ǔ", - "Û": "Û", - "Ů": "Ů", - "Ű": "Ű", - "Ṽ": "Ṽ", - "Ẃ": "Ẃ", - "Ẁ": "Ẁ", - "Ẅ": "Ẅ", - "Ŵ": "Ŵ", - "Ẇ": "Ẇ", - "Ẍ": "Ẍ", - "Ẋ": "Ẋ", - "Ý": "Ý", - "Ỳ": "Ỳ", - "Ÿ": "Ÿ", - "Ỹ": "Ỹ", - "Ȳ": "Ȳ", - "Ŷ": "Ŷ", - "Ẏ": "Ẏ", - "Ź": "Ź", - "Ž": "Ž", - "Ẑ": "Ẑ", - "Ż": "Ż", - "ά": "ά", - "ὰ": "ὰ", - "ᾱ": "ᾱ", - "ᾰ": "ᾰ", - "έ": "έ", - "ὲ": "ὲ", - "ή": "ή", - "ὴ": "ὴ", - "ί": "ί", - "ὶ": "ὶ", - "ϊ": "ϊ", - "ΐ": "ΐ", - "ῒ": "ῒ", - "ῑ": "ῑ", - "ῐ": "ῐ", - "ό": "ό", - "ὸ": "ὸ", - "ύ": "ύ", - "ὺ": "ὺ", - "ϋ": "ϋ", - "ΰ": "ΰ", - "ῢ": "ῢ", - "ῡ": "ῡ", - "ῠ": "ῠ", - "ώ": "ώ", - "ὼ": "ὼ", - "Ύ": "Ύ", - "Ὺ": "Ὺ", - "Ϋ": "Ϋ", - "Ῡ": "Ῡ", - "Ῠ": "Ῠ", - "Ώ": "Ώ", - "Ὼ": "Ὼ" -}; - -/* eslint no-constant-condition:0 */ - -const numberRegEx = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in symbolsOrd.js - -/** - * This file contains the parser used to parse out a TeX expression from the - * input. Since TeX isn't context-free, standard parsers don't work particularly - * well. - * - * The strategy of this parser is as such: - * - * The main functions (the `.parse...` ones) take a position in the current - * parse string to parse tokens from. The lexer (found in Lexer.js, stored at - * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When - * individual tokens are needed at a position, the lexer is called to pull out a - * token, which is then used. - * - * The parser has a property called "mode" indicating the mode that - * the parser is currently in. Currently it has to be one of "math" or - * "text", which denotes whether the current environment is a math-y - * one or a text-y one (e.g. inside \text). Currently, this serves to - * limit the functions which can be used in text mode. - * - * The main functions then return an object which contains the useful data that - * was parsed at its given point, and a new position at the end of the parsed - * data. The main functions can call each other and continue the parsing by - * using the returned position as a new starting point. - * - * There are also extra `.handle...` functions, which pull out some reused - * functionality into self-contained functions. - * - * The functions return ParseNodes. - */ - -class Parser { - constructor(input, settings, isPreamble = false) { - // Start in math mode - this.mode = "math"; - // Create a new macro expander (gullet) and (indirectly via that) also a - // new lexer (mouth) for this parser (stomach, in the language of TeX) - this.gullet = new MacroExpander(input, settings, this.mode); - // Store the settings for use in parsing - this.settings = settings; - // Are we defining a preamble? - this.isPreamble = isPreamble; - // Count leftright depth (for \middle errors) - this.leftrightDepth = 0; - this.prevAtomType = ""; - } - - /** - * Checks a result to make sure it has the right type, and throws an - * appropriate error otherwise. - */ - expect(text, consume = true) { - if (this.fetch().text !== text) { - throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); - } - if (consume) { - this.consume(); - } - } - - /** - * Discards the current lookahead token, considering it consumed. - */ - consume() { - this.nextToken = null; - } - - /** - * Return the current lookahead token, or if there isn't one (at the - * beginning, or if the previous lookahead token was consume()d), - * fetch the next token as the new lookahead token and return it. - */ - fetch() { - if (this.nextToken == null) { - this.nextToken = this.gullet.expandNextToken(); - } - return this.nextToken; - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - this.gullet.switchMode(newMode); - } - - /** - * Main parsing function, which parses an entire input. - */ - parse() { - // Create a group namespace for every $...$, $$...$$, \[...\].) - // A \def is then valid only within that pair of delimiters. - this.gullet.beginGroup(); - - if (this.settings.colorIsTextColor) { - // Use old \color behavior (same as LaTeX's \textcolor) if requested. - // We do this within the group for the math expression, so it doesn't - // pollute settings.macros. - this.gullet.macros.set("\\color", "\\textcolor"); - } - - // Try to parse the input - const parse = this.parseExpression(false); - - // If we succeeded, make sure there's an EOF at the end - this.expect("EOF"); - - if (this.isPreamble) { - const macros = Object.create(null); - Object.entries(this.gullet.macros.current).forEach(([key, value]) => { - macros[key] = value; - }); - this.gullet.endGroup(); - return macros - } - - // The only local macro that we want to save is from \tag. - const tag = this.gullet.macros.get("\\df@tag"); - - // End the group namespace for the expression - this.gullet.endGroup(); - - if (tag) { this.gullet.macros.current["\\df@tag"] = tag; } - - return parse; - } - - static get endOfExpression() { - return ["}", "\\endgroup", "\\end", "\\right", "\\endtoggle", "&"]; - } - - /** - * Parses an "expression", which is a list of atoms. - * - * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This - * happens when functions have higher precendence han infix - * nodes in implicit parses. - * - * `breakOnTokenText`: The text of the token that the expression should end - * with, or `null` if something else should end the - * expression. - */ - parseExpression(breakOnInfix, breakOnTokenText) { - const body = []; - // Keep adding atoms to the body until we can't parse any more atoms (either - // we reached the end, a }, or a \right) - while (true) { - // Ignore spaces in math mode - if (this.mode === "math") { - this.consumeSpaces(); - } - const lex = this.fetch(); - if (Parser.endOfExpression.indexOf(lex.text) !== -1) { - break; - } - if (breakOnTokenText && lex.text === breakOnTokenText) { - break; - } - if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { - break; - } - const atom = this.parseAtom(breakOnTokenText); - if (!atom) { - break; - } else if (atom.type === "internal") { - continue; - } - body.push(atom); - // Keep a record of the atom type, so that op.js can set correct spacing. - this.prevAtomType = atom.type === "atom" ? atom.family : atom.type; - } - if (this.mode === "text") { - this.formLigatures(body); - } - return this.handleInfixNodes(body); - } - - /** - * Rewrites infix operators such as \over with corresponding commands such - * as \frac. - * - * There can only be one infix operator per group. If there's more than one - * then the expression is ambiguous. This can be resolved by adding {}. - */ - handleInfixNodes(body) { - let overIndex = -1; - let funcName; - - for (let i = 0; i < body.length; i++) { - if (body[i].type === "infix") { - if (overIndex !== -1) { - throw new ParseError("only one infix operator per group", body[i].token); - } - overIndex = i; - funcName = body[i].replaceWith; - } - } - - if (overIndex !== -1 && funcName) { - let numerNode; - let denomNode; - - const numerBody = body.slice(0, overIndex); - const denomBody = body.slice(overIndex + 1); - - if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { - numerNode = numerBody[0]; - } else { - numerNode = { type: "ordgroup", mode: this.mode, body: numerBody }; - } - - if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { - denomNode = denomBody[0]; - } else { - denomNode = { type: "ordgroup", mode: this.mode, body: denomBody }; - } - - let node; - if (funcName === "\\\\abovefrac") { - node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); - } else { - node = this.callFunction(funcName, [numerNode, denomNode], []); - } - return [node]; - } else { - return body; - } - } - - /** - * Handle a subscript or superscript with nice errors. - */ - handleSupSubscript( - name // For error reporting. - ) { - const symbolToken = this.fetch(); - const symbol = symbolToken.text; - this.consume(); - this.consumeSpaces(); // ignore spaces before sup/subscript argument - const group = this.parseGroup(name); - - if (!group) { - throw new ParseError("Expected group after '" + symbol + "'", symbolToken); - } - - return group; - } - - /** - * Converts the textual input of an unsupported command into a text node - * contained within a color node whose color is determined by errorColor - */ - formatUnsupportedCmd(text) { - const textordArray = []; - - for (let i = 0; i < text.length; i++) { - textordArray.push({ type: "textord", mode: "text", text: text[i] }); - } - - const textNode = { - type: "text", - mode: this.mode, - body: textordArray - }; - - const colorNode = { - type: "color", - mode: this.mode, - color: this.settings.errorColor, - body: [textNode] - }; - - return colorNode; - } - - /** - * Parses a group with optional super/subscripts. - */ - parseAtom(breakOnTokenText) { - // The body of an atom is an implicit group, so that things like - // \left(x\right)^2 work correctly. - const base = this.parseGroup("atom", breakOnTokenText); - - // In text mode, we don't have superscripts or subscripts - if (this.mode === "text") { - return base; - } - - // Note that base may be empty (i.e. null) at this point. - - let superscript; - let subscript; - while (true) { - // Guaranteed in math mode, so eat any spaces first. - this.consumeSpaces(); - - // Lex the first token - const lex = this.fetch(); - - if (lex.text === "\\limits" || lex.text === "\\nolimits") { - // We got a limit control - if (base && base.type === "op") { - const limits = lex.text === "\\limits"; - base.limits = limits; - base.alwaysHandleSupSub = true; - } else if (base && base.type === "operatorname") { - if (base.alwaysHandleSupSub) { - base.limits = lex.text === "\\limits"; - } - } else { - throw new ParseError("Limit controls must follow a math operator", lex); - } - this.consume(); - } else if (lex.text === "^") { - // We got a superscript start - if (superscript) { - throw new ParseError("Double superscript", lex); - } - superscript = this.handleSupSubscript("superscript"); - } else if (lex.text === "_") { - // We got a subscript start - if (subscript) { - throw new ParseError("Double subscript", lex); - } - subscript = this.handleSupSubscript("subscript"); - } else if (lex.text === "'") { - // We got a prime - if (superscript) { - throw new ParseError("Double superscript", lex); - } - const prime = { type: "textord", mode: this.mode, text: "\\prime" }; - - // Many primes can be grouped together, so we handle this here - const primes = [prime]; - this.consume(); - // Keep lexing tokens until we get something that's not a prime - while (this.fetch().text === "'") { - // For each one, add another prime to the list - primes.push(prime); - this.consume(); - } - // If there's a superscript following the primes, combine that - // superscript in with the primes. - if (this.fetch().text === "^") { - primes.push(this.handleSupSubscript("superscript")); - } - // Put everything into an ordgroup as the superscript - superscript = { type: "ordgroup", mode: this.mode, body: primes }; - } else if (uSubsAndSups[lex.text]) { - // A Unicode subscript or superscript character. - // We treat these similarly to the unicode-math package. - // So we render a string of Unicode (sub|super)scripts the - // same as a (sub|super)script of regular characters. - let str = uSubsAndSups[lex.text]; - const isSub = unicodeSubRegEx.test(lex.text); - this.consume(); - // Continue fetching tokens to fill out the string. - while (true) { - const token = this.fetch().text; - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - this.consume(); - str += uSubsAndSups[token]; - } - // Now create a (sub|super)script. - const body = (new Parser(str, this.settings)).parse(); - if (isSub) { - subscript = { type: "ordgroup", mode: "math", body }; - } else { - superscript = { type: "ordgroup", mode: "math", body }; - } - } else { - // If it wasn't ^, _, a Unicode (sub|super)script, or ', stop parsing super/subscripts - break; - } - } - - if (superscript || subscript) { - if (base && base.type === "multiscript" && !base.postscripts) { - // base is the result of a \prescript function. - // Write the sub- & superscripts into the multiscript element. - base.postscripts = { sup: superscript, sub: subscript }; - return base - } else { - // We got either a superscript or subscript, create a supsub - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript - } - } - } else { - // Otherwise return the original body - return base; - } - } - - /** - * Parses an entire function, including its base and all of its arguments. - */ - parseFunction( - breakOnTokenText, - name // For determining its context - ) { - const token = this.fetch(); - const func = token.text; - const funcData = functions[func]; - if (!funcData) { - return null; - } - this.consume(); // consume command token - - if (name && name !== "atom" && !funcData.allowedInArgument) { - throw new ParseError( - "Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), - token - ); - } else if (this.mode === "text" && !funcData.allowedInText) { - throw new ParseError("Can't use function '" + func + "' in text mode", token); - } else if (this.mode === "math" && funcData.allowedInMath === false) { - throw new ParseError("Can't use function '" + func + "' in math mode", token); - } - - const prevAtomType = this.prevAtomType; - const { args, optArgs } = this.parseArguments(func, funcData); - this.prevAtomType = prevAtomType; - return this.callFunction(func, args, optArgs, token, breakOnTokenText); - } - - /** - * Call a function handler with a suitable context and arguments. - */ - callFunction(name, args, optArgs, token, breakOnTokenText) { - const context = { - funcName: name, - parser: this, - token, - breakOnTokenText - }; - const func = functions[name]; - if (func && func.handler) { - return func.handler(context, args, optArgs); - } else { - throw new ParseError(`No function handler for ${name}`); - } - } - - /** - * Parses the arguments of a function or environment - */ - parseArguments( - func, // Should look like "\name" or "\begin{name}". - funcData - ) { - const totalArgs = funcData.numArgs + funcData.numOptionalArgs; - if (totalArgs === 0) { - return { args: [], optArgs: [] }; - } - - const args = []; - const optArgs = []; - - for (let i = 0; i < totalArgs; i++) { - let argType = funcData.argTypes && funcData.argTypes[i]; - const isOptional = i < funcData.numOptionalArgs; - - if ( - (funcData.primitive && argType == null) || - // \sqrt expands into primitive if optional argument doesn't exist - (funcData.type === "sqrt" && i === 1 && optArgs[0] == null) - ) { - argType = "primitive"; - } - - const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional); - if (isOptional) { - optArgs.push(arg); - } else if (arg != null) { - args.push(arg); - } else { - // should be unreachable - throw new ParseError("Null argument, please report this as a bug"); - } - } - - return { args, optArgs }; - } - - /** - * Parses a group when the mode is changing. - */ - parseGroupOfType(name, type, optional) { - switch (type) { - case "size": - return this.parseSizeGroup(optional); - case "url": - return this.parseUrlGroup(optional); - case "math": - case "text": - return this.parseArgumentGroup(optional, type); - case "hbox": { - // hbox argument type wraps the argument in the equivalent of - // \hbox, which is like \text but switching to \textstyle size. - const group = this.parseArgumentGroup(optional, "text"); - return group != null - ? { - type: "styling", - mode: group.mode, - body: [group], - scriptLevel: "text" // simulate \textstyle - } - : null; - } - case "raw": { - const token = this.parseStringGroup("raw", optional); - return token != null - ? { - type: "raw", - mode: "text", - string: token.text - } - : null; - } - case "primitive": { - if (optional) { - throw new ParseError("A primitive argument cannot be optional"); - } - const group = this.parseGroup(name); - if (group == null) { - throw new ParseError("Expected group as " + name, this.fetch()); - } - return group; - } - case "original": - case null: - case undefined: - return this.parseArgumentGroup(optional); - default: - throw new ParseError("Unknown group type as " + name, this.fetch()); - } - } - - /** - * Discard any space tokens, fetching the next non-space token. - */ - consumeSpaces() { - while (this.fetch().text === " ") { - this.consume(); - } - } - - /** - * Parses a group, essentially returning the string formed by the - * brace-enclosed tokens plus some position information. - */ - parseStringGroup( - modeName, // Used to describe the mode in error messages. - optional - ) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF") { - str += nextToken.text; - this.consume(); - } - this.consume(); // consume the end of the argument - argToken.text = str; - return argToken; - } - - /** - * Parses a regex-delimited group: the largest sequence of tokens - * whose concatenated strings match `regex`. Returns the string - * formed by the tokens plus some position information. - */ - parseRegexGroup( - regex, - modeName // Used to describe the mode in error messages. - ) { - const firstToken = this.fetch(); - let lastToken = firstToken; - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { - lastToken = nextToken; - str += lastToken.text; - this.consume(); - } - if (str === "") { - throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); - } - return firstToken.range(lastToken, str); - } - - /** - * Parses a size specification, consisting of magnitude and unit. - */ - parseSizeGroup(optional) { - let res; - let isBlank = false; - // don't expand before parseStringGroup - this.gullet.consumeSpaces(); - if (!optional && this.gullet.future().text !== "{") { - res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); - } else { - res = this.parseStringGroup("size", optional); - } - if (!res) { - return null; - } - if (!optional && res.text.length === 0) { - // Because we've tested for what is !optional, this block won't - // affect \kern, \hspace, etc. It will capture the mandatory arguments - // to \genfrac and \above. - res.text = "0pt"; // Enable \above{} - isBlank = true; // This is here specifically for \genfrac - } - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); - if (!match) { - throw new ParseError("Invalid size: '" + res.text + "'", res); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "'", res); - } - return { - type: "size", - mode: this.mode, - value: data, - isBlank - }; - } - - /** - * Parses an URL, checking escaped letters and allowed protocols, - * and setting the catcode of % as an active character (as in \hyperref). - */ - parseUrlGroup(optional) { - this.gullet.lexer.setCatcode("%", 13); // active character - this.gullet.lexer.setCatcode("~", 12); // other character - const res = this.parseStringGroup("url", optional); - this.gullet.lexer.setCatcode("%", 14); // comment character - this.gullet.lexer.setCatcode("~", 13); // active character - if (res == null) { - return null; - } - // hyperref package allows backslashes alone in href, but doesn't - // generate valid links in such cases; we interpret this as - // "undefined" behaviour, and keep them as-is. Some browser will - // replace backslashes with forward slashes. - let url = res.text.replace(/\\([#$%&~_^{}])/g, "$1"); - url = res.text.replace(/{\u2044}/g, "/"); - return { - type: "url", - mode: this.mode, - url - }; - } - - /** - * Parses an argument with the mode specified. - */ - parseArgumentGroup(optional, mode) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - const outerMode = this.mode; - if (mode) { - // Switch to specified mode - this.switchMode(mode); - } - - this.gullet.beginGroup(); - const expression = this.parseExpression(false, "EOF"); - // TODO: find an alternative way to denote the end - this.expect("EOF"); // expect the end of the argument - this.gullet.endGroup(); - const result = { - type: "ordgroup", - mode: this.mode, - loc: argToken.loc, - body: expression - }; - - if (mode) { - // Switch mode back - this.switchMode(outerMode); - } - return result; - } - - /** - * Parses an ordinary group, which is either a single nucleus (like "x") - * or an expression in braces (like "{x+y}") or an implicit group, a group - * that starts at the current position, and ends right before a higher explicit - * group ends, or at EOF. - */ - parseGroup( - name, // For error reporting. - breakOnTokenText - ) { - const firstToken = this.fetch(); - const text = firstToken.text; - - let result; - // Try to parse an open brace or \begingroup - if (text === "{" || text === "\\begingroup" || text === "\\toggle") { - this.consume(); - const groupEnd = text === "{" - ? "}" - : text === "\\begingroup" - ? "\\endgroup" - : "\\endtoggle"; - - this.gullet.beginGroup(); - // If we get a brace, parse an expression - const expression = this.parseExpression(false, groupEnd); - const lastToken = this.fetch(); - this.expect(groupEnd); // Check that we got a matching closing brace - this.gullet.endGroup(); - result = { - type: (lastToken.text === "\\endtoggle" ? "toggle" : "ordgroup"), - mode: this.mode, - loc: SourceLocation.range(firstToken, lastToken), - body: expression, - // A group formed by \begingroup...\endgroup is a semi-simple group - // which doesn't affect spacing in math mode, i.e., is transparent. - // https://tex.stackexchange.com/questions/1930/when-should-one- - // use-begingroup-instead-of-bgroup - semisimple: text === "\\begingroup" || undefined - }; - } else { - // If there exists a function with this name, parse the function. - // Otherwise, just return a nucleus - result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol(); - if (result == null && text[0] === "\\" && - !Object.prototype.hasOwnProperty.call(implicitCommands, text )) { - result = this.formatUnsupportedCmd(text); - this.consume(); - } - } - return result; - } - - /** - * Form ligature-like combinations of characters for text mode. - * This includes inputs like "--", "---", "``" and "''". - * The result will simply replace multiple textord nodes with a single - * character in each value by a single textord node having multiple - * characters in its value. The representation is still ASCII source. - * The group will be modified in place. - */ - formLigatures(group) { - let n = group.length - 1; - for (let i = 0; i < n; ++i) { - const a = group[i]; - const v = a.text; - if (v === "-" && group[i + 1].text === "-") { - if (i + 1 < n && group[i + 2].text === "-") { - group.splice(i, 3, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 2]), - text: "---" - }); - n -= 2; - } else { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: "--" - }); - n -= 1; - } - } - if ((v === "'" || v === "`") && group[i + 1].text === v) { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: v + v - }); - n -= 1; - } - } - } - - /** - * Parse a single symbol out of the string. Here, we handle single character - * symbols and special functions like \verb. - */ - parseSymbol() { - const nucleus = this.fetch(); - let text = nucleus.text; - - if (/^\\verb[^a-zA-Z]/.test(text)) { - this.consume(); - let arg = text.slice(5); - const star = arg.charAt(0) === "*"; - if (star) { - arg = arg.slice(1); - } - // Lexer's tokenRegex is constructed to always have matching - // first/last characters. - if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { - throw new ParseError(`\\verb assertion failed -- - please report what input caused this bug`); - } - arg = arg.slice(1, -1); // remove first and last char - return { - type: "verb", - mode: "text", - body: arg, - star - }; - } - // At this point, we should have a symbol, possibly with accents. - // First expand any accented base symbol according to unicodeSymbols. - if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0]) && - !symbols[this.mode][text[0]]) { - // This behavior is not strict (XeTeX-compatible) in math mode. - if (this.settings.strict && this.mode === "math") { - throw new ParseError(`Accented Unicode text character "${text[0]}" used in ` + `math mode`, - nucleus - ); - } - text = unicodeSymbols[text[0]] + text.slice(1); - } - // Strip off any combining characters - const match = combiningDiacriticalMarksEndRegex.exec(text); - if (match) { - text = text.substring(0, match.index); - if (text === "i") { - text = "\u0131"; // dotless i, in math and text mode - } else if (text === "j") { - text = "\u0237"; // dotless j, in math and text mode - } - } - // Recognize base symbol - let symbol; - if (symbols[this.mode][text]) { - const group = symbols[this.mode][text].group; - const loc = SourceLocation.range(nucleus); - let s; - if (Object.prototype.hasOwnProperty.call(ATOMS, group )) { - const family = group; - s = { - type: "atom", - mode: this.mode, - family, - loc, - text - }; - } else { - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (!this.strict && numberRegEx.test(text)) { - // A number. Wrap in a if in math mode; otherwise. - this.consume(); - return { - type: "textord", - mode: this.mode, - loc: SourceLocation.range(nucleus), - text - } - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict) { - if (!supportedCodepoint(text.charCodeAt(0))) { - throw new ParseError(`Unrecognized Unicode character "${text[0]}"` + - ` (${text.charCodeAt(0)})`, nucleus); - } else if (this.mode === "math") { - throw new ParseError(`Unicode text character "${text[0]}" used in math mode`, nucleus) - } - } - // All nonmathematical Unicode characters are rendered as if they - // are in text mode (wrapped in \text) because that's what it - // takes to render them in LaTeX. - symbol = { - type: "textord", - mode: "text", - loc: SourceLocation.range(nucleus), - text - }; - } else { - return null; // EOF, ^, _, {, }, etc. - } - this.consume(); - // Transform combining characters into accents - if (match) { - for (let i = 0; i < match[0].length; i++) { - const accent = match[0][i]; - if (!unicodeAccents[accent]) { - throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); - } - const command = unicodeAccents[accent][this.mode] || - unicodeAccents[accent].text; - if (!command) { - throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); - } - symbol = { - type: "accent", - mode: this.mode, - loc: SourceLocation.range(nucleus), - label: command, - isStretchy: false, - isShifty: true, - base: symbol - }; - } - } - return symbol; - } -} - -/** - * Parses an expression using a Parser, then returns the parsed result. - */ -const parseTree = function(toParse, settings) { - if (!(typeof toParse === "string" || toParse instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(toParse, settings); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - - let tree = parser.parse(); - - // LaTeX ignores a \tag placed outside an AMS environment. - if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) { - // If the input used \tag, it will set the \df@tag macro to the tag. - // In this case, we separately parse the tag and wrap the tree. - if (parser.gullet.macros.get("\\df@tag")) { - if (!settings.displayMode) { - throw new ParseError("\\tag works only in display mode") - } - parser.gullet.feed("\\df@tag"); - tree = [ - { - type: "tag", - mode: "text", - body: tree, - tag: parser.parse() - } - ]; - } - } - - return tree -}; - -/** - * This file contains information about the style that the mathmlBuilder carries - * around with it. Data is held in an `Style` object, and when - * recursing, a new `Style` object can be created with the `.with*` functions. - */ - -const subOrSupLevel = [2, 2, 3, 3]; - -/** - * This is the main Style class. It contains the current style.level, color, and font. - * - * Style objects should not be modified. To create a new Style with - * different properties, call a `.with*` method. - */ -class Style { - constructor(data) { - // Style.level can be 0 | 1 | 2 | 3, which correspond to - // displaystyle, textstyle, scriptstyle, and scriptscriptstyle. - // style.level does not directly set MathML's script level. MathML does that itself. - // We use style.level to track, not set, math style so that we can get the - // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em. - this.level = data.level; - this.color = data.color; // string | void - // A font family applies to a group of fonts (i.e. SansSerif), while a font - // represents a specific font (i.e. SansSerif Bold). - // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm - this.font = data.font || ""; // string - this.fontFamily = data.fontFamily || ""; // string - this.fontSize = data.fontSize || 1.0; // number - this.fontWeight = data.fontWeight || ""; - this.fontShape = data.fontShape || ""; - this.maxSize = data.maxSize; // [number, number] - } - - /** - * Returns a new style object with the same properties as "this". Properties - * from "extension" will be copied to the new style object. - */ - extend(extension) { - const data = { - level: this.level, - color: this.color, - font: this.font, - fontFamily: this.fontFamily, - fontSize: this.fontSize, - fontWeight: this.fontWeight, - fontShape: this.fontShape, - maxSize: this.maxSize - }; - - for (const key in extension) { - if (Object.prototype.hasOwnProperty.call(extension, key)) { - data[key] = extension[key]; - } - } - - return new Style(data); - } - - withLevel(n) { - return this.extend({ - level: n - }); - } - - incrementLevel() { - return this.extend({ - level: Math.min(this.level + 1, 3) - }); - } - - inSubOrSup() { - return this.extend({ - level: subOrSupLevel[this.level] - }) - } - - /** - * Create a new style object with the given color. - */ - withColor(color) { - return this.extend({ - color: color - }); - } - - /** - * Creates a new style object with the given math font or old text font. - * @type {[type]} - */ - withFont(font) { - return this.extend({ - font - }); - } - - /** - * Create a new style objects with the given fontFamily. - */ - withTextFontFamily(fontFamily) { - return this.extend({ - fontFamily, - font: "" - }); - } - - /** - * Creates a new style object with the given font size - */ - withFontSize(num) { - return this.extend({ - fontSize: num - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontWeight(fontWeight) { - return this.extend({ - fontWeight, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontShape(fontShape) { - return this.extend({ - fontShape, - font: "" - }); - } - - /** - * Gets the CSS color of the current style object - */ - getColor() { - return this.color; - } -} - -/* Temml Post Process - * Perform two tasks not done by Temml when it created each individual Temml element. - * Given a block of block, - * 1. At each AMS auto-numbered environment, assign an id. - * 2. Populate the text contents of each \ref & \eqref - * - * As with other Temml code, this file is released under terms of the MIT license. - * https://mit-license.org/ - */ - -const version = "0.6.9"; - -function postProcess(block) { - const labelMap = {}; - let i = 0; - - // Get a collection of the parents of each \tag & auto-numbered equation - const parents = block.getElementsByClassName("tml-tageqn"); - for (const parent of parents) { - const eqns = parent.getElementsByClassName("tml-eqn"); - if (eqns. length > 0 ) { - // AMS automatically numbered equation. - // Assign an id. - i += 1; - eqns[0].id = "tml-eqn-" + i; - // No need to write a number into the text content of the element. - // A CSS counter does that even if this postProcess() function is not used. - } - // If there is a \label, add it to labelMap - const labels = parent.getElementsByClassName("tml-label"); - if (labels.length === 0) { continue } - if (eqns.length > 0) { - labelMap[labels[0].id] = String(i); - } else { - const tags = parent.getElementsByClassName("tml-tag"); - if (tags.length > 0) { - labelMap[labels[0].id] = tags[0].textContent; - } - } - } - - // Populate \ref & \eqref text content - const refs = block.getElementsByClassName("tml-ref"); - [...refs].forEach(ref => { - let str = labelMap[ref.getAttribute("href").slice(1)]; - if (ref.className.indexOf("tml-eqref") === -1) { - // \ref. Omit parens. - str = str.replace(/^\(/, ""); - str = str.replace(/\($/, ""); - } { - // \eqref. Include parens - if (str.charAt(0) !== "(") { str = "(" + str; } - if (str.slice(-1) !== ")") { str = str + ")"; } - } - ref.textContent = str; - }); -} - -/* eslint no-console:0 */ - -/** - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options) { - baseNode.textContent = ""; - const math = renderToMathMLTree(expression, options); - if (options.elementIsMath) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else { - baseNode.appendChild(math.toNode()); - } -}; - -// Temml's styles don't work properly in quirks mode. Print out an error, and -// disable rendering. -if (typeof document !== "undefined") { - if (document.compatMode !== "CSS1Compat") { - typeof console !== "undefined" && - console.warn( - "Warning: Temml doesn't work in quirks mode. Make sure your " + - "website has a suitable doctype." - ); - - render = function() { - throw new ParseError("Temml doesn't work in quirks mode."); - }; - } -} - -/** - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * Take an expression which contains a preamble. - * Parse it and return the macros. - */ -const definePreamble = function(expression, options) { - const settings = new Settings(options); - settings.macros = {}; - if (!(typeof expression === "string" || expression instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(expression, settings, true); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - const macros = parser.parse(); - return macros -}; - -/** - * If the given error is a Temml ParseError, - * renders the invalid LaTeX as a span with hover title giving the Temml - * error message. Otherwise, simply throws the error. - */ -const renderError = function(error, expression, options) { - if (options.throwOnError || !(error instanceof ParseError)) { - throw error; - } - const node = new Span(["temml-error"], [new TextNode$1(expression + "\n" + error.toString())]); - node.style.color = options.errorColor; - node.style.whiteSpace = "pre-line"; - return node; -}; - -/** - * Generates and returns the Temml build tree. This is used for advanced - * use cases (like rendering to custom output). - */ -const renderToMathMLTree = function(expression, options) { - const settings = new Settings(options); - try { - const tree = parseTree(expression, settings); - const style = new Style({ - level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT, - maxSize: settings.maxSize - }); - return buildMathML(tree, expression, style, settings); - } catch (error) { - return renderError(error, expression, settings); - } -}; - -var temml = { - /** - * Current Temml version - */ - version: version, - /** - * Renders the given LaTeX into MathML, and adds - * it as a child to the specified DOM node. - */ - render, - /** - * Renders the given LaTeX into MathML string, - * for sending to the client. - */ - renderToString, - /** - * Post-process an entire HTML block. - * Writes AMS auto-numbers and implements \ref{}. - * Typcally called once, after a loop has rendered many individual spans. - */ - postProcess, - /** - * Temml error, usually during parsing. - */ - ParseError, - /** - * Creates a set of macros with document-wide scope. - */ - definePreamble, - /** - * Parses the given LaTeX into Temml's internal parse tree structure, - * without rendering to HTML or MathML. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __parse: generateParseTree, - /** - * Renders the given LaTeX into a MathML internal DOM tree - * representation, without flattening that representation to a string. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __renderToMathMLTree: renderToMathMLTree, - /** - * adds a new symbol to builtin symbols table - */ - __defineSymbol: defineSymbol, - /** - * adds a new macro to builtin macro list - */ - __defineMacro: defineMacro -}; - -module.exports = temml; diff --git a/utils/temml.cjs.js b/utils/temml.cjs.js deleted file mode 100644 index 7423c084..00000000 --- a/utils/temml.cjs.js +++ /dev/null @@ -1,13022 +0,0 @@ -'use strict'; - -/** - * This is the ParseError class, which is the main error thrown by Temml - * functions when something has gone wrong. This is used to distinguish internal - * errors from errors in the expression that the user provided. - * - * If possible, a caller should provide a Token or ParseNode with information - * about where in the source string the problem occurred. - */ -class ParseError { - constructor( - message, // The error message - token // An object providing position information - ) { - let error = " " + message; - let start; - - const loc = token && token.loc; - if (loc && loc.start <= loc.end) { - // If we have the input and a position, make the error a bit fancier - - // Get the input - const input = loc.lexer.input; - - // Prepend some information - start = loc.start; - const end = loc.end; - if (start === input.length) { - error += " at end of input: "; - } else { - error += " at position " + (start + 1) + ": "; - } - - // Underline token in question using combining underscores - const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); - - // Extract some context from the input and add it to the error - let left; - if (start > 15) { - left = "…" + input.slice(start - 15, start); - } else { - left = input.slice(0, start); - } - let right; - if (end + 15 < input.length) { - right = input.slice(end, end + 15) + "…"; - } else { - right = input.slice(end); - } - error += left + underlined + right; - } - - // Some hackery to make ParseError a prototype of Error - // See http://stackoverflow.com/a/8460753 - const self = new Error(error); - self.name = "TemmlParseError"; - self.__proto__ = ParseError.prototype; - self.position = start; - return self; - } -} - -ParseError.prototype.__proto__ = Error.prototype; - -// -/** - * This file contains a list of utility functions which are useful in other - * files. - */ - -/** - * Return whether an element is contained in a list - */ -const contains = function(list, elem) { - return list.indexOf(elem) !== -1; -}; - -/** - * Provide a default value if a setting is undefined - */ -const deflt = function(setting, defaultIfUndefined) { - return setting === undefined ? defaultIfUndefined : setting; -}; - -// hyphenate and escape adapted from Facebook's React under Apache 2 license - -const uppercase = /([A-Z])/g; -const hyphenate = function(str) { - return str.replace(uppercase, "-$1").toLowerCase(); -}; - -const ESCAPE_LOOKUP = { - "&": "&", - ">": ">", - "<": "<", - '"': """, - "'": "'" -}; - -const ESCAPE_REGEX = /[&><"']/g; - -/** - * Escapes text to prevent scripting attacks. - */ -function escape(text) { - return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); -} - -/** - * Sometimes we want to pull out the innermost element of a group. In most - * cases, this will just be the group itself, but when ordgroups and colors have - * a single element, we want to pull that out. - */ -const getBaseElem = function(group) { - if (group.type === "ordgroup") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "color") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "font") { - return getBaseElem(group.body); - } else { - return group; - } -}; - -/** - * TeXbook algorithms often reference "character boxes", which are simply groups - * with a single character in them. To decide if something is a character box, - * we find its innermost group, and see if it is a single character. - */ -const isCharacterBox = function(group) { - const baseElem = getBaseElem(group); - - // These are all the types of groups which hold single characters - return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom" -}; - -const assert = function(value) { - if (!value) { - throw new Error("Expected non-null, but got " + String(value)); - } - return value; -}; - -/** - * Return the protocol of a URL, or "_relative" if the URL does not specify a - * protocol (and thus is relative). - */ -const protocolFromUrl = function(url) { - const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); - return protocol != null ? protocol[1] : "_relative"; -}; - -/** - * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook - * gives an acceptable rounding error of 100sp (which would be the nearest - * 1/6551.6em with our ptPerEm = 10): - * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69 - */ -const round = function(n) { - return +n.toFixed(4); -}; - -var utils = { - contains, - deflt, - escape, - hyphenate, - getBaseElem, - isCharacterBox, - protocolFromUrl, - round -}; - -/** - * This is a module for storing settings passed into Temml. It correctly handles - * default settings. - */ - -/** - * The main Settings object - */ -class Settings { - constructor(options) { - // allow null options - options = options || {}; - this.displayMode = utils.deflt(options.displayMode, false); // boolean - this.annotate = utils.deflt(options.annotate, false); // boolean - this.elementIsMath = utils.deflt(options.elementIsMath, false); // boolean - this.leqno = utils.deflt(options.leqno, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.preventTagLap = utils.deflt(options.preventTagLap, false); // boolean - this.macros = options.macros || {}; - this.xml = utils.deflt(options.xml, false); // boolean - this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean - this.strict = utils.deflt(options.strict, false); // boolean - this.trust = utils.deflt(options.trust, false); // trust context. See html.js. - this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity)); // number - this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number - } - - /** - * Report nonstrict (non-LaTeX-compatible) input. - * Can safely not be called if `this.strict` is false in JavaScript. - */ - reportNonstrict(errorCode, errorMsg, token) { - const strict = this.strict; - if (strict === false) { - return; - } else if (strict === true) { - throw new ParseError( - "LaTeX-incompatible input and strict mode is set to 'error': " + - `${errorMsg} [${errorCode}]`, - token - ); - } else { - // won't happen in type-safe code - return; - } - } - - /** - * Check whether to test potentially dangerous input, and return - * `true` (trusted) or `false` (untrusted). The sole argument `context` - * should be an object with `command` field specifying the relevant LaTeX - * command (as a string starting with `\`), and any other arguments, etc. - * If `context` has a `url` field, a `protocol` field will automatically - * get added by this function (changing the specified object). - */ - isTrusted(context) { - if (context.url && !context.protocol) { - context.protocol = utils.protocolFromUrl(context.url); - } - const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; - return Boolean(trust); - } -} - -/** - * All registered functions. - * `functions.js` just exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary. - */ -const _functions = {}; - -/** - * All MathML builders. Should be only used in the `define*` and the `build*ML` - * functions. - */ -const _mathmlGroupBuilders = {}; - -function defineFunction({ - type, - names, - props, - handler, - mathmlBuilder -}) { - // Set default values of functions - const data = { - type, - numArgs: props.numArgs, - argTypes: props.argTypes, - allowedInArgument: !!props.allowedInArgument, - allowedInText: !!props.allowedInText, - allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, - numOptionalArgs: props.numOptionalArgs || 0, - infix: !!props.infix, - primitive: !!props.primitive, - handler: handler - }; - for (let i = 0; i < names.length; ++i) { - _functions[names[i]] = data; - } - if (type) { - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } - } -} - -/** - * Use this to register only the MathML builder for a function(e.g. - * if the function's ParseNode is generated in Parser.js rather than via a - * stand-alone handler provided to `defineFunction`). - */ -function defineFunctionBuilders({ type, mathmlBuilder }) { - defineFunction({ - type, - names: [], - props: { numArgs: 0 }, - handler() { - throw new Error("Should never be called.") - }, - mathmlBuilder - }); -} - -const normalizeArgument = function(arg) { - return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg -}; - -// Since the corresponding buildMathML function expects a -// list of elements, we normalize for different kinds of arguments -const ordargument = function(arg) { - return arg.type === "ordgroup" ? arg.body : [arg] -}; - -/** - * This node represents a document fragment, which contains elements, but when - * placed into the DOM doesn't have any representation itself. It only contains - * children and doesn't have any DOM node properties. - */ -class DocumentFragment { - constructor(children) { - this.children = children; - this.classes = []; - this.style = {}; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - /** Convert the fragment into a node. */ - toNode() { - const frag = document.createDocumentFragment(); - - for (let i = 0; i < this.children.length; i++) { - frag.appendChild(this.children[i].toNode()); - } - - return frag; - } - - /** Convert the fragment into HTML markup. */ - toMarkup() { - let markup = ""; - - // Simply concatenate the markup for the children together. - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText. Applies to - * MathDomNode's only. - */ - toText() { - // To avoid this, we would subclass documentFragment separately for - // MathML, but polyfills for subclassing is expensive per PR 1469. - const toText = (child) => child.toText(); - return this.children.map(toText).join(""); - } -} - -/** - * These objects store the data about the DOM nodes we create, as well as some - * extra data. They can then be transformed into real DOM nodes with the - * `toNode` function or HTML markup using `toMarkup`. They are useful for both - * storing extra properties on the nodes, as well as providing a way to easily - * work with the DOM. - * - * Similar functions for working with MathML nodes exist in mathMLTree.js. - * - */ - -/** - * Create an HTML className based on a list of classes. In addition to joining - * with spaces, we also remove empty classes. - */ -const createClass = function(classes) { - return classes.filter((cls) => cls).join(" "); -}; - -const initNode = function(classes, style) { - this.classes = classes || []; - this.attributes = {}; - this.style = style || {}; -}; - -/** - * Convert into an HTML node - */ -const toNode = function(tagName) { - const node = document.createElement(tagName); - - // Apply the class - node.className = createClass(this.classes); - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - // Apply attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - // Append the children, also as HTML nodes - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; -}; - -/** - * Convert into an HTML markup string - */ -const toMarkup = function(tagName) { - let markup = `<${tagName}`; - - // Add the class - if (this.classes.length) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; - } - } - - markup += ">"; - - // Add the markup of the children, also as markup - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ``; - - return markup; -}; - -/** - * This node represents a span node, with a className, a list of children, and - * an inline style. - * - */ -class Span { - constructor(classes, children, style) { - initNode.call(this, classes, style); - this.children = children || []; - } - - setAttribute(attribute, value) { - this.attributes[attribute] = value; - } - - toNode() { - return toNode.call(this, "span"); - } - - toMarkup() { - return toMarkup.call(this, "span"); - } -} - -class TextNode { - constructor(text) { - this.text = text; - } - toNode() { - return document.createTextNode(this.text); - } - toMarkup() { - return utils.escape(this.text); - } -} - -/** - * This node represents an image embed () element. - */ -class Img { - constructor(src, alt, style) { - this.alt = alt; - this.src = src; - this.classes = ["mord"]; - this.style = style; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - toNode() { - const node = document.createElement("img"); - node.src = this.src; - node.alt = this.alt; - node.className = "mord"; - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - return node; - } - - toMarkup() { - let markup = `${this.alt}` and - * `` tags). - */ -class MathNode { - constructor(type, children, classes, style, isSVG) { - this.type = type; - this.attributes = {}; - this.children = children || []; - this.classes = classes || []; - this.style = style || {}; // Used for elements - this.isSVG = isSVG || false; - } - - /** - * Sets an attribute on a MathML node. MathML depends on attributes to convey a - * semantic content, so this is used heavily. - */ - setAttribute(name, value) { - this.attributes[name] = value; - } - - /** - * Gets an attribute on a MathML node. - */ - getAttribute(name) { - return this.attributes[name]; - } - - /** - * Converts the math node into a MathML-namespaced DOM element. - */ - toNode() { - const node = this.isSVG - ? document.createElementNS("http://www.w3.org/2000/svg", this.type) - : document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); - - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - if (this.classes.length > 0) { - node.className = createClass(this.classes); - } - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; - } - - /** - * Converts the math node into an HTML markup string. - */ - toMarkup() { - let markup = "<" + this.type; - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - markup += " " + attr + '="'; - markup += utils.escape(this.attributes[attr]); - markup += '"'; - } - } - - if (this.classes.length > 0) { - markup += ` class ="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - markup += ">"; - - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ""; - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText, but escaped. - */ - toText() { - return this.children.map((child) => child.toText()).join(""); - } -} - -/** - * This node represents a piece of text. - */ -class TextNode$1 { - constructor(text) { - this.text = text; - } - - /** - * Converts the text node into a DOM text node. - */ - toNode() { - return document.createTextNode(this.text); - } - - /** - * Converts the text node into escaped HTML markup - * (representing the text itself). - */ - toMarkup() { - return utils.escape(this.toText()); - } - - /** - * Converts the text node into a string - * (representing the text iteself). - */ - toText() { - return this.text; - } -} - -// Do not make an the only child of a . -// An acts as its own implicit . -const wrapWithMstyle = expression => { - let node; - if (expression.length === 1 && expression[0].type === "mrow") { - node = expression.pop(); - node.type = "mstyle"; - } else { - node = new MathNode("mstyle", expression); - } - return node -}; - -var mathMLTree = { - MathNode, - TextNode: TextNode$1, - newDocumentFragment -}; - -/** - * This file provides support for building horizontal stretchy elements. - */ - -// From mhchem reaction arrows \ce{A <=>> B} and \ce{A <<=> B} -const keysWithoutUnicodePoints = ["equilibriumRight", "equilibriumLeft"]; - -const stretchyCodePoint = { - widehat: "^", - widecheck: "ˇ", - widetilde: "~", - wideparen: "⏜", // \u23dc - utilde: "~", - overleftarrow: "\u2190", - underleftarrow: "\u2190", - xleftarrow: "\u2190", - overrightarrow: "\u2192", - underrightarrow: "\u2192", - xrightarrow: "\u2192", - underbrace: "\u23df", - overbrace: "\u23de", - overgroup: "\u23e0", - overparen: "⏜", - undergroup: "\u23e1", - underparen: "\u23dd", - overleftrightarrow: "\u2194", - underleftrightarrow: "\u2194", - xleftrightarrow: "\u2194", - Overrightarrow: "\u21d2", - xRightarrow: "\u21d2", - overleftharpoon: "\u21bc", - xleftharpoonup: "\u21bc", - overrightharpoon: "\u21c0", - xrightharpoonup: "\u21c0", - xLeftarrow: "\u21d0", - xLeftrightarrow: "\u21d4", - xhookleftarrow: "\u21a9", - xhookrightarrow: "\u21aa", - xmapsto: "\u21a6", - xrightharpoondown: "\u21c1", - xleftharpoondown: "\u21bd", - xtwoheadleftarrow: "\u219e", - xtwoheadrightarrow: "\u21a0", - xlongequal: "=", - xrightleftarrows: "\u21c4", - yields: "\u2192", - yieldsLeft: "\u2190", - mesomerism: "\u2194", - longrightharpoonup: "\u21c0", - longleftharpoondown: "\u21bd", - "\\cdrightarrow": "\u2192", - "\\cdleftarrow": "\u2190", - "\\cdlongequal": "=" -}; - -const nodeFromObject = (obj) => { - // Build a stretchy arrow from two SVGs. - const children = []; - if (obj.children) { - obj.children.map(child => { children.push(nodeFromObject(child)); }); - } - const node = obj.type === "span" - ? new Span(null, children, obj.style) - : new mathMLTree.MathNode(obj.type, children, [], obj.style, true); - Object.entries(obj.attributes).forEach(([key, value]) => { - node.setAttribute(key, value); - }); - return node -}; - -const mathMLnode = function(label, macros = {}) { - const key = label.slice(1); - let child; - if (!keysWithoutUnicodePoints.includes(key)) { - child = new mathMLTree.TextNode(stretchyCodePoint[key]); - } else { - const atKey = "\\@" + key; - if (!macros.has(atKey)) { - throw new ParseError("Arrow not available. The mhchem package is needed.") - } - child = nodeFromObject(JSON.parse(macros.get(atKey))); - } - const node = new mathMLTree.MathNode("mo", [child]); - node.setAttribute("stretchy", "true"); - return node -}; - -var stretchy = { - mathMLnode -}; - -/** - * This file holds a list of all no-argument functions and single-character - * symbols (like 'a' or ';'). - * - * For each of the symbols, there are two properties they can have: - * - group (required): the ParseNode group type the symbol should have (i.e. - "textord", "mathord", etc). - * - replace: the character that this symbol or function should be - * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi - * character in the main font). - * - * The outermost map in the table indicates what mode the symbols should be - * accepted in (e.g. "math" or "text"). - */ - -// Some of these have a "-token" suffix since these are also used as `ParseNode` -// types for raw text tokens, and we want to avoid conflicts with higher-level -// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by -// looking up the `symbols` map. -const ATOMS = { - bin: 1, - close: 1, - inner: 1, - open: 1, - punct: 1, - rel: 1 -}; -const NON_ATOMS = { - "accent-token": 1, - mathord: 1, - "op-token": 1, - spacing: 1, - textord: 1 -}; - -const symbols = { - math: {}, - text: {} -}; - -/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ -function defineSymbol(mode, group, replace, name, acceptUnicodeChar) { - symbols[mode][name] = { group, replace }; - - if (acceptUnicodeChar && replace) { - symbols[mode][replace] = symbols[mode][name]; - } -} - -// Some abbreviations for commonly used strings. -// This helps minify the code, and also spotting typos using jshint. - -// modes: -const math = "math"; -const text = "text"; - -// groups: -const accent = "accent-token"; -const bin = "bin"; -const close = "close"; -const inner = "inner"; -const mathord = "mathord"; -const op = "op-token"; -const open = "open"; -const punct = "punct"; -const rel = "rel"; -const spacing = "spacing"; -const textord = "textord"; - -// Now comes the symbol table - -// Relation Symbols -defineSymbol(math, rel, "\u2261", "\\equiv", true); -defineSymbol(math, rel, "\u227a", "\\prec", true); -defineSymbol(math, rel, "\u227b", "\\succ", true); -defineSymbol(math, rel, "\u223c", "\\sim", true); -defineSymbol(math, rel, "\u27c2", "\\perp", true); -defineSymbol(math, rel, "\u2aaf", "\\preceq", true); -defineSymbol(math, rel, "\u2ab0", "\\succeq", true); -defineSymbol(math, rel, "\u2243", "\\simeq", true); -defineSymbol(math, rel, "\u224c", "\\backcong", true); -defineSymbol(math, rel, "|", "\\mid", true); -defineSymbol(math, rel, "\u226a", "\\ll", true); -defineSymbol(math, rel, "\u226b", "\\gg", true); -defineSymbol(math, rel, "\u224d", "\\asymp", true); -defineSymbol(math, rel, "\u2225", "\\parallel"); -defineSymbol(math, rel, "\u22c8", "\\bowtie", true); -defineSymbol(math, rel, "\u2323", "\\smile", true); -defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true); -defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true); -defineSymbol(math, rel, "\u2250", "\\doteq", true); -defineSymbol(math, rel, "\u2322", "\\frown", true); -defineSymbol(math, rel, "\u220b", "\\ni", true); -defineSymbol(math, rel, "\u220c", "\\notni", true); -defineSymbol(math, rel, "\u221d", "\\propto", true); -defineSymbol(math, rel, "\u22a2", "\\vdash", true); -defineSymbol(math, rel, "\u22a3", "\\dashv", true); -defineSymbol(math, rel, "\u220b", "\\owns"); -defineSymbol(math, rel, "\u2258", "\\arceq", true); -defineSymbol(math, rel, "\u2259", "\\wedgeq", true); -defineSymbol(math, rel, "\u225a", "\\veeeq", true); -defineSymbol(math, rel, "\u225b", "\\stareq", true); -defineSymbol(math, rel, "\u225d", "\\eqdef", true); -defineSymbol(math, rel, "\u225e", "\\measeq", true); -defineSymbol(math, rel, "\u225f", "\\questeq", true); -defineSymbol(math, rel, "\u2260", "\\ne", true); -defineSymbol(math, rel, "\u2260", "\\neq"); -// mathtools.sty -defineSymbol(math, rel, "\u2237", "\\dblcolon", true); -defineSymbol(math, rel, "\u2254", "\\coloneqq", true); -defineSymbol(math, rel, "\u2255", "\\eqqcolon", true); -defineSymbol(math, rel, "\u2239", "\\eqcolon", true); -defineSymbol(math, rel, "\u2A74", "\\Coloneqq", true); - -// Punctuation -defineSymbol(math, punct, "\u002e", "\\ldotp"); -defineSymbol(math, punct, "\u00b7", "\\cdotp"); - -// Misc Symbols -defineSymbol(math, textord, "\u0023", "\\#"); -defineSymbol(text, textord, "\u0023", "\\#"); -defineSymbol(math, textord, "\u0026", "\\&"); -defineSymbol(text, textord, "\u0026", "\\&"); -defineSymbol(math, textord, "\u2135", "\\aleph", true); -defineSymbol(math, textord, "\u2200", "\\forall", true); -defineSymbol(math, textord, "\u210f", "\\hbar", true); -defineSymbol(math, textord, "\u2203", "\\exists", true); -defineSymbol(math, textord, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\AA", true); -defineSymbol(text, textord, "Å", "\\AA", true); -defineSymbol(math, textord, "\u2663", "\\clubsuit", true); -defineSymbol(math, textord, "\u2667", "\\varclubsuit", true); -defineSymbol(math, textord, "\u2118", "\\wp", true); -defineSymbol(math, textord, "\u266f", "\\sharp", true); -defineSymbol(math, textord, "\u2662", "\\diamondsuit", true); -defineSymbol(math, textord, "\u2666", "\\vardiamondsuit", true); -defineSymbol(math, textord, "\u211c", "\\Re", true); -defineSymbol(math, textord, "\u2661", "\\heartsuit", true); -defineSymbol(math, textord, "\u2665", "\\varheartsuit", true); -defineSymbol(math, textord, "\u2111", "\\Im", true); -defineSymbol(math, textord, "\u2660", "\\spadesuit", true); -defineSymbol(math, textord, "\u2664", "\\varspadesuit", true); -defineSymbol(math, textord, "\u2640", "\\female", true); -defineSymbol(math, textord, "\u2642", "\\male", true); -defineSymbol(math, textord, "\u00a7", "\\S", true); -defineSymbol(text, textord, "\u00a7", "\\S"); -defineSymbol(math, textord, "\u00b6", "\\P", true); -defineSymbol(text, textord, "\u00b6", "\\P"); -defineSymbol(text, textord, "\u263a", "\\smiley", true); -defineSymbol(math, textord, "\u263a", "\\smiley", true); - -// Math and Text -defineSymbol(math, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\textdagger"); -defineSymbol(math, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\textdaggerdbl"); - -// Large Delimiters -defineSymbol(math, close, "\u23b1", "\\rmoustache", true); -defineSymbol(math, open, "\u23b0", "\\lmoustache", true); -defineSymbol(math, close, "\u27ef", "\\rgroup", true); -defineSymbol(math, open, "\u27ee", "\\lgroup", true); - -// Binary Operators -defineSymbol(math, bin, "\u2213", "\\mp", true); -defineSymbol(math, bin, "\u2296", "\\ominus", true); -defineSymbol(math, bin, "\u228e", "\\uplus", true); -defineSymbol(math, bin, "\u2293", "\\sqcap", true); -defineSymbol(math, bin, "\u2217", "\\ast"); -defineSymbol(math, bin, "\u2294", "\\sqcup", true); -defineSymbol(math, bin, "\u25ef", "\\bigcirc", true); -defineSymbol(math, bin, "\u2219", "\\bullet"); -defineSymbol(math, bin, "\u2021", "\\ddagger"); -defineSymbol(math, bin, "\u2240", "\\wr", true); -defineSymbol(math, bin, "\u2a3f", "\\amalg"); -defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath - -// Arrow Symbols -defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true); -defineSymbol(math, rel, "\u21d0", "\\Leftarrow", true); -defineSymbol(math, rel, "\u27f8", "\\Longleftarrow", true); -defineSymbol(math, rel, "\u27f6", "\\longrightarrow", true); -defineSymbol(math, rel, "\u21d2", "\\Rightarrow", true); -defineSymbol(math, rel, "\u27f9", "\\Longrightarrow", true); -defineSymbol(math, rel, "\u2194", "\\leftrightarrow", true); -defineSymbol(math, rel, "\u27f7", "\\longleftrightarrow", true); -defineSymbol(math, rel, "\u21d4", "\\Leftrightarrow", true); -defineSymbol(math, rel, "\u27fa", "\\Longleftrightarrow", true); -defineSymbol(math, rel, "\u21a6", "\\mapsto", true); -defineSymbol(math, rel, "\u27fc", "\\longmapsto", true); -defineSymbol(math, rel, "\u2197", "\\nearrow", true); -defineSymbol(math, rel, "\u21a9", "\\hookleftarrow", true); -defineSymbol(math, rel, "\u21aa", "\\hookrightarrow", true); -defineSymbol(math, rel, "\u2198", "\\searrow", true); -defineSymbol(math, rel, "\u21bc", "\\leftharpoonup", true); -defineSymbol(math, rel, "\u21c0", "\\rightharpoonup", true); -defineSymbol(math, rel, "\u2199", "\\swarrow", true); -defineSymbol(math, rel, "\u21bd", "\\leftharpoondown", true); -defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true); -defineSymbol(math, rel, "\u2196", "\\nwarrow", true); -defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true); -defineSymbol(math, mathord, "\u21af", "\\lightning", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); - -// AMS Negated Binary Relations -defineSymbol(math, rel, "\u226e", "\\nless", true); -// Symbol names preceeded by "@" each have a corresponding macro. -defineSymbol(math, rel, "\u2a87", "\\lneq", true); -defineSymbol(math, rel, "\u2268", "\\lneqq", true); -defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq"); -defineSymbol(math, rel, "\u22e6", "\\lnsim", true); -defineSymbol(math, rel, "\u2a89", "\\lnapprox", true); -defineSymbol(math, rel, "\u2280", "\\nprec", true); -// unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e0", "\\npreceq", true); -defineSymbol(math, rel, "\u22e8", "\\precnsim", true); -defineSymbol(math, rel, "\u2ab9", "\\precnapprox", true); -defineSymbol(math, rel, "\u2241", "\\nsim", true); -defineSymbol(math, rel, "\u2224", "\\nmid", true); -defineSymbol(math, rel, "\u2224", "\\nshortmid"); -defineSymbol(math, rel, "\u22ac", "\\nvdash", true); -defineSymbol(math, rel, "\u22ad", "\\nvDash", true); -defineSymbol(math, rel, "\u22ea", "\\ntriangleleft"); -defineSymbol(math, rel, "\u22ec", "\\ntrianglelefteq", true); -defineSymbol(math, rel, "\u2284", "\\nsubset", true); -defineSymbol(math, rel, "\u2285", "\\nsupset", true); -defineSymbol(math, rel, "\u228a", "\\subsetneq", true); -defineSymbol(math, rel, "\u228a\ufe00", "\\varsubsetneq"); -defineSymbol(math, rel, "\u2acb", "\\subsetneqq", true); -defineSymbol(math, rel, "\u2acb\ufe00", "\\varsubsetneqq"); -defineSymbol(math, rel, "\u226f", "\\ngtr", true); -defineSymbol(math, rel, "\u2a88", "\\gneq", true); -defineSymbol(math, rel, "\u2269", "\\gneqq", true); -defineSymbol(math, rel, "\u2269\ufe00", "\\gvertneqq"); -defineSymbol(math, rel, "\u22e7", "\\gnsim", true); -defineSymbol(math, rel, "\u2a8a", "\\gnapprox", true); -defineSymbol(math, rel, "\u2281", "\\nsucc", true); -// unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e1", "\\nsucceq", true); -defineSymbol(math, rel, "\u22e9", "\\succnsim", true); -defineSymbol(math, rel, "\u2aba", "\\succnapprox", true); -// unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u2246", "\\ncong", true); -defineSymbol(math, rel, "\u2226", "\\nparallel", true); -defineSymbol(math, rel, "\u2226", "\\nshortparallel"); -defineSymbol(math, rel, "\u22af", "\\nVDash", true); -defineSymbol(math, rel, "\u22eb", "\\ntriangleright"); -defineSymbol(math, rel, "\u22ed", "\\ntrianglerighteq", true); -defineSymbol(math, rel, "\u228b", "\\supsetneq", true); -defineSymbol(math, rel, "\u228b", "\\varsupsetneq"); -defineSymbol(math, rel, "\u2acc", "\\supsetneqq", true); -defineSymbol(math, rel, "\u2acc\ufe00", "\\varsupsetneqq"); -defineSymbol(math, rel, "\u22ae", "\\nVdash", true); -defineSymbol(math, rel, "\u2ab5", "\\precneqq", true); -defineSymbol(math, rel, "\u2ab6", "\\succneqq", true); -defineSymbol(math, bin, "\u22b4", "\\unlhd"); -defineSymbol(math, bin, "\u22b5", "\\unrhd"); - -// AMS Negated Arrows -defineSymbol(math, rel, "\u219a", "\\nleftarrow", true); -defineSymbol(math, rel, "\u219b", "\\nrightarrow", true); -defineSymbol(math, rel, "\u21cd", "\\nLeftarrow", true); -defineSymbol(math, rel, "\u21cf", "\\nRightarrow", true); -defineSymbol(math, rel, "\u21ae", "\\nleftrightarrow", true); -defineSymbol(math, rel, "\u21ce", "\\nLeftrightarrow", true); - -// AMS Misc -defineSymbol(math, rel, "\u25b3", "\\vartriangle"); -defineSymbol(math, textord, "\u210f", "\\hslash"); -defineSymbol(math, textord, "\u25bd", "\\triangledown"); -defineSymbol(math, textord, "\u25ca", "\\lozenge"); -defineSymbol(math, textord, "\u24c8", "\\circledS"); -defineSymbol(math, textord, "\u00ae", "\\circledR", true); -defineSymbol(text, textord, "\u00ae", "\\circledR"); -defineSymbol(text, textord, "\u00ae", "\\textregistered"); -defineSymbol(math, textord, "\u2221", "\\measuredangle", true); -defineSymbol(math, textord, "\u2204", "\\nexists"); -defineSymbol(math, textord, "\u2127", "\\mho"); -defineSymbol(math, textord, "\u2132", "\\Finv", true); -defineSymbol(math, textord, "\u2141", "\\Game", true); -defineSymbol(math, textord, "\u2035", "\\backprime"); -defineSymbol(math, textord, "\u25b2", "\\blacktriangle"); -defineSymbol(math, textord, "\u25bc", "\\blacktriangledown"); -defineSymbol(math, textord, "\u25a0", "\\blacksquare"); -defineSymbol(math, textord, "\u29eb", "\\blacklozenge"); -defineSymbol(math, textord, "\u2605", "\\bigstar"); -defineSymbol(math, textord, "\u2222", "\\sphericalangle", true); -defineSymbol(math, textord, "\u2201", "\\complement", true); -// unicode-math maps U+F0 to \matheth. We map to AMS function \eth -defineSymbol(math, textord, "\u00f0", "\\eth", true); -defineSymbol(text, textord, "\u00f0", "\u00f0"); -defineSymbol(math, textord, "\u2571", "\\diagup"); -defineSymbol(math, textord, "\u2572", "\\diagdown"); -defineSymbol(math, textord, "\u25a1", "\\square"); -defineSymbol(math, textord, "\u25a1", "\\Box"); -defineSymbol(math, textord, "\u25ca", "\\Diamond"); -// unicode-math maps U+A5 to \mathyen. We map to AMS function \yen -defineSymbol(math, textord, "\u00a5", "\\yen", true); -defineSymbol(text, textord, "\u00a5", "\\yen", true); -defineSymbol(math, textord, "\u2713", "\\checkmark", true); -defineSymbol(text, textord, "\u2713", "\\checkmark"); -defineSymbol(math, textord, "\u2717", "\\ballotx", true); -defineSymbol(text, textord, "\u2717", "\\ballotx"); -defineSymbol(text, textord, "\u2022", "\\textbullet"); - -// AMS Hebrew -defineSymbol(math, textord, "\u2136", "\\beth", true); -defineSymbol(math, textord, "\u2138", "\\daleth", true); -defineSymbol(math, textord, "\u2137", "\\gimel", true); - -// AMS Greek -defineSymbol(math, textord, "\u03dd", "\\digamma", true); -defineSymbol(math, textord, "\u03f0", "\\varkappa"); - -// AMS Delimiters -defineSymbol(math, open, "\u231C", "\\ulcorner", true); -defineSymbol(math, close, "\u231D", "\\urcorner", true); -defineSymbol(math, open, "\u231E", "\\llcorner", true); -defineSymbol(math, close, "\u231F", "\\lrcorner", true); - -// AMS Binary Relations -defineSymbol(math, rel, "\u2266", "\\leqq", true); -defineSymbol(math, rel, "\u2a7d", "\\leqslant", true); -defineSymbol(math, rel, "\u2a95", "\\eqslantless", true); -defineSymbol(math, rel, "\u2272", "\\lesssim", true); -defineSymbol(math, rel, "\u2a85", "\\lessapprox", true); -defineSymbol(math, rel, "\u224a", "\\approxeq", true); -defineSymbol(math, bin, "\u22d6", "\\lessdot"); -defineSymbol(math, rel, "\u22d8", "\\lll", true); -defineSymbol(math, rel, "\u2276", "\\lessgtr", true); -defineSymbol(math, rel, "\u22da", "\\lesseqgtr", true); -defineSymbol(math, rel, "\u2a8b", "\\lesseqqgtr", true); -defineSymbol(math, rel, "\u2251", "\\doteqdot"); -defineSymbol(math, rel, "\u2253", "\\risingdotseq", true); -defineSymbol(math, rel, "\u2252", "\\fallingdotseq", true); -defineSymbol(math, rel, "\u223d", "\\backsim", true); -defineSymbol(math, rel, "\u22cd", "\\backsimeq", true); -defineSymbol(math, rel, "\u2ac5", "\\subseteqq", true); -defineSymbol(math, rel, "\u22d0", "\\Subset", true); -defineSymbol(math, rel, "\u228f", "\\sqsubset", true); -defineSymbol(math, rel, "\u227c", "\\preccurlyeq", true); -defineSymbol(math, rel, "\u22de", "\\curlyeqprec", true); -defineSymbol(math, rel, "\u227e", "\\precsim", true); -defineSymbol(math, rel, "\u2ab7", "\\precapprox", true); -defineSymbol(math, rel, "\u22b2", "\\vartriangleleft"); -defineSymbol(math, rel, "\u22b4", "\\trianglelefteq"); -defineSymbol(math, rel, "\u22a8", "\\vDash", true); -defineSymbol(math, rel, "\u22aa", "\\Vvdash", true); -defineSymbol(math, rel, "\u2323", "\\smallsmile"); -defineSymbol(math, rel, "\u2322", "\\smallfrown"); -defineSymbol(math, rel, "\u224f", "\\bumpeq", true); -defineSymbol(math, rel, "\u224e", "\\Bumpeq", true); -defineSymbol(math, rel, "\u2267", "\\geqq", true); -defineSymbol(math, rel, "\u2a7e", "\\geqslant", true); -defineSymbol(math, rel, "\u2a96", "\\eqslantgtr", true); -defineSymbol(math, rel, "\u2273", "\\gtrsim", true); -defineSymbol(math, rel, "\u2a86", "\\gtrapprox", true); -defineSymbol(math, bin, "\u22d7", "\\gtrdot"); -defineSymbol(math, rel, "\u22d9", "\\ggg", true); -defineSymbol(math, rel, "\u2277", "\\gtrless", true); -defineSymbol(math, rel, "\u22db", "\\gtreqless", true); -defineSymbol(math, rel, "\u2a8c", "\\gtreqqless", true); -defineSymbol(math, rel, "\u2256", "\\eqcirc", true); -defineSymbol(math, rel, "\u2257", "\\circeq", true); -defineSymbol(math, rel, "\u225c", "\\triangleq", true); -defineSymbol(math, rel, "\u223c", "\\thicksim"); -defineSymbol(math, rel, "\u2248", "\\thickapprox"); -defineSymbol(math, rel, "\u2ac6", "\\supseteqq", true); -defineSymbol(math, rel, "\u22d1", "\\Supset", true); -defineSymbol(math, rel, "\u2290", "\\sqsupset", true); -defineSymbol(math, rel, "\u227d", "\\succcurlyeq", true); -defineSymbol(math, rel, "\u22df", "\\curlyeqsucc", true); -defineSymbol(math, rel, "\u227f", "\\succsim", true); -defineSymbol(math, rel, "\u2ab8", "\\succapprox", true); -defineSymbol(math, rel, "\u22b3", "\\vartriangleright"); -defineSymbol(math, rel, "\u22b5", "\\trianglerighteq"); -defineSymbol(math, rel, "\u22a9", "\\Vdash", true); -defineSymbol(math, rel, "\u2223", "\\shortmid"); -defineSymbol(math, rel, "\u2225", "\\shortparallel"); -defineSymbol(math, rel, "\u226c", "\\between", true); -defineSymbol(math, rel, "\u22d4", "\\pitchfork", true); -defineSymbol(math, rel, "\u221d", "\\varpropto"); -defineSymbol(math, rel, "\u25c0", "\\blacktriangleleft"); -// unicode-math says that \therefore is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2234", "\\therefore", true); -defineSymbol(math, rel, "\u220d", "\\backepsilon"); -defineSymbol(math, rel, "\u25b6", "\\blacktriangleright"); -// unicode-math says that \because is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2235", "\\because", true); -defineSymbol(math, rel, "\u22d8", "\\llless"); -defineSymbol(math, rel, "\u22d9", "\\gggtr"); -defineSymbol(math, bin, "\u22b2", "\\lhd"); -defineSymbol(math, bin, "\u22b3", "\\rhd"); -defineSymbol(math, rel, "\u2242", "\\eqsim", true); -defineSymbol(math, rel, "\u22c8", "\\Join"); -defineSymbol(math, rel, "\u2251", "\\Doteq", true); - -// AMS Binary Operators -defineSymbol(math, bin, "\u2214", "\\dotplus", true); -defineSymbol(math, bin, "\u2216", "\\smallsetminus"); -defineSymbol(math, bin, "\u22d2", "\\Cap", true); -defineSymbol(math, bin, "\u22d3", "\\Cup", true); -defineSymbol(math, bin, "\u2a5e", "\\doublebarwedge", true); -defineSymbol(math, bin, "\u229f", "\\boxminus", true); -defineSymbol(math, bin, "\u229e", "\\boxplus", true); -defineSymbol(math, bin, "\u22c7", "\\divideontimes", true); -defineSymbol(math, bin, "\u22c9", "\\ltimes", true); -defineSymbol(math, bin, "\u22ca", "\\rtimes", true); -defineSymbol(math, bin, "\u22cb", "\\leftthreetimes", true); -defineSymbol(math, bin, "\u22cc", "\\rightthreetimes", true); -defineSymbol(math, bin, "\u22cf", "\\curlywedge", true); -defineSymbol(math, bin, "\u22ce", "\\curlyvee", true); -defineSymbol(math, bin, "\u229d", "\\circleddash", true); -defineSymbol(math, bin, "\u229b", "\\circledast", true); -defineSymbol(math, bin, "\u22ba", "\\intercal", true); -defineSymbol(math, bin, "\u22d2", "\\doublecap"); -defineSymbol(math, bin, "\u22d3", "\\doublecup"); -defineSymbol(math, bin, "\u22a0", "\\boxtimes", true); - -// AMS Arrows -// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. -// We'll map it to AMS function \dashrightarrow. It produces the same atom. -defineSymbol(math, rel, "\u21e2", "\\dashrightarrow", true); -// unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21e0", "\\dashleftarrow", true); -defineSymbol(math, rel, "\u21c7", "\\leftleftarrows", true); -defineSymbol(math, rel, "\u21c6", "\\leftrightarrows", true); -defineSymbol(math, rel, "\u21da", "\\Lleftarrow", true); -defineSymbol(math, rel, "\u219e", "\\twoheadleftarrow", true); -defineSymbol(math, rel, "\u21a2", "\\leftarrowtail", true); -defineSymbol(math, rel, "\u21ab", "\\looparrowleft", true); -defineSymbol(math, rel, "\u21cb", "\\leftrightharpoons", true); -defineSymbol(math, rel, "\u21b6", "\\curvearrowleft", true); -// unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21ba", "\\circlearrowleft", true); -defineSymbol(math, rel, "\u21b0", "\\Lsh", true); -defineSymbol(math, rel, "\u21c8", "\\upuparrows", true); -defineSymbol(math, rel, "\u21bf", "\\upharpoonleft", true); -defineSymbol(math, rel, "\u21c3", "\\downharpoonleft", true); -defineSymbol(math, rel, "\u22b6", "\\origof", true); -defineSymbol(math, rel, "\u22b7", "\\imageof", true); -defineSymbol(math, rel, "\u22b8", "\\multimap", true); -defineSymbol(math, rel, "\u21ad", "\\leftrightsquigarrow", true); -defineSymbol(math, rel, "\u21c9", "\\rightrightarrows", true); -defineSymbol(math, rel, "\u21c4", "\\rightleftarrows", true); -defineSymbol(math, rel, "\u21a0", "\\twoheadrightarrow", true); -defineSymbol(math, rel, "\u21a3", "\\rightarrowtail", true); -defineSymbol(math, rel, "\u21ac", "\\looparrowright", true); -defineSymbol(math, rel, "\u21b7", "\\curvearrowright", true); -// unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21bb", "\\circlearrowright", true); -defineSymbol(math, rel, "\u21b1", "\\Rsh", true); -defineSymbol(math, rel, "\u21ca", "\\downdownarrows", true); -defineSymbol(math, rel, "\u21be", "\\upharpoonright", true); -defineSymbol(math, rel, "\u21c2", "\\downharpoonright", true); -defineSymbol(math, rel, "\u21dd", "\\rightsquigarrow", true); -defineSymbol(math, rel, "\u21dd", "\\leadsto"); -defineSymbol(math, rel, "\u21db", "\\Rrightarrow", true); -defineSymbol(math, rel, "\u21be", "\\restriction"); - -defineSymbol(math, textord, "\u2018", "`"); -defineSymbol(math, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\textdollar"); -defineSymbol(math, textord, "%", "\\%"); -defineSymbol(text, textord, "%", "\\%"); -defineSymbol(math, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\textunderscore"); -defineSymbol(text, textord, "\u2423", "\\textvisiblespace", true); -defineSymbol(math, textord, "\u2220", "\\angle", true); -defineSymbol(math, textord, "\u221e", "\\infty", true); -defineSymbol(math, textord, "\u2032", "\\prime"); -defineSymbol(math, textord, "\u25b3", "\\triangle"); -defineSymbol(text, textord, "\u0391", "\\Alpha", true); -defineSymbol(text, textord, "\u0392", "\\Beta", true); -defineSymbol(text, textord, "\u0393", "\\Gamma", true); -defineSymbol(text, textord, "\u0394", "\\Delta", true); -defineSymbol(text, textord, "\u0395", "\\Epsilon", true); -defineSymbol(text, textord, "\u0396", "\\Zeta", true); -defineSymbol(text, textord, "\u0397", "\\Eta", true); -defineSymbol(text, textord, "\u0398", "\\Theta", true); -defineSymbol(text, textord, "\u0399", "\\Iota", true); -defineSymbol(text, textord, "\u039a", "\\Kappa", true); -defineSymbol(text, textord, "\u039b", "\\Lambda", true); -defineSymbol(text, textord, "\u039c", "\\Mu", true); -defineSymbol(text, textord, "\u039d", "\\Nu", true); -defineSymbol(text, textord, "\u039e", "\\Xi", true); -defineSymbol(text, textord, "\u039f", "\\Omicron", true); -defineSymbol(text, textord, "\u03a0", "\\Pi", true); -defineSymbol(text, textord, "\u03a1", "\\Rho", true); -defineSymbol(text, textord, "\u03a3", "\\Sigma", true); -defineSymbol(text, textord, "\u03a4", "\\Tau", true); -defineSymbol(text, textord, "\u03a5", "\\Upsilon", true); -defineSymbol(text, textord, "\u03a6", "\\Phi", true); -defineSymbol(text, textord, "\u03a7", "\\Chi", true); -defineSymbol(text, textord, "\u03a8", "\\Psi", true); -defineSymbol(text, textord, "\u03a9", "\\Omega", true); -defineSymbol(math, mathord, "\u0391", "\\Alpha", true); -defineSymbol(math, mathord, "\u0392", "\\Beta", true); -defineSymbol(math, mathord, "\u0393", "\\Gamma", true); -defineSymbol(math, mathord, "\u0394", "\\Delta", true); -defineSymbol(math, mathord, "\u0395", "\\Epsilon", true); -defineSymbol(math, mathord, "\u0396", "\\Zeta", true); -defineSymbol(math, mathord, "\u0397", "\\Eta", true); -defineSymbol(math, mathord, "\u0398", "\\Theta", true); -defineSymbol(math, mathord, "\u0399", "\\Iota", true); -defineSymbol(math, mathord, "\u039a", "\\Kappa", true); -defineSymbol(math, mathord, "\u039b", "\\Lambda", true); -defineSymbol(math, mathord, "\u039c", "\\Mu", true); -defineSymbol(math, mathord, "\u039d", "\\Nu", true); -defineSymbol(math, mathord, "\u039e", "\\Xi", true); -defineSymbol(math, mathord, "\u039f", "\\Omicron", true); -defineSymbol(math, mathord, "\u03a0", "\\Pi", true); -defineSymbol(math, mathord, "\u03a1", "\\Rho", true); -defineSymbol(math, mathord, "\u03a3", "\\Sigma", true); -defineSymbol(math, mathord, "\u03a4", "\\Tau", true); -defineSymbol(math, mathord, "\u03a5", "\\Upsilon", true); -defineSymbol(math, mathord, "\u03a6", "\\Phi", true); -defineSymbol(math, mathord, "\u03a7", "\\Chi", true); -defineSymbol(math, mathord, "\u03a8", "\\Psi", true); -defineSymbol(math, mathord, "\u03a9", "\\Omega", true); -defineSymbol(math, textord, "\u00ac", "\\neg", true); -defineSymbol(math, textord, "\u00ac", "\\lnot"); -defineSymbol(math, textord, "\u22a4", "\\top"); -defineSymbol(math, textord, "\u22a5", "\\bot"); -defineSymbol(math, textord, "\u2205", "\\emptyset"); -defineSymbol(math, textord, "\u00f8", "\\varnothing"); -defineSymbol(math, mathord, "\u03b1", "\\alpha", true); -defineSymbol(math, mathord, "\u03b2", "\\beta", true); -defineSymbol(math, mathord, "\u03b3", "\\gamma", true); -defineSymbol(math, mathord, "\u03b4", "\\delta", true); -defineSymbol(math, mathord, "\u03f5", "\\epsilon", true); -defineSymbol(math, mathord, "\u03b6", "\\zeta", true); -defineSymbol(math, mathord, "\u03b7", "\\eta", true); -defineSymbol(math, mathord, "\u03b8", "\\theta", true); -defineSymbol(math, mathord, "\u03b9", "\\iota", true); -defineSymbol(math, mathord, "\u03ba", "\\kappa", true); -defineSymbol(math, mathord, "\u03bb", "\\lambda", true); -defineSymbol(math, mathord, "\u03bc", "\\mu", true); -defineSymbol(math, mathord, "\u03bd", "\\nu", true); -defineSymbol(math, mathord, "\u03be", "\\xi", true); -defineSymbol(math, mathord, "\u03bf", "\\omicron", true); -defineSymbol(math, mathord, "\u03c0", "\\pi", true); -defineSymbol(math, mathord, "\u03c1", "\\rho", true); -defineSymbol(math, mathord, "\u03c3", "\\sigma", true); -defineSymbol(math, mathord, "\u03c4", "\\tau", true); -defineSymbol(math, mathord, "\u03c5", "\\upsilon", true); -defineSymbol(math, mathord, "\u03d5", "\\phi", true); -defineSymbol(math, mathord, "\u03c7", "\\chi", true); -defineSymbol(math, mathord, "\u03c8", "\\psi", true); -defineSymbol(math, mathord, "\u03c9", "\\omega", true); -defineSymbol(math, mathord, "\u03b5", "\\varepsilon", true); -defineSymbol(math, mathord, "\u03d1", "\\vartheta", true); -defineSymbol(math, mathord, "\u03d6", "\\varpi", true); -defineSymbol(math, mathord, "\u03f1", "\\varrho", true); -defineSymbol(math, mathord, "\u03c2", "\\varsigma", true); -defineSymbol(math, mathord, "\u03c6", "\\varphi", true); -defineSymbol(math, mathord, "\u03d8", "\\Coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\varcoppa", true); -defineSymbol(math, mathord, "\u03de", "\\Koppa", true); -defineSymbol(math, mathord, "\u03df", "\\koppa", true); -defineSymbol(math, mathord, "\u03e0", "\\Sampi", true); -defineSymbol(math, mathord, "\u03e1", "\\sampi", true); -defineSymbol(math, mathord, "\u03da", "\\Stigma", true); -defineSymbol(math, mathord, "\u03db", "\\stigma", true); -defineSymbol(math, bin, "\u2217", "\u2217", true); -defineSymbol(math, bin, "+", "+"); -defineSymbol(math, bin, "*", "*"); -defineSymbol(math, bin, "\u2044", "\u2044"); -defineSymbol(math, bin, "\u2212", "-", true); -defineSymbol(math, bin, "\u22c5", "\\cdot", true); -defineSymbol(math, bin, "\u2218", "\\circ"); -defineSymbol(math, bin, "\u00f7", "\\div", true); -defineSymbol(math, bin, "\u00b1", "\\pm", true); -defineSymbol(math, bin, "\u00d7", "\\times", true); -defineSymbol(math, bin, "\u2229", "\\cap", true); -defineSymbol(math, bin, "\u222a", "\\cup", true); -defineSymbol(math, bin, "\u2216", "\\setminus"); -defineSymbol(math, bin, "\u2227", "\\land"); -defineSymbol(math, bin, "\u2228", "\\lor"); -defineSymbol(math, bin, "\u2227", "\\wedge", true); -defineSymbol(math, bin, "\u2228", "\\vee", true); -defineSymbol(math, textord, "\u221a", "\\surd"); -defineSymbol(math, open, "\u27e6", "\\llbracket", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u27e7", "\\rrbracket", true); -defineSymbol(math, open, "\u27e8", "\\langle", true); -defineSymbol(math, open, "|", "\\lvert"); -defineSymbol(math, open, "\u2016", "\\lVert"); -defineSymbol(math, close, "?", "?"); -defineSymbol(math, close, "!", "!"); -defineSymbol(math, close, "‼", "‼"); -defineSymbol(math, close, "\u27e9", "\\rangle", true); -defineSymbol(math, close, "|", "\\rvert"); -defineSymbol(math, close, "\u2016", "\\rVert"); -defineSymbol(math, open, "\u2983", "\\lBrace", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u2984", "\\rBrace", true); -defineSymbol(math, rel, "=", "="); -defineSymbol(math, rel, "\u2248", "\\approx", true); -defineSymbol(math, rel, "\u2245", "\\cong", true); -defineSymbol(math, rel, "\u2265", "\\ge"); -defineSymbol(math, rel, "\u2265", "\\geq", true); -defineSymbol(math, rel, "\u2190", "\\gets"); -defineSymbol(math, rel, ">", "\\gt", true); -defineSymbol(math, rel, "\u2208", "\\in", true); -defineSymbol(math, rel, "\u2209", "\\notin", true); -defineSymbol(math, rel, "\ue020", "\\@not"); -defineSymbol(math, rel, "\u2282", "\\subset", true); -defineSymbol(math, rel, "\u2283", "\\supset", true); -defineSymbol(math, rel, "\u2286", "\\subseteq", true); -defineSymbol(math, rel, "\u2287", "\\supseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteqq"); -defineSymbol(math, rel, "\u2289", "\\nsupseteq", true); -defineSymbol(math, rel, "\u2289", "\\nsupseteqq"); -defineSymbol(math, rel, "\u22a8", "\\models"); -defineSymbol(math, rel, "\u2190", "\\leftarrow", true); -defineSymbol(math, rel, "\u2264", "\\le"); -defineSymbol(math, rel, "\u2264", "\\leq", true); -defineSymbol(math, rel, "<", "\\lt", true); -defineSymbol(math, rel, "\u2192", "\\rightarrow", true); -defineSymbol(math, rel, "\u2192", "\\to"); -defineSymbol(math, rel, "\u2271", "\\ngeq", true); -defineSymbol(math, rel, "\u2271", "\\ngeqq"); -defineSymbol(math, rel, "\u2271", "\\ngeqslant"); -defineSymbol(math, rel, "\u2270", "\\nleq", true); -defineSymbol(math, rel, "\u2270", "\\nleqq"); -defineSymbol(math, rel, "\u2270", "\\nleqslant"); -defineSymbol(math, spacing, "\u00a0", "\\ "); -defineSymbol(math, spacing, "\u00a0", "\\space"); -// Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% -defineSymbol(math, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(text, spacing, "\u00a0", "\\ "); -defineSymbol(text, spacing, "\u00a0", " "); -defineSymbol(text, spacing, "\u00a0", "\\space"); -defineSymbol(text, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(math, spacing, null, "\\nobreak"); -defineSymbol(math, spacing, null, "\\allowbreak"); -defineSymbol(math, punct, ",", ","); -defineSymbol(math, punct, ";", ";"); -defineSymbol(math, bin, "\u22bc", "\\barwedge", true); -defineSymbol(math, bin, "\u22bb", "\\veebar", true); -defineSymbol(math, bin, "\u2299", "\\odot", true); -defineSymbol(math, bin, "\u2295", "\\oplus", true); -defineSymbol(math, bin, "\u2297", "\\otimes", true); -defineSymbol(math, textord, "\u2202", "\\partial", true); -defineSymbol(math, bin, "\u2298", "\\oslash", true); -defineSymbol(math, bin, "\u229a", "\\circledcirc", true); -defineSymbol(math, bin, "\u22a1", "\\boxdot", true); -defineSymbol(math, bin, "\u25b3", "\\bigtriangleup"); -defineSymbol(math, bin, "\u25bd", "\\bigtriangledown"); -defineSymbol(math, bin, "\u2020", "\\dagger"); -defineSymbol(math, bin, "\u22c4", "\\diamond"); -defineSymbol(math, bin, "\u22c6", "\\star"); -defineSymbol(math, bin, "\u25c3", "\\triangleleft"); -defineSymbol(math, bin, "\u25b9", "\\triangleright"); -defineSymbol(math, open, "{", "\\{"); -defineSymbol(text, textord, "{", "\\{"); -defineSymbol(text, textord, "{", "\\textbraceleft"); -defineSymbol(math, close, "}", "\\}"); -defineSymbol(text, textord, "}", "\\}"); -defineSymbol(text, textord, "}", "\\textbraceright"); -defineSymbol(math, open, "{", "\\lbrace"); -defineSymbol(math, close, "}", "\\rbrace"); -defineSymbol(math, open, "[", "\\lbrack", true); -defineSymbol(text, textord, "[", "\\lbrack", true); -defineSymbol(math, close, "]", "\\rbrack", true); -defineSymbol(text, textord, "]", "\\rbrack", true); -defineSymbol(math, open, "(", "\\lparen", true); -defineSymbol(math, close, ")", "\\rparen", true); -defineSymbol(text, textord, "<", "\\textless", true); // in T1 fontenc -defineSymbol(text, textord, ">", "\\textgreater", true); // in T1 fontenc -defineSymbol(math, open, "\u230a", "\\lfloor", true); -defineSymbol(math, close, "\u230b", "\\rfloor", true); -defineSymbol(math, open, "\u2308", "\\lceil", true); -defineSymbol(math, close, "\u2309", "\\rceil", true); -defineSymbol(math, textord, "\\", "\\backslash"); -defineSymbol(math, textord, "|", "|"); -defineSymbol(math, textord, "|", "\\vert"); -defineSymbol(text, textord, "|", "\\textbar", true); // in T1 fontenc -defineSymbol(math, textord, "\u2016", "\\|"); -defineSymbol(math, textord, "\u2016", "\\Vert"); -defineSymbol(text, textord, "\u2016", "\\textbardbl"); -defineSymbol(text, textord, "~", "\\textasciitilde"); -defineSymbol(text, textord, "\\", "\\textbackslash"); -defineSymbol(text, textord, "^", "\\textasciicircum"); -defineSymbol(math, rel, "\u2191", "\\uparrow", true); -defineSymbol(math, rel, "\u21d1", "\\Uparrow", true); -defineSymbol(math, rel, "\u2193", "\\downarrow", true); -defineSymbol(math, rel, "\u21d3", "\\Downarrow", true); -defineSymbol(math, rel, "\u2195", "\\updownarrow", true); -defineSymbol(math, rel, "\u21d5", "\\Updownarrow", true); -defineSymbol(math, op, "\u2210", "\\coprod"); -defineSymbol(math, op, "\u22c1", "\\bigvee"); -defineSymbol(math, op, "\u22c0", "\\bigwedge"); -defineSymbol(math, op, "\u2a04", "\\biguplus"); -defineSymbol(math, op, "\u22c2", "\\bigcap"); -defineSymbol(math, op, "\u22c3", "\\bigcup"); -defineSymbol(math, op, "\u222b", "\\int"); -defineSymbol(math, op, "\u222b", "\\intop"); -defineSymbol(math, op, "\u222c", "\\iint"); -defineSymbol(math, op, "\u222d", "\\iiint"); -defineSymbol(math, op, "\u220f", "\\prod"); -defineSymbol(math, op, "\u2211", "\\sum"); -defineSymbol(math, op, "\u2a02", "\\bigotimes"); -defineSymbol(math, op, "\u2a01", "\\bigoplus"); -defineSymbol(math, op, "\u2a00", "\\bigodot"); -defineSymbol(math, op, "\u222e", "\\oint"); -defineSymbol(math, op, "\u222f", "\\oiint"); -defineSymbol(math, op, "\u2230", "\\oiiint"); -defineSymbol(math, op, "\u2231", "\\intclockwise"); -defineSymbol(math, op, "\u2232", "\\varointclockwise"); -defineSymbol(math, op, "\u2a0c", "\\iiiint"); -defineSymbol(math, op, "\u2a0d", "\\intbar"); -defineSymbol(math, op, "\u2a0e", "\\intBar"); -defineSymbol(math, op, "\u2a0f", "\\fint"); -defineSymbol(math, op, "\u2a12", "\\rppolint"); -defineSymbol(math, op, "\u2a13", "\\scpolint"); -defineSymbol(math, op, "\u2a15", "\\pointint"); -defineSymbol(math, op, "\u2a16", "\\sqint"); -defineSymbol(math, op, "\u2a17", "\\intlarhk"); -defineSymbol(math, op, "\u2a18", "\\intx"); -defineSymbol(math, op, "\u2a19", "\\intcap"); -defineSymbol(math, op, "\u2a1a", "\\intcup"); -defineSymbol(math, op, "\u2a05", "\\bigsqcap"); -defineSymbol(math, op, "\u2a06", "\\bigsqcup"); -defineSymbol(math, op, "\u222b", "\\smallint"); -defineSymbol(text, inner, "\u2026", "\\textellipsis"); -defineSymbol(math, inner, "\u2026", "\\mathellipsis"); -defineSymbol(text, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u22f0", "\\iddots", true); -defineSymbol(math, inner, "\u22ef", "\\@cdots", true); -defineSymbol(math, inner, "\u22f1", "\\ddots", true); -defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro -defineSymbol(math, accent, "\u02ca", "\\acute"); -defineSymbol(math, accent, "\u0060", "\\grave"); -defineSymbol(math, accent, "\u00a8", "\\ddot"); -defineSymbol(math, accent, "\u20db", "\\dddot"); -defineSymbol(math, accent, "\u20dc", "\\ddddot"); -defineSymbol(math, accent, "\u007e", "\\tilde"); -defineSymbol(math, accent, "\u00af", "\\bar"); -defineSymbol(math, accent, "\u02d8", "\\breve"); -defineSymbol(math, accent, "\u02c7", "\\check"); -defineSymbol(math, accent, "\u005e", "\\hat"); -defineSymbol(math, accent, "\u20d7", "\\vec"); -defineSymbol(math, accent, "\u02d9", "\\dot"); -defineSymbol(math, accent, "\u02da", "\\mathring"); -defineSymbol(math, mathord, "\u0131", "\\imath", true); -defineSymbol(math, mathord, "\u0237", "\\jmath", true); -defineSymbol(math, textord, "\u0131", "\u0131"); -defineSymbol(math, textord, "\u0237", "\u0237"); -defineSymbol(text, textord, "\u0131", "\\i", true); -defineSymbol(text, textord, "\u0237", "\\j", true); -defineSymbol(text, textord, "\u00df", "\\ss", true); -defineSymbol(text, textord, "\u00e6", "\\ae", true); -defineSymbol(text, textord, "\u0153", "\\oe", true); -defineSymbol(text, textord, "\u00f8", "\\o", true); -defineSymbol(math, mathord, "\u00f8", "\\o", true); -defineSymbol(text, textord, "\u00c6", "\\AE", true); -defineSymbol(text, textord, "\u0152", "\\OE", true); -defineSymbol(text, textord, "\u00d8", "\\O", true); -defineSymbol(math, mathord, "\u00d8", "\\O", true); -defineSymbol(text, accent, "\u02ca", "\\'"); // acute -defineSymbol(text, accent, "\u02cb", "\\`"); // grave -defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(text, accent, "\u02dc", "\\~"); // tilde -defineSymbol(text, accent, "\u02c9", "\\="); // macron -defineSymbol(text, accent, "\u02d8", "\\u"); // breve -defineSymbol(text, accent, "\u02d9", "\\."); // dot above -defineSymbol(text, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(text, accent, "\u02da", "\\r"); // ring above -defineSymbol(text, accent, "\u02c7", "\\v"); // caron -defineSymbol(text, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(text, accent, "\u02dd", "\\H"); // double acute -defineSymbol(math, accent, "\u02ca", "\\'"); // acute -defineSymbol(math, accent, "\u02cb", "\\`"); // grave -defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(math, accent, "\u02dc", "\\~"); // tilde -defineSymbol(math, accent, "\u02c9", "\\="); // macron -defineSymbol(math, accent, "\u02d8", "\\u"); // breve -defineSymbol(math, accent, "\u02d9", "\\."); // dot above -defineSymbol(math, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(math, accent, "\u02da", "\\r"); // ring above -defineSymbol(math, accent, "\u02c7", "\\v"); // caron -defineSymbol(math, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(math, accent, "\u02dd", "\\H"); // double acute - -// These ligatures are detected and created in Parser.js's `formLigatures`. -const ligatures = { - "--": true, - "---": true, - "``": true, - "''": true -}; - -defineSymbol(text, textord, "\u2013", "--", true); -defineSymbol(text, textord, "\u2013", "\\textendash"); -defineSymbol(text, textord, "\u2014", "---", true); -defineSymbol(text, textord, "\u2014", "\\textemdash"); -defineSymbol(text, textord, "\u2018", "`", true); -defineSymbol(text, textord, "\u2018", "\\textquoteleft"); -defineSymbol(text, textord, "\u2019", "'", true); -defineSymbol(text, textord, "\u2019", "\\textquoteright"); -defineSymbol(text, textord, "\u201c", "``", true); -defineSymbol(text, textord, "\u201c", "\\textquotedblleft"); -defineSymbol(text, textord, "\u201d", "''", true); -defineSymbol(text, textord, "\u201d", "\\textquotedblright"); -// \degree from gensymb package -defineSymbol(math, textord, "\u00b0", "\\degree", true); -defineSymbol(text, textord, "\u00b0", "\\degree"); -// \textdegree from inputenc package -defineSymbol(text, textord, "\u00b0", "\\textdegree", true); -// TODO: In LaTeX, \pounds can generate a different character in text and math -// mode, but among our fonts, only Main-Regular defines this character "163". -defineSymbol(math, textord, "\u00a3", "\\pounds"); -defineSymbol(math, textord, "\u00a3", "\\mathsterling", true); -defineSymbol(text, textord, "\u00a3", "\\pounds"); -defineSymbol(text, textord, "\u00a3", "\\textsterling", true); -defineSymbol(math, textord, "\u2720", "\\maltese"); -defineSymbol(text, textord, "\u2720", "\\maltese"); -defineSymbol(math, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\texteuro"); -defineSymbol(math, textord, "\u00a9", "\\copyright", true); -defineSymbol(text, textord, "\u00a9", "\\textcopyright"); - -// Italic Greek -defineSymbol(math, textord, "𝛤", "\\varGamma"); -defineSymbol(math, textord, "𝛥", "\\varDelta"); -defineSymbol(math, textord, "𝛩", "\\varTheta"); -defineSymbol(math, textord, "𝛬", "\\varLambda"); -defineSymbol(math, textord, "𝛯", "\\varXi"); -defineSymbol(math, textord, "𝛱", "\\varPi"); -defineSymbol(math, textord, "𝛴", "\\varSigma"); -defineSymbol(math, textord, "𝛶", "\\varUpsilon"); -defineSymbol(math, textord, "𝛷", "\\varPhi"); -defineSymbol(math, textord, "𝛹", "\\varPsi"); -defineSymbol(math, textord, "𝛺", "\\varOmega"); -defineSymbol(text, textord, "𝛤", "\\varGamma"); -defineSymbol(text, textord, "𝛥", "\\varDelta"); -defineSymbol(text, textord, "𝛩", "\\varTheta"); -defineSymbol(text, textord, "𝛬", "\\varLambda"); -defineSymbol(text, textord, "𝛯", "\\varXi"); -defineSymbol(text, textord, "𝛱", "\\varPi"); -defineSymbol(text, textord, "𝛴", "\\varSigma"); -defineSymbol(text, textord, "𝛶", "\\varUpsilon"); -defineSymbol(text, textord, "𝛷", "\\varPhi"); -defineSymbol(text, textord, "𝛹", "\\varPsi"); -defineSymbol(text, textord, "𝛺", "\\varOmega"); - - -// There are lots of symbols which are the same, so we add them in afterwards. -// All of these are textords in math mode -const mathTextSymbols = '0123456789/@."'; -for (let i = 0; i < mathTextSymbols.length; i++) { - const ch = mathTextSymbols.charAt(i); - defineSymbol(math, textord, ch, ch); -} - -// All of these are textords in text mode -const textSymbols = '0123456789!@*()-=+";:?/.,'; -for (let i = 0; i < textSymbols.length; i++) { - const ch = textSymbols.charAt(i); - defineSymbol(text, textord, ch, ch); -} - -// All of these are textords in text mode, and mathords in math mode -const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -for (let i = 0; i < letters.length; i++) { - const ch = letters.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// Some more letters in Unicode Basic Multilingual Plane. -const narrow = "ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ"; -for (let i = 0; i < narrow.length; i++) { - const ch = narrow.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// The next loop loads wide (surrogate pair) characters. -// We support some letters in the Unicode range U+1D400 to U+1D7FF, -// Mathematical Alphanumeric Symbols. -let wideChar = ""; -for (let i = 0; i < letters.length; i++) { - // The hex numbers in the next line are a surrogate pair. - // 0xD835 is the high surrogate for all letters in the range we support. - // 0xDC00 is the low surrogate for bold A. - wideChar = String.fromCharCode(0xd835, 0xdc00 + i); // A-Z a-z bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc34 + i); // A-Z a-z italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc68 + i); // A-Z a-z bold italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd04 + i); // A-Z a-z Fractur - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdda0 + i); // A-Z a-z sans-serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xddd4 + i); // A-Z a-z sans bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde08 + i); // A-Z a-z sans italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde70 + i); // A-Z a-z monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd38 + i); // A-Z a-z double struck - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - const ch = letters.charAt(i); - wideChar = String.fromCharCode(0xd835, 0xdc9c + i); // A-Z a-z calligraphic - defineSymbol(math, mathord, ch, wideChar); - defineSymbol(text, textord, ch, wideChar); -} - -// Next, some wide character numerals -for (let i = 0; i < 10; i++) { - wideChar = String.fromCharCode(0xd835, 0xdfce + i); // 0-9 bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfe2 + i); // 0-9 sans serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfec + i); // 0-9 bold sans - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdff6 + i); // 0-9 monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); -} - -/* - * Neither Firefox nor Chrome support hard line breaks or soft line breaks. - * (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs) - * So Temml has work-arounds for both hard and soft breaks. - * The work-arounds sadly do not work simultaneously. Any top-level hard - * break makes soft line breaks impossible. - * - * Hard breaks are simulated by creating a and putting each line in its own . - * - * To create soft line breaks, Temml avoids using the and tags. - * Then the top level of a element can be occupied by elements, and the browser - * will break after a if the expression extends beyond the container limit. - * - * We want the expression to render with soft line breaks after each top-level binary or - * relational operator, per TeXbook p. 173. So we gather the expression into s so that - * each ends in a binary or relational operator. - * - * Soft line breaks will not work in Chromium and Safari, only Firefox. - * - * Hopefully browsers will someday do their own linebreaking and we will be able to delete - * much of this module. - */ - -function setLineBreaks(expression, isDisplayMode, isAnnotated, color = undefined) { - if (color === undefined) { - // First, make one pass through the expression and split any color nodes. - const upperLimit = expression.length - 1; - for (let i = upperLimit; i >= 0; i--) { - const node = expression[i]; - if (node.type === "mstyle" && node.attributes.mathcolor) { - const color = node.attributes.mathcolor; - const fragment = setLineBreaks(node.children, isDisplayMode, isAnnotated, color); - if (!(fragment.type && fragment.type !== "mtable")) { - expression.splice(i, 1, ...fragment.children); - - } - } - } - } - - const tagName = color ? "mstyle" : "mrow"; - - const mtrs = []; - let mrows = []; - let block = []; - let canBeBIN = false; // The first node cannot be an infix binary operator. - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type && node.type === "mstyle" && node.attributes.mathcolor) { - // Start a new block. (Insert a soft linebreak.) - mrows.push(new mathMLTree.MathNode(tagName, block)); - // Insert the mstyle - mrows.push(node); - block = []; - continue - } - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(new mathMLTree.MathNode(tagName, block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - continue - } - block.push(node); - if (node.type && node.type === "mo" && !isDisplayMode && !isAnnotated) { - // This may be a place for a soft line break. - if (canBeBIN && !node.attributes.form) { - // Check if the following node is a \nobreak text node, e.g. "~"" - const next = i < expression.length - 1 ? expression[i + 1] : null; - let glueIsFreeOfNobreak = true; - if ( - !( - next && - next.type === "mtext" && - next.attributes.linebreak && - next.attributes.linebreak === "nobreak" - ) - ) { - // We may need to start a new block. - // First, put any post-operator glue on same line as operator. - for (let j = i + 1; j < expression.length; j++) { - const nd = expression[j]; - if ( - nd.type && - nd.type === "mspace" && - !(nd.attributes.linebreak && nd.attributes.linebreak === "newline") - ) { - block.push(nd); - i += 1; - if ( - nd.attributes && - nd.attributes.linebreak && - nd.attributes.linebreak === "nobreak" - ) { - glueIsFreeOfNobreak = false; - } - } else { - break; - } - } - } - if (glueIsFreeOfNobreak) { - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - block = []; - } - canBeBIN = false; - } - const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"; - // Any operator that follows an open delimiter is unary. - canBeBIN = !(node.attributes.separator || isOpenDelimiter); - } else { - canBeBIN = true; - } - } - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - const mtr = new mathMLTree.MathNode("mtr", [mtd]); - mtrs.push(mtr); - const mtable = new mathMLTree.MathNode("mtable", mtrs); - if (!isDisplayMode) { - mtable.setAttribute("columnalign", "left"); - mtable.setAttribute("rowspacing", "0em"); - } - return mtable - } - return mathMLTree.newDocumentFragment(mrows); -} - -/** - * This file converts a parse tree into a cooresponding MathML tree. The main - * entry point is the `buildMathML` function, which takes a parse tree from the - * parser. - */ - -/** - * Takes a symbol and converts it into a MathML text node after performing - * optional replacement from symbols.js. - */ -const makeText = function(text, mode, style) { - if ( - symbols[mode][text] && - symbols[mode][text].replace && - text.charCodeAt(0) !== 0xd835 && - !( - Object.prototype.hasOwnProperty.call(ligatures, text) && - style && - ((style.fontFamily && style.fontFamily.substr(4, 2) === "tt") || - (style.font && style.font.substr(4, 2) === "tt")) - ) - ) { - text = symbols[mode][text].replace; - } - - return new mathMLTree.TextNode(text); -}; - -/** - * Wrap the given array of nodes in an node if needed, i.e., - * unless the array has length 1. Always returns a single node. - */ -const makeRow = function(body) { - if (body.length === 1) { - return body[0]; - } else { - return new mathMLTree.MathNode("mrow", body); - } -}; - -/** - * Takes a list of nodes, builds them, and returns a list of the generated - * MathML nodes. Also combine consecutive outputs into a single - * tag. - */ -const buildExpression = function(expression, style, isOrdgroup) { - if (expression.length === 1) { - const group = buildGroup(expression[0], style); - if (isOrdgroup && group instanceof MathNode && group.type === "mo") { - // When TeX writers want to suppress spacing on an operator, - // they often put the operator by itself inside braces. - group.setAttribute("lspace", "0em"); - group.setAttribute("rspace", "0em"); - } - return [group]; - } - - const groups = []; - for (let i = 0; i < expression.length; i++) { - const group = buildGroup(expression[i], style); - groups.push(group); - } - return groups; -}; - -/** - * Equivalent to buildExpression, but wraps the elements in an - * if there's more than one. Returns a single node instead of an array. - */ -const buildExpressionRow = function(expression, style, isOrdgroup) { - return makeRow(buildExpression(expression, style, isOrdgroup)); -}; - -/** - * Takes a group from the parser and calls the appropriate groupBuilders function - * on it to produce a MathML node. - */ -const buildGroup = function(group, style) { - if (!group) { - return new mathMLTree.MathNode("mrow"); - } - - if (_mathmlGroupBuilders[group.type]) { - // Call the groupBuilders function - const result = _mathmlGroupBuilders[group.type](group, style); - return result; - } else { - throw new ParseError("Got group of unknown type: '" + group.type + "'"); - } -}; - - -const taggedExpression = (expression, tag, style, leqno, preventTagLap) => { - const glue = new mathMLTree.MathNode("mtd", []); - glue.setAttribute("style", "padding: 0;width: 50%;"); - tag = buildExpressionRow(tag[0].body, style); - tag.classes = ["tml-tag"]; - if (!preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - tag.setAttribute((leqno ? "rspace" : "lspace"), "-1width"); - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = leqno - ? [tag, glue, expression, glue] - : [glue, expression, glue, tag]; - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.setAttribute("width", "100%"); - return table -}; - -/** - * Takes a full parse tree and settings and builds a MathML representation of - * it. - */ -function buildMathML(tree, texExpression, style, settings) { - // Strip off outer tag wrapper for processing below. - let tag = null; - if (tree.length === 1 && tree[0].type === "tag") { - tag = tree[0].tag; - tree = tree[0].body; - } - - const expression = buildExpression(tree, style); - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - && !(n1.type === "mstyle" && n1.attributes.mathcolor) - ? expression[0] - : setLineBreaks(expression, settings.displayMode, settings.annotate); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno, settings.preventTagLap); - } - - let semantics; - if (settings.annotate) { - // Build a TeX annotation of the source - const annotation = new mathMLTree.MathNode( - "annotation", [new mathMLTree.TextNode(texExpression)]); - annotation.setAttribute("encoding", "application/x-tex"); - semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = settings.annotate - ? new mathMLTree.MathNode("math", [semantics]) - : new mathMLTree.MathNode("math", [wrapper]); - - if (settings.xml) { - math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); - } - if (settings.displayMode) { - math.setAttribute("display", "block"); - } - return math; -} - -const mathmlBuilder = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.mathMLnode(group.label) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup(group.base, style), accentNode] - ); - - node.setAttribute("accent", "true"); - return node; -}; - -const NON_STRETCHY_ACCENT_REGEX = new RegExp( - [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" - ] - .map((accent) => `\\${accent}`) - .join("|") -); - -// Accents -defineFunction({ - type: "accent", - names: [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring", - "\\overparen", - "\\widecheck", - "\\widehat", - "\\wideparen", - "\\widetilde", - "\\overrightarrow", - "\\overleftarrow", - "\\Overrightarrow", - "\\overleftrightarrow", - "\\overgroup", - "\\overleftharpoon", - "\\overrightharpoon" - ], - props: { - numArgs: 1 - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - - const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); - const isShifty = - !isStretchy || - context.funcName === "\\widehat" || - context.funcName === "\\widetilde" || - context.funcName === "\\widecheck"; - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - isShifty: isShifty, - base: base - }; - }, - mathmlBuilder -}); - -// Text-mode accents -defineFunction({ - type: "accent", - names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\c", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"], - props: { - numArgs: 1, - allowedInText: true, - allowedInMath: true, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - const mode = context.parser.mode; - - if (mode === "math" && context.parser.settings.strict) { - // LaTeX only writes a warning. It doesn't stop. We'll issue the same warning. - // eslint-disable-next-line no-console - console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`); - } - - return { - type: "accent", - mode: mode, - label: context.funcName, - isStretchy: false, - isShifty: true, - base: base - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "accentUnder", - names: [ - "\\underleftarrow", - "\\underrightarrow", - "\\underleftrightarrow", - "\\undergroup", - "\\underparen", - "\\utilde" - ], - props: { - numArgs: 1 - }, - handler: ({ parser, funcName }, args) => { - const base = args[0]; - return { - type: "accentUnder", - mode: parser.mode, - label: funcName, - base: base - }; - }, - mathmlBuilder: (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - const node = new mathMLTree.MathNode("munder", [ - buildGroup(group.base, style), - accentNode - ]); - node.setAttribute("accentunder", "true"); - return node; - } -}); - -// Helper functions -const paddedNode = (group, width = "+0.6em") => { - const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); - node.setAttribute("width", width); - node.setAttribute("lspace", "0.3em"); - return node; -}; - -const munderoverNode = (label, body, below, style, macros = {}) => { - const arrowNode = stretchy.mathMLnode(label, macros); - const minWidth = label.charAt(1) === "x" - ? "1.75em" // mathtools extensible arrows - : label.slice(2, 4) === "cd" - ? "3.0em" // cd package arrows - : "2.0em"; // mhchem arrows - arrowNode.setAttribute("minsize", minWidth); - // minsize attribute doesn't work in Firefox. - // https://bugzilla.mozilla.org/show_bug.cgi?id=320303 - const labelStyle = style.incrementLevel(); - - const upperNode = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)) - ? paddedNode(buildGroup(body, labelStyle)) - // Since Firefox does not recognize minsize set on the arrow, - // create an upper node w/correct width. - : paddedNode(null, minWidth); - const lowerNode = (below && below.body && - (below.body.body || below.body.length > 0)) - ? paddedNode(buildGroup(below, labelStyle)) - : paddedNode(null, minWidth); - const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - return node -}; - -// Stretchy arrows with an optional argument -defineFunction({ - type: "xArrow", - names: [ - "\\xleftarrow", - "\\xrightarrow", - "\\xLeftarrow", - "\\xRightarrow", - "\\xleftrightarrow", - "\\xLeftrightarrow", - "\\xhookleftarrow", - "\\xhookrightarrow", - "\\xmapsto", - "\\xrightharpoondown", - "\\xrightharpoonup", - "\\xleftharpoondown", - "\\xleftharpoonup", - "\\xlongequal", - "\\xtwoheadrightarrow", - "\\xtwoheadleftarrow", - // The next 7 functions are here only to support mhchem - "\\yields", - "\\yieldsLeft", - "\\mesomerism", - "\\longrightharpoonup", - "\\longleftharpoondown", - "\\equilibriumRight", - "\\equilibriumLeft", - // The next 3 functions are here only to support the {CD} environment. - "\\\\cdrightarrow", - "\\\\cdleftarrow", - "\\\\cdlongequal" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - return { - type: "xArrow", - mode: parser.mode, - label: funcName, - body: args[0], - below: optArgs[0], - macros: parser.gullet.macros // Contains SVG paths for mhchem equilibrium arrows. - }; - }, - mathmlBuilder(group, style) { - return munderoverNode(group.label, group.body, group.below, style, group.macros) - } -}); - -const arrowComponent = { - "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"], - "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"], - "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"], - "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"], - "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"] -}; - -// Browser are not good at stretching stacked arrows such as ⇄. -// So we stack a pair of single arrows. -defineFunction({ - type: "stackedArrow", - names: [ - "\\xtofrom", // expfeil - "\\xleftrightharpoons", // mathtools - "\\xrightleftharpoons", // mathtools - "\\yieldsLeftRight", // mhchem - "\\equilibrium" // mhchem - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - const lowerArrowBody = args[0] - ? { - type: "hphantom", - mode: parser.mode, - body: args[0] - } - : null; - const upperArrowBelow = optArgs[0] - ? { - type: "hphantom", - mode: parser.mode, - body: optArgs[0] - } - : null; - return { - type: "stackedArrow", - mode: parser.mode, - label: funcName, - body: args[0], - upperArrowBelow, - lowerArrowBody, - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - const topLabel = arrowComponent[group.label][0]; - const botLabel = arrowComponent[group.label][1]; - const topArrow = munderoverNode(topLabel, group.body, group.upperArrowBelow, style); - const botArrow = munderoverNode(botLabel, group.lowerArrowBody, group.below, style); - - const topSpace = new mathMLTree.MathNode("mspace"); - topSpace.setAttribute("width", "0.2778em"); - const botSpace = new mathMLTree.MathNode("mspace"); - botSpace.setAttribute("width", "-0.2778em"); - - const raiseNode = new mathMLTree.MathNode("mpadded", [topSpace, topArrow]); - raiseNode.setAttribute("voffset", "0.3em"); - raiseNode.setAttribute("height", "+0.3em"); - raiseNode.setAttribute("depth", "-0.3em"); - raiseNode.setAttribute("width", "0em"); - - const botRow = new mathMLTree.MathNode("mrow", [botSpace, botArrow]); - - const wrapper = new mathMLTree.MathNode("mpadded", [raiseNode, botRow]); - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - wrapper.setAttribute("lspace", "0em"); - wrapper.setAttribute("rspace", "0em"); - return wrapper - } -}); - -defineFunction({ - type: "cancelto", - names: ["\\cancelto"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "cancelto", - mode: parser.mode, - value: args[0], - expression: args[1] - }; - }, - mathmlBuilder(group, style) { - const value = new mathMLTree.MathNode( - "mpadded", - [buildGroup(group.value, style)] - ); - value.setAttribute("depth", `-0.1em`); - value.setAttribute("height", `+0.1em`); - value.setAttribute("voffset", `0.1em`); - - const expression = new mathMLTree.MathNode( - "menclose", - [buildGroup(group.expression, style)] - ); - expression.setAttribute("notation", `updiagonalarrow`); - - return new mathMLTree.MathNode("msup", [expression, value]) - } -}); - -/** - * Asserts that the node is of the given type and returns it with stricter - * typing. Throws if the node's type does not match. - */ -function assertNodeType(node, type) { - if (!node || node.type !== type) { - throw new Error( - `Expected node of type ${type}, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return node; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function assertSymbolNodeType(node) { - const typedNode = checkSymbolNodeType(node); - if (!typedNode) { - throw new Error( - `Expected node of symbol group type, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return typedNode; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function checkSymbolNodeType(node) { - if (node && (node.type === "atom" || - Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) { - return node; - } - return null; -} - -const cdArrowFunctionName = { - ">": "\\\\cdrightarrow", - "<": "\\\\cdleftarrow", - "=": "\\\\cdlongequal", - A: "\\uparrow", - V: "\\downarrow", - "|": "\\Vert", - ".": "no arrow" -}; - -const newCell = () => { - // Create an empty cell, to be filled below with parse nodes. - return { type: "styling", body: [], mode: "math", scriptLevel: "display" }; -}; - -const isStartOfArrow = (node) => { - return node.type === "textord" && node.text === "@"; -}; - -const isLabelEnd = (node, endChar) => { - return (node.type === "mathord" || node.type === "atom") && node.text === endChar; -}; - -function cdArrow(arrowChar, labels, parser) { - // Return a parse tree of an arrow and its labels. - // This acts in a way similar to a macro expansion. - const funcName = cdArrowFunctionName[arrowChar]; - switch (funcName) { - case "\\\\cdrightarrow": - case "\\\\cdleftarrow": - return parser.callFunction(funcName, [labels[0]], [labels[1]]); - case "\\uparrow": - case "\\downarrow": { - const leftLabel = parser.callFunction("\\\\cdleft", [labels[0]], []); - const bareArrow = { - type: "atom", - text: funcName, - mode: "math", - family: "rel" - }; - const sizedArrow = parser.callFunction("\\Big", [bareArrow], []); - const rightLabel = parser.callFunction("\\\\cdright", [labels[1]], []); - const arrowGroup = { - type: "ordgroup", - mode: "math", - body: [leftLabel, sizedArrow, rightLabel] - }; - return parser.callFunction("\\\\cdparent", [arrowGroup], []); - } - case "\\\\cdlongequal": - return parser.callFunction("\\\\cdlongequal", [], []); - case "\\Vert": { - const arrow = { type: "textord", text: "\\Vert", mode: "math" }; - return parser.callFunction("\\Big", [arrow], []); - } - default: - return { type: "textord", text: " ", mode: "math" }; - } -} - -function parseCD(parser) { - // Get the array's parse nodes with \\ temporarily mapped to \cr. - const parsedRows = []; - parser.gullet.beginGroup(); - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - parser.gullet.beginGroup(); - while (true) { // eslint-disable-line no-constant-condition - // Get the parse nodes for the next row. - parsedRows.push(parser.parseExpression(false, "\\\\")); - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - const next = parser.fetch().text; - if (next === "&" || next === "\\\\") { - parser.consume(); - } else if (next === "\\end") { - if (parsedRows[parsedRows.length - 1].length === 0) { - parsedRows.pop(); // final row ended in \\ - } - break; - } else { - throw new ParseError("Expected \\\\ or \\cr or \\end", parser.nextToken); - } - } - - let row = []; - const body = [row]; - - // Loop thru the parse nodes. Collect them into cells and arrows. - for (let i = 0; i < parsedRows.length; i++) { - // Start a new row. - const rowNodes = parsedRows[i]; - // Create the first cell. - let cell = newCell(); - - for (let j = 0; j < rowNodes.length; j++) { - if (!isStartOfArrow(rowNodes[j])) { - // If a parseNode is not an arrow, it goes into a cell. - cell.body.push(rowNodes[j]); - } else { - // Parse node j is an "@", the start of an arrow. - // Before starting on the arrow, push the cell into `row`. - row.push(cell); - - // Now collect parseNodes into an arrow. - // The character after "@" defines the arrow type. - j += 1; - const arrowChar = assertSymbolNodeType(rowNodes[j]).text; - - // Create two empty label nodes. We may or may not use them. - const labels = new Array(2); - labels[0] = { type: "ordgroup", mode: "math", body: [] }; - labels[1] = { type: "ordgroup", mode: "math", body: [] }; - - // Process the arrow. - if ("=|.".indexOf(arrowChar) > -1) ; else if ("<>AV".indexOf(arrowChar) > -1) { - // Four arrows, `@>>>`, `@<<<`, `@AAA`, and `@VVV`, each take - // two optional labels. E.g. the right-point arrow syntax is - // really: @>{optional label}>{optional label}> - // Collect parseNodes into labels. - for (let labelNum = 0; labelNum < 2; labelNum++) { - let inLabel = true; - for (let k = j + 1; k < rowNodes.length; k++) { - if (isLabelEnd(rowNodes[k], arrowChar)) { - inLabel = false; - j = k; - break; - } - if (isStartOfArrow(rowNodes[k])) { - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[k] - ); - } - - labels[labelNum].body.push(rowNodes[k]); - } - if (inLabel) { - // isLabelEnd never returned a true. - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[j] - ); - } - } - } else { - throw new ParseError(`Expected one of "<>AV=|." after @.`); - } - - // Now join the arrow to its labels. - const arrow = cdArrow(arrowChar, labels, parser); - - // Wrap the arrow in a styling node - row.push(arrow); - // In CD's syntax, cells are implicit. That is, everything that - // is not an arrow gets collected into a cell. So create an empty - // cell now. It will collect upcoming parseNodes. - cell = newCell(); - } - } - if (i % 2 === 0) { - // Even-numbered rows consist of: cell, arrow, cell, arrow, ... cell - // The last cell is not yet pushed into `row`, so: - row.push(cell); - } else { - // Odd-numbered rows consist of: vert arrow, empty cell, ... vert arrow - // Remove the empty cell that was placed at the beginning of `row`. - row.shift(); - } - row = []; - body.push(row); - } - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - // define column separation. - const cols = new Array(body[0].length).fill({ - type: "align", - align: "c" - }); - - return { - type: "array", - mode: "math", - body, - arraystretch: 1, - addJot: true, - rowGaps: [null], - cols, - colSeparationType: "CD", - hLinesBeforeRow: new Array(body.length + 1).fill([]) - }; -} - -// The functions below are not available for general use. -// They are here only for internal use by the {CD} environment in placing labels -// next to vertical arrows. - -// We don't need any such functions for horizontal arrows because we can reuse -// the functionality that already exists for extensible arrows. - -defineFunction({ - type: "cdlabel", - names: ["\\\\cdleft", "\\\\cdright"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "cdlabel", - mode: parser.mode, - side: funcName.slice(4), - label: args[0] - }; - }, - mathmlBuilder(group, style) { - let label = new mathMLTree.MathNode("mrow", [buildGroup(group.label, style)]); - label = new mathMLTree.MathNode("mpadded", [label]); - label.setAttribute("width", "0"); - if (group.side === "left") { - label.setAttribute("lspace", "-1width"); - } - // We have to guess at vertical alignment. We know the arrow is 1.8em tall, - // But we don't know the height or depth of the label. - label.setAttribute("voffset", "0.7em"); - label = new mathMLTree.MathNode("mstyle", [label]); - label.setAttribute("displaystyle", "false"); - label.setAttribute("scriptlevel", "1"); - return label; - } -}); - -defineFunction({ - type: "cdlabelparent", - names: ["\\\\cdparent"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - return { - type: "cdlabelparent", - mode: parser.mode, - fragment: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow", [buildGroup(group.fragment, style)]); - } -}); - -// \@char is an internal function that takes a grouped decimal argument like -// {123} and converts into symbol with code 123. It is used by the *macro* -// \char defined in macros.js. -defineFunction({ - type: "textord", - names: ["\\@char"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - const arg = assertNodeType(args[0], "ordgroup"); - const group = arg.body; - let number = ""; - for (let i = 0; i < group.length; i++) { - const node = assertNodeType(group[i], "textord"); - number += node.text; - } - const code = parseInt(number); - if (isNaN(code)) { - throw new ParseError(`\\@char has non-numeric argument ${number}`) - } - return { - type: "textord", - mode: parser.mode, - text: String.fromCodePoint(code) - } - } -}); - -/* In LaTeX, \colon is defined as: - * \renewcommand{\colon}{\nobreak\mskip2mu\mathpunct{}\nonscript - * \mkern-\thinmuskip{:}\mskip6muplus1mu\relax} - * - * Doing that with a Temml macro produces semantically poor MathML. Do it more directly. - */ - -defineFunction({ - type: "colonFunction", - names: ["\\colon"], - props: { numArgs: 0 }, - handler({ parser }) { return { type: "colonFunction", mode: parser.mode } }, - mathmlBuilder(group, style) { - const mo = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(":")]); - // lspace depends on the script level. - mo.attributes.lspace = (style.level < 2 ? "0.05556em" : "0.1111em"); - mo.attributes.rspace = "0.3333em"; // 6mu - return mo - } -}); - -defineFunction({ - type: "colonequal", - names: [":"], - props: { numArgs: 0 }, - handler({ parser }, args) { - if (parser.fetch().text === "=") { - // Special case for := - parser.consume(); - return { type: "colonequal", mode: parser.mode } - } - return { type: "atom", family: "rel", text: ":", mode: parser.mode } - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u2254")]) - } -}); - -// Helpers -const htmlRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6})$/i; -const htmlOrNameRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i; -const RGBregEx = /^ *\d{1,3} *(?:, *\d{1,3} *){2}$/; -const rgbRegEx = /^ *[10](?:\.\d*)? *(?:, *[10](?:\.\d*)? *){2}$/; -const xcolorHtmlRegEx = /^[a-f0-9]{6}$/i; -const toHex = num => { - let str = num.toString(16); - if (str.length === 1) { str = "0" + str; } - return str -}; - -// Colors from Tables 4.1 and 4.2 of the xcolor package. -// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx. -// Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable -// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274. -const xcolors = JSON.parse(`{ - "Apricot": "#ffb484", - "Aquamarine": "#08b4bc", - "Bittersweet": "#c84c14", - "blue": "#0000FF", - "Blue": "#303494", - "BlueGreen": "#08b4bc", - "BlueViolet": "#503c94", - "BrickRed": "#b8341c", - "brown": "#BF804", - "Brown": "#802404", - "BurntOrange": "#f8941c", - "CadetBlue": "#78749c", - "CarnationPink": "#f884b4", - "Cerulean": "#08a4e4", - "CornflowerBlue": "#40ace4", - "cyan": "#00FFF", - "Cyan": "#08acec", - "Dandelion": "#ffbc44", - "darkgray": "#404040", - "DarkOrchid": "#a8548c", - "Emerald": "#08ac9c", - "ForestGreen": "#089c54", - "Fuchsia": "#90348c", - "Goldenrod": "#ffdc44", - "gray": "#80808", - "Gray": "#98949c", - "green": "#00FF0", - "Green": "#08a44c", - "GreenYellow": "#e0e474", - "JungleGreen": "#08ac9c", - "Lavender": "#f89cc4", - "lightgray": "#BFBFB", - "lime": "#BFFF00", - "LimeGreen": "#90c43c", - "magenta": "#FF00F", - "Magenta": "#f0048c", - "Mahogany": "#b0341c", - "Maroon": "#b03434", - "Melon": "#f89c7c", - "MidnightBlue": "#086494", - "Mulberry": "#b03c94", - "NavyBlue": "#086cbc", - "olive": "#7F7F00", - "OliveGreen": "#407c34", - "orange": "#FF800", - "Orange": "#f8843c", - "OrangeRed": "#f0145c", - "Orchid": "#b074ac", - "Peach": "#f8945c", - "Periwinkle": "#8074bc", - "PineGreen": "#088c74", - "pink": "#ff7f7f", - "Plum": "#98248c", - "ProcessBlue": "#08b4ec", - "purple": "#BF0040", - "Purple": "#a0449c", - "RawSienna": "#983c04", - "red": "#ff0000", - "Red": "#f01c24", - "RedOrange": "#f86434", - "RedViolet": "#a0246c", - "Rhodamine": "#f0549c", - "Royallue": "#0874bc", - "RoyalPurple": "#683c9c", - "RubineRed": "#f0047c", - "Salmon": "#f8948c", - "SeaGreen": "#30bc9c", - "Sepia": "#701404", - "SkyBlue": "#48c4dc", - "SpringGreen": "#c8dc64", - "Tan": "#e09c74", - "teal": "#007F7F", - "TealBlue": "#08acb4", - "Thistle": "#d884b4", - "Turquoise": "#08b4cc", - "violet": "#800080", - "Violet": "#60449c", - "VioletRed": "#f054a4", - "WildStrawberry": "#f0246c", - "yellow": "#FFFF00", - "Yellow": "#fff404", - "YellowGreen": "#98cc6c", - "YellowOrange": "#ffa41c" -}`); - -const colorFromSpec = (model, spec) => { - let color = ""; - if (model === "HTML") { - if (!htmlRegEx.test(spec)) { - throw new ParseError("Invalid HTML input.") - } - color = spec; - } else if (model === "RGB") { - if (!RGBregEx.test(spec)) { - throw new ParseError("Invalid RGB input.") - } - spec.split(",").map(e => { color += toHex(Number(e.trim())); }); - } else { - if (!rgbRegEx.test(spec)) { - throw new ParseError("Invalid rbg input.") - } - spec.split(",").map(e => { - const num = Number(e.trim()); - if (num > 1) { throw new ParseError("Color rgb input must be < 1.") } - color += toHex((num * 255)); - }); - } - if (color.charAt(0) !== "#") { color = "#" + color; } - return color -}; - -const validateColor = (color, macros) => { - const macroName = `\\\\color@${color}`; // from \defineColor. - const match = htmlOrNameRegEx.exec(color); - if (!match) { throw new ParseError("Invalid color: '" + color + "'") } - // We allow a 6-digit HTML color spec without a leading "#". - // This follows the xcolor package's HTML color model. - // Predefined color names are all missed by this RegEx pattern. - if (xcolorHtmlRegEx.test(color)) { - return "#" + color - } else if (color.charAt(0) === "#") { - return color - } else if (macros.has(macroName)) { - color = macros.get(macroName).tokens[0].text; - } else if (xcolors[color]) { - color = xcolors[color]; - } - return color -}; - -const mathmlBuilder$1 = (group, style) => { - const inner = buildExpression(group.body, style.withColor(group.color)); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("mathcolor", group.color); - // Wrap w/. We get better operator spacing that way. - return new mathMLTree.MathNode("mrow", [node]) -}; - -defineFunction({ - type: "color", - names: ["\\textcolor"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "original"] - }, - handler({ parser }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - const body = args[1]; - return { - type: "color", - mode: parser.mode, - color, - body: ordargument(body) - } - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineFunction({ - type: "color", - names: ["\\color"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw"] - }, - handler({ parser, breakOnTokenText }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - - // Set macro \current@color in current namespace to store the current - // color, mimicking the behavior of color.sty. - // This is currently used just to correctly color a \right - // that follows a \color command. - parser.gullet.macros.set("\\current@color", color); - - // Parse out the implicit body that should be colored. - // Since \color nodes should not be nested, break on \color. - const body = parser.parseExpression(true, "\\color"); - - return { - type: "color", - mode: parser.mode, - color, - body - } - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineFunction({ - type: "color", - names: ["\\definecolor"], - props: { - numArgs: 3, - allowedInText: true, - argTypes: ["raw", "raw", "raw"] - }, - handler({ parser }, args) { - const name = assertNodeType(args[0], "raw").string; - if (!/^[A-Za-z]+$/.test(name)) { - throw new ParseError("Color name must be latin letters.") - } - const model = assertNodeType(args[1], "raw").string; - if (!["HTML", "RGB", "rgb"].includes(model)) { - throw new ParseError("Color model must be HTML, RGB, or rgb.") - } - const spec = assertNodeType(args[2], "raw").string; - const color = colorFromSpec(model, spec); - parser.gullet.macros.set(`\\\\color@${name}`, { tokens: [{ text: color }], numArgs: 0 }); - return { type: "internal", mode: parser.mode } - } - // No mathmlBuilder. The point of \definecolor is to set a macro. -}); - -/** - * This file does conversion between units. In particular, it provides - * calculateSize to convert other units into CSS units. - */ - -const ptPerUnit = { - // Convert to CSS (Postscipt) points, not TeX points - // https://en.wikibooks.org/wiki/LaTeX/Lengths and - // https://tex.stackexchange.com/a/8263 - pt: 800 / 803, // convert TeX point to CSS (Postscript) point - pc: (12 * 800) / 803, // pica - dd: ((1238 / 1157) * 800) / 803, // didot - cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot) - nd: ((685 / 642) * 800) / 803, // new didot - nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot) - sp: ((1 / 65536) * 800) / 803 // scaled point (TeX's internal smallest unit) -}; - -/** - * Determine whether the specified unit (either a string defining the unit - * or a "size" parse node containing a unit field) is valid. - */ -const validUnits = [ - "em", - "ex", - "mu", - "pt", - "mm", - "cm", - "in", - "px", - "bp", - "pc", - "dd", - "cc", - "nd", - "nc", - "sp" -]; - -const validUnit = function(unit) { - if (typeof unit !== "string") { - unit = unit.unit; - } - return validUnits.indexOf(unit) > -1 -}; - -const emScale = styleLevel => { - const scriptLevel = Math.max(styleLevel - 1, 0); - return [1, 0.7, 0.5][scriptLevel] -}; - -/* - * Convert a "size" parse node (with numeric "number" and string "unit" fields, - * as parsed by functions.js argType "size") into a CSS value. - */ -const calculateSize = function(sizeValue, style) { - const number = sizeValue.number; - const unit = sizeValue.unit; - switch (unit) { - case "mm": - case "cm": - case "in": - case "px": - return { number, unit }; // absolute CSS units. - case "em": - case "ex": - // In TeX, em and ex do not change size in \scriptstyle. - return { number: utils.round(number / emScale(style.level)), unit }; - case "bp": - return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch). - case "pt": - case "pc": - case "dd": - case "cc": - case "nd": - case "nc": - case "sp": - return { number: utils.round(number * ptPerUnit[unit]), unit: "pt" } - case "mu": { - return { number: utils.round(number / 18), unit: "em" } - } - default: - throw new ParseError("Invalid unit: '" + unit + "'") - } -}; - -// Row breaks within tabular environments, and line breaks at top level - -// \DeclareRobustCommand\\{...\@xnewline} -defineFunction({ - type: "cr", - names: ["\\\\"], - props: { - numArgs: 0, - numOptionalArgs: 1, - argTypes: ["size"], - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = optArgs[0]; - if (parser.settings.displayMode && parser.settings.strict === "warn") { - parser.settings.reportNonstrict( - "newLineInDisplayMode", - "In LaTeX, \\\\ or \\newline " + "does nothing in display mode" - ); - } - const newLine = !parser.settings.displayMode || parser.settings.strict !== true; - return { - type: "cr", - mode: parser.mode, - newLine, - size: size && assertNodeType(size, "size").value - } - }, - - // The following builder is called only at the top level, - // not within tabular/array environments. - - mathmlBuilder(group, style) { - // MathML 3.0 calls for newline to occur in an or an . - // Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.linebreaking - const node = new mathMLTree.MathNode("mo"); - if (group.newLine) { - node.setAttribute("linebreak", "newline"); - if (group.size) { - const size = calculateSize(group.size, style); - node.setAttribute("height", size.number + size.unit); - } - } - return node - } -}); - -const checkControlSequence = (tok) => { - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - return name; -}; - -const getRHS = (parser) => { - let tok = parser.gullet.popToken(); - if (tok.text === "=") { - // consume optional equals - tok = parser.gullet.popToken(); - if (tok.text === " ") { - // consume one optional space - tok = parser.gullet.popToken(); - } - } - return tok; -}; - -const letCommand = (parser, name, tok) => { - let macro = parser.gullet.macros.get(tok.text); - if (macro == null) { - // don't expand it later even if a macro with the same name is defined - // e.g., \let\foo=\frac \def\frac{\relax} \frac12 - tok.noexpand = true; - macro = { - tokens: [tok], - numArgs: 0, - // reproduce the same behavior in expansion - unexpandable: !parser.gullet.isExpandable(tok.text) - }; - } - parser.gullet.macros.set(name, macro); -}; - -// Basic support for macro definitions: \def -// -> -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\edef"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let tok = parser.gullet.popToken(); - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - - let numArgs = 0; - let insert; - const delimiters = [[]]; - // contains no braces - while (parser.gullet.future().text !== "{") { - tok = parser.gullet.popToken(); - if (tok.text === "#") { - // If the very last character of the is #, so that - // this # is immediately followed by {, TeX will behave as if the { - // had been inserted at the right end of both the parameter text - // and the replacement text. - if (parser.gullet.future().text === "{") { - insert = parser.gullet.future(); - delimiters[numArgs].push("{"); - break; - } - - // A parameter, the first appearance of # must be followed by 1, - // the next by 2, and so on; up to nine #’s are allowed - tok = parser.gullet.popToken(); - if (!/^[1-9]$/.test(tok.text)) { - throw new ParseError(`Invalid argument number "${tok.text}"`); - } - if (parseInt(tok.text) !== numArgs + 1) { - throw new ParseError(`Argument number "${tok.text}" out of order`); - } - numArgs++; - delimiters.push([]); - } else if (tok.text === "EOF") { - throw new ParseError("Expected a macro definition"); - } else { - delimiters[numArgs].push(tok.text); - } - } - // replacement text, enclosed in '{' and '}' and properly nested - let { tokens } = parser.gullet.consumeArg(); - if (insert) { - tokens.unshift(insert); - } - - if (funcName === "\\edef") { - tokens = parser.gullet.expandTokens(tokens); - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set(name, { tokens, numArgs, delimiters } - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: ["\\let"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.consumeSpaces(); - const tok = getRHS(parser); - letCommand(parser, name, tok); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: ["\\futurelet"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - const middle = parser.gullet.popToken(); - const tok = parser.gullet.popToken(); - letCommand(parser, name, tok); - parser.gullet.pushToken(tok); - parser.gullet.pushToken(middle); - return { type: "internal", mode: parser.mode }; - } -}); - -defineFunction({ - type: "internal", - names: ["\\newcommand", "\\renewcommand", "\\providecommand"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let name = ""; - const tok = parser.gullet.popToken(); - if (tok.text === "{") { - name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.popToken(); - } else { - name = checkControlSequence(tok); - } - - const exists = parser.gullet.isDefined(name); - if (exists && funcName === "\\newcommand") { - throw new ParseError( - `\\newcommand{${name}} attempting to redefine ${name}; use \\renewcommand` - ); - } - if (!exists && funcName === "\\renewcommand") { - throw new ParseError( - `\\renewcommand{${name}} when command ${name} does not yet exist; use \\newcommand` - ); - } - - let numArgs = 0; - if (parser.gullet.future().text === "[") { - let tok = parser.gullet.popToken(); - tok = parser.gullet.popToken(); - if (!/^[0-9]$/.test(tok.text)) { - throw new ParseError(`Invalid number of arguments: "${tok.text}"`); - } - numArgs = parseInt(tok.text); - tok = parser.gullet.popToken(); - if (tok.text !== "]") { - throw new ParseError(`Invalid argument "${tok.text}"`); - } - } - - // replacement text, enclosed in '{' and '}' and properly nested - const { tokens } = parser.gullet.consumeArg(); - - parser.gullet.macros.set(name, { tokens, numArgs }); - - return { type: "internal", mode: parser.mode }; - - } -}); - -// Extra data needed for the delimiter handler down below -const delimiterSizes = { - "\\bigl": { mclass: "mopen", size: 1 }, - "\\Bigl": { mclass: "mopen", size: 2 }, - "\\biggl": { mclass: "mopen", size: 3 }, - "\\Biggl": { mclass: "mopen", size: 4 }, - "\\bigr": { mclass: "mclose", size: 1 }, - "\\Bigr": { mclass: "mclose", size: 2 }, - "\\biggr": { mclass: "mclose", size: 3 }, - "\\Biggr": { mclass: "mclose", size: 4 }, - "\\bigm": { mclass: "mrel", size: 1 }, - "\\Bigm": { mclass: "mrel", size: 2 }, - "\\biggm": { mclass: "mrel", size: 3 }, - "\\Biggm": { mclass: "mrel", size: 4 }, - "\\big": { mclass: "mord", size: 1 }, - "\\Big": { mclass: "mord", size: 2 }, - "\\bigg": { mclass: "mord", size: 3 }, - "\\Bigg": { mclass: "mord", size: 4 } -}; - -const delimiters = [ - "(", - "\\lparen", - ")", - "\\rparen", - "[", - "\\lbrack", - "]", - "\\rbrack", - "\\{", - "\\lbrace", - "\\}", - "\\rbrace", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lt", - "\\gt", - "\\lvert", - "\\rvert", - "\\lVert", - "\\rVert", - "\\lgroup", - "\\rgroup", - "\u27ee", - "\u27ef", - "\\lmoustache", - "\\rmoustache", - "\u23b0", - "\u23b1", - "\\llbracket", - "\\rrbracket", - "\u27e6", - "\u27e6", - "\\lBrace", - "\\rBrace", - "\u2983", - "\u2984", - "/", - "\\backslash", - "|", - "\\vert", - "\\|", - "\\Vert", - "\\uparrow", - "\\Uparrow", - "\\downarrow", - "\\Downarrow", - "\\updownarrow", - "\\Updownarrow", - "." -]; - -// Metrics of the different sizes. Found by looking at TeX's output of -// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ -// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. -const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; - -// Delimiter functions -function checkDelimiter(delim, context) { - if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") { - // Recover "/" from the zero spacing group. (See macros.js) - delim = { type: "textord", text: "/", mode: "math" }; - } - const symDelim = checkSymbolNodeType(delim); - if (symDelim && utils.contains(delimiters, symDelim.text)) { - // If a character is not in the MathML operator dictionary, it will not stretch. - // Replace such characters w/characters that will stretch. - if (utils.contains(["<", "\\lt"], symDelim.text)) { symDelim.text = "⟨"; } - if (utils.contains([">", "\\gt"], symDelim.text)) { symDelim.text = "⟩"; } - if (symDelim.text === "/") { symDelim.text = "\u2215"; } - if (symDelim.text === "\\backslash") { symDelim.text = "\u2216"; } - return symDelim; - } else if (symDelim) { - throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim); - } else { - throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim); - } -} - -defineFunction({ - type: "delimsizing", - names: [ - "\\bigl", - "\\Bigl", - "\\biggl", - "\\Biggl", - "\\bigr", - "\\Bigr", - "\\biggr", - "\\Biggr", - "\\bigm", - "\\Bigm", - "\\biggm", - "\\Biggm", - "\\big", - "\\Big", - "\\bigg", - "\\Bigg" - ], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - return { - type: "delimsizing", - mode: context.parser.mode, - size: delimiterSizes[context.funcName].size, - mclass: delimiterSizes[context.funcName].mclass, - delim: delim.text - }; - }, - mathmlBuilder: (group) => { - const children = []; - - if (group.delim === ".") { group.delim = ""; } - children.push(makeText(group.delim, group.mode)); - - const node = new mathMLTree.MathNode("mo", children); - - if (group.mclass === "mopen" || group.mclass === "mclose") { - // Only some of the delimsizing functions act as fences, and they - // return "mopen" or "mclose" mclass. - node.setAttribute("fence", "true"); - } else { - // Explicitly disable fencing if it's not a fence, to override the - // defaults. - node.setAttribute("fence", "false"); - } - if (group.delim === "\u2216") { - // \backslash is not in the operator dictionary, - // so we have to explicitly set stretchy to true. - node.setAttribute("stretchy", "true"); - } - - node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox. - node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em"); - node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em"); - - return node; - } -}); - -function assertParsed(group) { - if (!group.body) { - throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); - } -} - -defineFunction({ - type: "leftright-right", - names: ["\\right"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - // \left case below triggers parsing of \right in - // `const right = parser.parseFunction();` - // uses this return value. - const color = context.parser.gullet.macros.get("\\current@color"); - if (color && typeof color !== "string") { - throw new ParseError("\\current@color set to non-string in \\right"); - } - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text, - color // undefined if not set via \color - }; - } -}); - -defineFunction({ - type: "leftright", - names: ["\\left"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - const parser = context.parser; - // Parse out the implicit body - ++parser.leftrightDepth; - // parseExpression stops before '\\right' - const body = parser.parseExpression(false); - --parser.leftrightDepth; - // Check the next token - parser.expect("\\right", false); - const right = assertNodeType(parser.parseFunction(), "leftright-right"); - return { - type: "leftright", - mode: parser.mode, - body, - left: delim.text, - right: right.delim, - rightColor: right.color - }; - }, - mathmlBuilder: (group, style) => { - assertParsed(group); - const inner = buildExpression(group.body, style); - - if (group.left === ".") { group.left = ""; } - const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]); - leftNode.setAttribute("fence", "true"); - leftNode.setAttribute("form", "prefix"); - if (group.left === "\u2216") { leftNode.setAttribute("stretchy", "true"); } - inner.unshift(leftNode); - - if (group.right === ".") { group.right = ""; } - const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]); - rightNode.setAttribute("fence", "true"); - rightNode.setAttribute("form", "postfix"); - if (group.right === "\u2216") { rightNode.setAttribute("stretchy", "true"); } - if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor); } - inner.push(rightNode); - - return makeRow(inner); - } -}); - -defineFunction({ - type: "middle", - names: ["\\middle"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - if (!context.parser.leftrightDepth) { - throw new ParseError("\\middle without preceding \\left", delim); - } - - return { - type: "middle", - mode: context.parser.mode, - delim: delim.text - }; - }, - mathmlBuilder: (group, style) => { - const textNode = makeText(group.delim, group.mode); - const middleNode = new mathMLTree.MathNode("mo", [textNode]); - middleNode.setAttribute("fence", "true"); - // MathML gives 5/18em spacing to each element. - // \middle should get delimiter spacing instead. - middleNode.setAttribute("lspace", "0.05em"); - middleNode.setAttribute("rspace", "0.05em"); - return middleNode; - } -}); - -const mathmlBuilder$2 = (group, style) => { - const node = new mathMLTree.MathNode( - group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", - [buildGroup(group.body, style)] - ); - switch (group.label) { - case "\\cancel": - node.setAttribute("notation", "updiagonalstrike"); - break; - case "\\bcancel": - node.setAttribute("notation", "downdiagonalstrike"); - break; - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break; - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break; - case "\\sout": - node.setAttribute("notation", "horizontalstrike"); - break; - case "\\fbox": - node.setAttribute("notation", "box"); - break; - case "\\angl": - node.setAttribute("notation", "actuarial"); - break; - case "\\fcolorbox": - case "\\colorbox": { - // doesn't have a good notation option for \colorbox. - // So use instead. Set some attributes that come - // included with . - const fboxsep = 3; // 3 pt from LaTeX source2e - node.setAttribute("width", `+${2 * fboxsep}pt`); - node.setAttribute("height", `+${2 * fboxsep}pt`); - node.setAttribute("lspace", `${fboxsep}pt`); // - node.setAttribute("voffset", `${fboxsep}pt`); - if (group.label === "\\fcolorbox") { - node.setAttribute("style", "border: 0.06em solid " + String(group.borderColor)); - } - break; - } - case "\\xcancel": - node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); - break; - } - if (group.backgroundColor) { - node.setAttribute("mathbackground", group.backgroundColor); - } - return node; -}; - -defineFunction({ - type: "enclose", - names: ["\\colorbox"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - const body = args[1]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor: color, - body - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -defineFunction({ - type: "enclose", - names: ["\\fcolorbox"], - props: { - numArgs: 3, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let borderColor = ""; - let backgroundColor; - if (model) { - const borderSpec = assertNodeType(args[0], "raw").string; - const backgroundSpec = assertNodeType(args[0], "raw").string; - borderColor = colorFromSpec(model, borderSpec); - backgroundColor = colorFromSpec(model, backgroundSpec); - } else { - borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros); - } - const body = args[2]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor, - borderColor, - body - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -defineFunction({ - type: "enclose", - names: ["\\fbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "enclose", - mode: parser.mode, - label: "\\fbox", - body: args[0] - }; - } -}); - -defineFunction({ - type: "enclose", - names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\angl", "\\phase", "\\longdiv"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - body - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -/** - * All registered environments. - * `environments.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `environments.js`. - */ -const _environments = {}; - -function defineEnvironment({ type, names, props, handler, mathmlBuilder }) { - // Set default values of environments. - const data = { - type, - numArgs: props.numArgs || 0, - allowedInText: false, - numOptionalArgs: 0, - handler - }; - for (let i = 0; i < names.length; ++i) { - _environments[names[i]] = data; - } - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } -} - -// In TeX, there are actually three sets of dimensions, one for each of - -// Math style is not quite the same thing as script level. -const StyleLevel = { - DISPLAY: 0, - TEXT: 1, - SCRIPT: 2, - SCRIPTSCRIPT: 3 -}; - -// Helper functions -function getHLines(parser) { - // Return an array. The array length = number of hlines. - // Each element in the array tells if the line is dashed. - const hlineInfo = []; - parser.consumeSpaces(); - let nxt = parser.fetch().text; - while (nxt === "\\hline" || nxt === "\\hdashline") { - parser.consume(); - hlineInfo.push(nxt === "\\hdashline"); - parser.consumeSpaces(); - nxt = parser.fetch().text; - } - return hlineInfo; -} - -const validateAmsEnvironmentContext = context => { - const settings = context.parser.settings; - if (!settings.displayMode) { - throw new ParseError(`{${context.envName}} can be used only in` + - ` display mode.`); - } -}; - -const getTag = (group, style, rowNum) => { - let tag; - const tagContents = group.tags.shift(); - if (tagContents) { - // The author has written a \tag or a \notag in this row. - if (tagContents.body) { - tag = buildExpressionRow(tagContents.body, style); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } - } else if (group.colSeparationType === "multline" && - ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) { - // A multiline that does not receive a tag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a post-processor. - tag = new mathMLTree.MathNode("mtext", [], ["tml-eqn"]); - } - if (!group.preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - if (!group.leqno) { tag.setAttribute("lspace", "-1width"); } - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!group.preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - return tag -}; - -/** - * Parse the body of the environment, with rows delimited by \\ and - * columns delimited by &, and create a nested list in row-major order - * with one group per cell. If given an optional argument scriptLevel - * ("text", "display", etc.), then each cell is cast into that scriptLevel. - */ -function parseArray( - parser, - { - hskipBeforeAndAfter, // boolean - addJot, // boolean - cols, // [{ type: string , align: l|c|r|null }] - arraystretch, // number - colSeparationType, // "align" | "alignat" | "gather" | "small" | "CD" | "multline" - addEqnNum, // boolean - singleRow, // boolean - emptySingleRow, // boolean - maxNumCols, // number - leqno // boolean - }, - scriptLevel -) { - parser.gullet.beginGroup(); - if (!singleRow) { - // \cr is equivalent to \\ without the optional size argument (see below) - // TODO: provide helpful error when \cr is used outside array environment - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - } - if (addEqnNum) { - parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // Get current arraystretch if it's not set by the environment - if (arraystretch === undefined || Number.isNaN(arraystretch)) { - const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); - if (stretch == null) { - // Default \arraystretch from lttab.dtx - arraystretch = 1; - } else { - arraystretch = parseFloat(stretch); - if (!arraystretch || arraystretch < 0) { - throw new ParseError(`Invalid \\arraystretch: ${stretch}`); - } - } - } - - // Start group for first cell - parser.gullet.beginGroup(); - - let row = []; - const body = [row]; - const rowGaps = []; - const tags = []; - let rowTag; - const hLinesBeforeRow = []; - - // Test for \hline at the top of the array. - hLinesBeforeRow.push(getHLines(parser)); - - // eslint-disable-next-line no-constant-condition - while (true) { - // Parse each cell in its own group (namespace) - let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\"); - - if (addEqnNum && !rowTag) { - // Check if the author wrote a \tag{} inside this cell. - for (let i = 0; i < cell.length; i++) { - if (cell[i].type === "envTag" || cell[i].type === "noTag") { - // Get the contents of the \text{} nested inside the \env@Tag{} - rowTag = cell[i].type === "envTag" - ? cell.splice(i, 1)[0].body.body[0] - : { body: null }; - break - } - } - } - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - - cell = { - type: "ordgroup", - mode: parser.mode, - body: cell - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (singleRow || colSeparationType) { - // {equation} or {split} - throw new ParseError("Too many tab characters: &", parser.nextToken); - } else { - // {array} environment - parser.settings.reportNonstrict( - "textEnv", - "Too few columns " + "specified in the {array} column argument." - ); - } - } - parser.consume(); - } else if (next === "\\end") { - // Arrays terminate newlines with `\crcr` which consumes a `\cr` if - // the last line is empty. However, AMS environments keep the - // empty row if it's the only one. - // NOTE: Currently, `cell` is the last item added into `row`. - if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) { - body.pop(); - } - if (hLinesBeforeRow.length < body.length + 1) { - hLinesBeforeRow.push([]); - } - break; - } else if (next === "\\\\") { - parser.consume(); - let size; - // \def\Let@{\let\\\math@cr} - // \def\math@cr{...\math@cr@} - // \def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}} - // \def\math@cr@@[#1]{...\math@cr@@@...} - // \def\math@cr@@@{\cr} - if (parser.gullet.future().text !== " ") { - size = parser.parseSizeGroup(true); - } - rowGaps.push(size ? size.value : null); - - tags.push(rowTag); - - // check for \hline(s) following the row separator - hLinesBeforeRow.push(getHLines(parser)); - - row = []; - rowTag = null; - body.push(row); - } else { - throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); - } - } - - // End cell group - parser.gullet.endGroup(); - // End array group defining \cr - parser.gullet.endGroup(); - - tags.push(rowTag); - - return { - type: "array", - mode: parser.mode, - addJot, - arraystretch, - body, - cols, - rowGaps, - hskipBeforeAndAfter, - hLinesBeforeRow, - colSeparationType, - addEqnNum, - scriptLevel, - tags, - leqno, - preventTagLap: parser.settings.preventTagLap - }; -} - -// Decides on a scriptLevel for cells in an array according to whether the given -// environment name starts with the letter 'd'. -function dCellStyle(envName) { - return envName.substr(0, 1) === "d" ? "display" : "text" -} - -const alignMap = { - c: "center ", - l: "left ", - r: "right " -}; - -const mathmlBuilder$3 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - let glue; - if (group.addEqnNum) { - glue = new mathMLTree.MathNode("mtd", [], []); - const glueStyle = "padding: 0;width: " + - (group.colSeparationType === "multline" ? "7.5%" : "50%"); - glue.setAttribute("style", glueStyle); - } - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellStyle = group.scriptLevel === "text" - ? StyleLevel.TEXT - : group.scriptLevel === "script" - ? StyleLevel.SCRIPT - : StyleLevel.DISPLAY; - - for (let j = 0; j < rw.length; j++) { - const mtd = new mathMLTree.MathNode( - "mtd", - [buildGroup(rw[j], style.withLevel(cellStyle))] - ); - if (group.colSeparationType === "multline") { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue); - row.push(glue); - const tag = getTag(group, style.withLevel(cellStyle), i); - if (group.leqno) { - row.unshift(tag); - } else { - row.push(tag); - } - } - // If group.addEqnNum, insert a breadcrumb to be found by temmlPostProcess(). - tbl.push(new mathMLTree.MathNode("mtr", row, group.addEqnNum ? ["tml-tageqn"] : [] )); - } - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - // Set column alignment, row spacing, column spacing, and - // array lines by setting attributes on the table element. - - // Set the row spacing. In MathML, we specify a gap distance. - // We do not use rowGap[] because MathML automatically increases - // cell height with the height/depth of the element content. - - // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. - // We simulate this by adding (arraystretch - 1)em to the gap. This - // does a reasonable job of adjusting arrays containing 1 em tall content. - - // The 0.16 and 0.09 values are found emprically. They produce an array - // similar to LaTeX and in which content does not interfere with \hines. - const gap = - group.arraystretch === 0 - ? 0 // {subarray} - : group.arraystretch === 0.5 - ? 0.1 // {smallmatrix} - : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); - table.setAttribute("rowspacing", utils.round(gap) + "em"); - - if (group.addEqnNum || group.colSeparationType === "multline") { - table.setAttribute("width", "100%"); - } - - // MathML table lines go only between cells. - // To place a line on an edge we'll use , if necessary. - let menclose = ""; - let align = ""; - - if (group.cols && group.cols.length > 0) { - // Find column alignment, column spacing, and vertical lines. - const cols = group.cols; - let columnLines = ""; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - if (cols[0].type === "separator") { - menclose += "left "; - iStart = 1; - } - if (cols[cols.length - 1].type === "separator") { - menclose += "right "; - iEnd -= 1; - } - - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - align += alignMap[cols[i].align]; - - if (prevTypeWasAlign) { - columnLines += "none "; - } - prevTypeWasAlign = true; - } else if (cols[i].type === "separator") { - // MathML accepts only single lines between cells. - // So we read only the first of consecutive separators. - if (prevTypeWasAlign) { - columnLines += cols[i].separator === "|" ? "solid " : "dashed "; - prevTypeWasAlign = false; - } - } - } - if (group.addEqnNum) { - align = "left " + align + "right "; // allow for glue cells on each side - align = group.leqno ? "left " + align : align += "right"; // eqn num cell - } - - table.setAttribute("columnalign", align.trim()); - - if (/[sd]/.test(columnLines)) { - table.setAttribute("columnlines", columnLines.trim()); - } - } - - // Set column spacing. - switch (group.colSeparationType) { - case "gather": - case "gathered": - case "alignedat": - case "alignat": - case "alignat*": - table.setAttribute("columnspacing", "0em"); - break - case "small": - table.setAttribute("columnspacing", "0.2778em"); - break - case "CD": - table.setAttribute("columnspacing", "0.5em"); - break - case "align": - case "align*": { - const cols = group.cols || []; - let spacing = group.addEqnNum ? "0em " : ""; - for (let i = 1; i < cols.length; i++) { - spacing += i % 2 ? "0em " : "1em "; - } - if (group.addEqnNum) { spacing += "0em"; } - table.setAttribute("columnspacing", spacing.trim()); - break - } - default: - table.setAttribute("columnspacing", "1em"); - } - - // Address \hline and \hdashline - let rowLines = ""; - const hlines = group.hLinesBeforeRow; - - menclose += hlines[0].length > 0 ? "top " : ""; - menclose += hlines[hlines.length - 1].length > 0 ? "bottom " : ""; - - for (let i = 1; i < hlines.length - 1; i++) { - rowLines += - hlines[i].length === 0 - ? "none " - : // MathML accepts only a single line between rows. Read one element. - hlines[i][0] - ? "dashed " - : "solid "; - } - if (/[sd]/.test(rowLines)) { - table.setAttribute("rowlines", rowLines.trim()); - } - - if (menclose !== "") { - table = new mathMLTree.MathNode("menclose", [table]); - table.setAttribute("notation", menclose.trim()); - } - - if (!Number.isNaN(group.arraystretch) && group.arraystretch < 1) { - // A small array. Wrap in scriptstyle so row gap is not too large. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table; -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addJot: true, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - colSeparationType: context.envName, - maxNumCols: context.envName === "split" ? 2 : undefined, - leqno: context.parser.settings.leqno - }, - "display" - ); - - // Determining number of columns. - // 1. If the first argument is given, we use it as a number of columns, - // and makes sure that each row doesn't exceed that number. - // 2. Otherwise, just count number of columns = maximum number - // of cells in each row ("aligned" mode -- isAligned will be true). - // - // At the same time, prepend empty group {} at beginning of every second - // cell in each row (starting with second cell) so that operators become - // binary. This behavior is implemented in amsmath's \start@aligned. - let numMaths; - let numCols = 0; - if (args[0] && args[0].type === "ordgroup") { - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - const isAligned = !numCols; - res.body.forEach(function(row) { - if (!isAligned) { - // Case 1 - const curMaths = row.length / 2; - if (numMaths < curMaths) { - throw new ParseError( - "Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, - row[0] - ); - } - } else if (numCols < row.length) { - // Case 2 - numCols = row.length; - } - }); - - // Adjusting alignment. - // In aligned mode, we add one \qquad between columns; - // otherwise we add nothing. - for (let i = 0; i < numCols; ++i) { - let align = "r"; - if (i % 2 === 1) { - align = "l"; - } - cols[i] = { - type: "align", - align: align - }; - } - res.colSeparationType = isAligned ? "align" : "alignat"; - return res; -}; - -// Arrays are part of LaTeX, defined in lttab.dtx so its documentation -// is part of the source2e.pdf file of LaTeX2e source documentation. -// {darray} is an {array} environment where cells are set in \displaystyle, -// as defined in nccmath.sty. -defineEnvironment({ - type: "array", - names: ["array", "darray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Since no types are specified above, the two possibilities are - // - The argument is wrapped in {} or [], in which case Parser's - // parseGroup() returns an "ordgroup" wrapping some symbol node. - // - The argument is a bare symbol node. - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - if ("lcr".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } else if (ca === "|") { - return { - type: "separator", - separator: "|" - }; - } else if (ca === ":") { - return { - type: "separator", - separator: ":" - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - const res = { - cols, - colSeparationType: "array", - hskipBeforeAndAfter: true, // \@preamble in lttab.dtx - maxNumCols: cols.length - }; - return parseArray(context.parser, res, dCellStyle(context.envName)); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// The matrix environments of amsmath builds on the array environment -// of LaTeX, which is discussed above. -// The mathtools package adds starred versions of the same environments. -// These have an optional argument to choose left|center|right justification. -defineEnvironment({ - type: "array", - names: [ - "matrix", - "pmatrix", - "bmatrix", - "Bmatrix", - "vmatrix", - "Vmatrix", - "matrix*", - "pmatrix*", - "bmatrix*", - "Bmatrix*", - "vmatrix*", - "Vmatrix*" - ], - props: { - numArgs: 0 - }, - handler(context) { - const delimiters = { - matrix: null, - pmatrix: ["(", ")"], - bmatrix: ["[", "]"], - Bmatrix: ["\\{", "\\}"], - vmatrix: ["|", "|"], - Vmatrix: ["\\Vert", "\\Vert"] - }[context.envName.replace("*", "")]; - // \hskip -\arraycolsep in amsmath - let colAlign = "c"; - const payload = { - hskipBeforeAndAfter: false, - colSeparationType: "matrix", - cols: [{ type: "align", align: colAlign }] - }; - if (context.envName.charAt(context.envName.length - 1) === "*") { - // It's one of the mathtools starred functions. - // Parse the optional alignment argument. - const parser = context.parser; - parser.consumeSpaces(); - if (parser.fetch().text === "[") { - parser.consume(); - parser.consumeSpaces(); - colAlign = parser.fetch().text; - if ("lcr".indexOf(colAlign) === -1) { - throw new ParseError("Expected l or c or r", parser.nextToken); - } - parser.consume(); - parser.consumeSpaces(); - parser.expect("]"); - parser.consume(); - payload.cols = [{ type: "align", align: colAlign }]; - } - } - const res = parseArray(context.parser, payload, "text"); - // Populate cols with the correct number of column alignment specs. - const numCols = Math.max(0, ...res.body.map((row) => row.length)); - res.cols = new Array(numCols).fill({ type: "align", align: colAlign }); - return delimiters - ? { - type: "leftright", - mode: context.mode, - body: [res], - left: delimiters[0], - right: delimiters[1], - rightColor: undefined // \right uninfluenced by \color in array - } - : res; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["smallmatrix"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { arraystretch: 0.5 }; - const res = parseArray(context.parser, payload, "script"); - res.colSeparationType = "small"; - return res; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["subarray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Parsing of {subarray} is similar to {array} - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - // {subarray} only recognizes "l" & "c" - if ("lc".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - if (cols.length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - let res = { - cols, - hskipBeforeAndAfter: false, - colSeparationType: "array", - arraystretch: 0 - }; - res = parseArray(context.parser, res, "script"); - if (res.body.length > 0 && res.body[0].length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - return res; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// A cases environment (in amsmath.sty) is almost equivalent to -// \def -// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. -// {dcases} is a {cases} environment where cells are set in \displaystyle, -// as defined in mathtools.sty. -// {rcases} is another mathtools environment. It's brace is on the right side. -defineEnvironment({ - type: "array", - names: ["cases", "dcases", "rcases", "drcases"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { - cols: [ - { - type: "align", - align: "l" - }, - { - type: "align", - align: "l" - } - ], - colSeparationType: "cases" - }; - const res = parseArray(context.parser, payload, dCellStyle(context.envName)); - return { - type: "leftright", - mode: context.mode, - body: [res], - left: context.envName.indexOf("r") > -1 ? "." : "\\{", - right: context.envName.indexOf("r") > -1 ? "\\}" : ".", - rightColor: undefined - }; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// In the align environment, one uses ampersands, &, to specify number of -// columns in each row, and to locate spacing between each column. -// align gets automatic numbering. align* and aligned do not. -// The alignedat environment can be used in math mode. -// Note that we assume \nomallineskiplimit to be zero, -// so that \strut@ is the same as \strut. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$3 -}); - -// A gathered environment is like an array environment with one centered -// column, but where rows are considered lines so get \jot line spacing -// and contents are set in \displaystyle. -defineEnvironment({ - type: "array", - names: ["gathered", "gather", "gather*"], - props: { - numArgs: 0 - }, - handler(context) { - if (utils.contains(["gather", "gather*"], context.envName)) { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [ - { - type: "align", - align: "c" - } - ], - addJot: true, - colSeparationType: "gather", - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// alignat environment is like an align environment, but one must explicitly -// specify maximum number of columns in each row, and can adjust spacing between -// each columns. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["equation", "equation*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "equation", - emptySingleRow: true, - singleRow: true, - maxNumCols: 1, - colSeparationType: "gather", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["multline", "multline*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "multline", - maxNumCols: 1, - colSeparationType: "multline", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["CD"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - return parseCD(context.parser); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// Catch \hline outside array environment -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\hline", "\\hdashline"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: true - }, - handler(context, args) { - throw new ParseError(`${context.funcName} valid only within array environment`); - } -}); - -const environments = _environments; - -// Environment delimiters. HTML/MathML rendering is defined in the corresponding -// defineEnvironment definitions. -defineFunction({ - type: "environment", - names: ["\\begin", "\\end"], - props: { - numArgs: 1, - argTypes: ["text"] - }, - handler({ parser, funcName }, args) { - const nameGroup = args[0]; - if (nameGroup.type !== "ordgroup") { - throw new ParseError("Invalid environment name", nameGroup); - } - let envName = ""; - for (let i = 0; i < nameGroup.body.length; ++i) { - envName += assertNodeType(nameGroup.body[i], "textord").text; - } - - if (funcName === "\\begin") { - // begin...end is similar to left...right - if (!Object.prototype.hasOwnProperty.call(environments, envName )) { - throw new ParseError("No such environment: " + envName, nameGroup); - } - // Build the environment object. Arguments and other information will - // be made available to the begin and end methods using properties. - const env = environments[envName]; - const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env); - const context = { - mode: parser.mode, - envName, - parser - }; - const result = env.handler(context, args, optArgs); - parser.expect("\\end", false); - const endNameToken = parser.nextToken; - const end = assertNodeType(parser.parseFunction(), "environment"); - if (end.name !== envName) { - throw new ParseError( - `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, - endNameToken - ); - } - return result; - } - - return { - type: "environment", - mode: parser.mode, - name: envName, - nameGroup - }; - } -}); - -defineFunction({ - type: "envTag", - names: ["\\env@tag"], - props: { - numArgs: 1, - argTypes: ["math"] - }, - handler({ parser }, args) { - return { - type: "envTag", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -defineFunction({ - type: "noTag", - names: ["\\env@notag"], - props: { - numArgs: 0 - }, - handler({ parser }) { - return { - type: "noTag", - mode: parser.mode - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -const mathmlBuilder$4 = (group, style) => { - const font = group.font; - const newStyle = style.withFont(font); - const mathGroup = buildGroup(group.body, newStyle); - - if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{} - if (mathGroup.type === "mo" && font === "boldsymbol") { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - let canConsolidate = mathGroup.children[0].type === "mo"; - for (let i = 1; i < mathGroup.children.length; i++) { - if (mathGroup.children[i].type === "mo" && font === "boldsymbol") { - mathGroup.children[i].style.fontWeight = "bold"; - } - if (mathGroup.children[i].type !== "mi") { canConsolidate = false; } - const localVariant = mathGroup.children[i].attributes && - mathGroup.children[i].attributes.mathvariant || ""; - if (localVariant !== "normal") { canConsolidate = false; } - } - if (!canConsolidate) { return mathGroup } - // Consolidate the elements. - const mi = mathGroup.children[0]; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children.push(mathGroup.children[i].children[0]); - } - if (mathGroup.attributes.mathcolor) { mi.attributes.mathcolor = mathGroup.attributes.mathcolor; } - if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") { - // Workaround for a Firefox bug that renders spurious space around - // a - // Ref: https://bugs.webkit.org/show_bug.cgi?id=129097 - // We insert a text node that contains a zero-width space and wrap in an mrow. - // TODO: Get rid of this workaround when the Firefox bug is fixed. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - return mi -}; - -const fontAliases = { - "\\Bbb": "\\mathbb", - "\\bold": "\\mathbf", - "\\frak": "\\mathfrak", - "\\bm": "\\boldsymbol" -}; - -defineFunction({ - type: "font", - names: [ - // styles - "\\mathrm", - "\\mathit", - "\\mathbf", - "\\mathnormal", - "\\up@greek", - "\\pmb", - "\\boldsymbol", - - // families - "\\mathbb", - "\\mathcal", - "\\mathfrak", - "\\mathscr", - "\\mathsf", - "\\mathtt", - "\\oldstylenums", - - // aliases - "\\Bbb", - "\\bm", - "\\bold", - "\\frak" - ], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = normalizeArgument(args[0]); - let func = funcName; - if (func in fontAliases) { - func = fontAliases[func]; - } - return { - type: "font", - mode: parser.mode, - font: func.slice(1), - body - }; - }, - mathmlBuilder: mathmlBuilder$4 -}); - -// Old font changing functions -defineFunction({ - type: "font", - names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ parser, funcName, breakOnTokenText }, args) => { - const { mode } = parser; - const body = parser.parseExpression(true, breakOnTokenText); - const fontStyle = `math${funcName.slice(1)}`; - - return { - type: "font", - mode: mode, - font: fontStyle, - body: { - type: "ordgroup", - mode: parser.mode, - body - } - }; - }, - mathmlBuilder: mathmlBuilder$4 -}); - -const stylArray = ["display", "text", "script", "scriptscript"]; -const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 }; - -const mathmlBuilder$5 = (group, style) => { - // Track the scriptLevel of the numerator and denominator. - // We may need that info for \mathchoice or for adjusting em dimensions. - const childOptions = group.scriptLevel === "auto" - ? style.incrementLevel() - : group.scriptLevel === "display" - ? style.withLevel(StyleLevel.TEXT) - : group.scriptLevel === "text" - ? style.withLevel(StyleLevel.SCRIPT) - : style.withLevel(StyleLevel.SCRIPTSCRIPT); - - let node = new mathMLTree.MathNode("mfrac", [ - buildGroup(group.numer, childOptions), - buildGroup(group.denom, childOptions) - ]); - - if (!group.hasBarLine) { - node.setAttribute("linethickness", "0px"); - } else if (group.barSize) { - const ruleWidth = calculateSize(group.barSize, style); - node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit); - } - - if (group.leftDelim != null || group.rightDelim != null) { - const withDelims = []; - - if (group.leftDelim != null) { - const leftOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.leftDelim.replace("\\", "")) - ]); - leftOp.setAttribute("fence", "true"); - withDelims.push(leftOp); - } - - withDelims.push(node); - - if (group.rightDelim != null) { - const rightOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.rightDelim.replace("\\", "")) - ]); - rightOp.setAttribute("fence", "true"); - withDelims.push(rightOp); - } - - node = makeRow(withDelims); - } - - if (group.scriptLevel !== "auto") { - node = new mathMLTree.MathNode("mstyle", [node]); - node.setAttribute("displaystyle", String(group.scriptLevel === "display")); - node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]); - } - - return node; -}; - -defineFunction({ - type: "genfrac", - names: [ - "\\dfrac", - "\\frac", - "\\tfrac", - "\\dbinom", - "\\binom", - "\\tbinom", - "\\\\atopfrac", // can’t be entered directly - "\\\\bracefrac", - "\\\\brackfrac" // ditto - ], - props: { - numArgs: 2, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - let hasBarLine = false; - let leftDelim = null; - let rightDelim = null; - let scriptLevel = "auto"; - - switch (funcName) { - case "\\dfrac": - case "\\frac": - case "\\tfrac": - hasBarLine = true; - break; - case "\\\\atopfrac": - hasBarLine = false; - break; - case "\\dbinom": - case "\\binom": - case "\\tbinom": - leftDelim = "("; - rightDelim = ")"; - break; - case "\\\\bracefrac": - leftDelim = "\\{"; - rightDelim = "\\}"; - break; - case "\\\\brackfrac": - leftDelim = "["; - rightDelim = "]"; - break; - default: - throw new Error("Unrecognized genfrac command"); - } - - switch (funcName) { - case "\\dfrac": - case "\\dbinom": - scriptLevel = "display"; - break; - case "\\tfrac": - case "\\tbinom": - scriptLevel = "text"; - break; - } - - return { - type: "genfrac", - mode: parser.mode, - continued: false, - numer, - denom, - hasBarLine, - leftDelim, - rightDelim, - scriptLevel, - barSize: null - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -defineFunction({ - type: "genfrac", - names: ["\\cfrac"], - props: { - numArgs: 2 - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - - return { - type: "genfrac", - mode: parser.mode, - continued: true, - numer, - denom, - hasBarLine: true, - leftDelim: null, - rightDelim: null, - scriptLevel: "display", - barSize: null - }; - } -}); - -// Infix generalized fractions -- these are not rendered directly, but replaced -// immediately by one of the variants above. -defineFunction({ - type: "infix", - names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], - props: { - numArgs: 0, - infix: true - }, - handler({ parser, funcName, token }) { - let replaceWith; - switch (funcName) { - case "\\over": - replaceWith = "\\frac"; - break; - case "\\choose": - replaceWith = "\\binom"; - break; - case "\\atop": - replaceWith = "\\\\atopfrac"; - break; - case "\\brace": - replaceWith = "\\\\bracefrac"; - break; - case "\\brack": - replaceWith = "\\\\brackfrac"; - break; - default: - throw new Error("Unrecognized infix genfrac command"); - } - return { - type: "infix", - mode: parser.mode, - replaceWith, - token - }; - } -}); - -const delimFromValue = function(delimString) { - let delim = null; - if (delimString.length > 0) { - delim = delimString; - delim = delim === "." ? null : delim; - } - return delim; -}; - -defineFunction({ - type: "genfrac", - names: ["\\genfrac"], - props: { - numArgs: 6, - allowedInArgument: true, - argTypes: ["math", "math", "size", "text", "math", "math"] - }, - handler({ parser }, args) { - const numer = args[4]; - const denom = args[5]; - - // Look into the parse nodes to get the desired delimiters. - const leftNode = normalizeArgument(args[0]); - const leftDelim = leftNode.type === "atom" && leftNode.family === "open" - ? delimFromValue(leftNode.text) - : null; - const rightNode = normalizeArgument(args[1]); - const rightDelim = - rightNode.type === "atom" && rightNode.family === "close" - ? delimFromValue(rightNode.text) - : null; - - const barNode = assertNodeType(args[2], "size"); - let hasBarLine; - let barSize = null; - if (barNode.isBlank) { - // \genfrac acts differently than \above. - // \genfrac treats an empty size group as a signal to use a - // standard bar size. \above would see size = 0 and omit the bar. - hasBarLine = true; - } else { - barSize = barNode.value; - hasBarLine = barSize.number > 0; - } - - // Find out if we want displaystyle, textstyle, etc. - let scriptLevel = "auto"; - let styl = args[3]; - if (styl.type === "ordgroup") { - if (styl.body.length > 0) { - const textOrd = assertNodeType(styl.body[0], "textord"); - scriptLevel = stylArray[Number(textOrd.text)]; - } - } else { - styl = assertNodeType(styl, "textord"); - scriptLevel = stylArray[Number(styl.text)]; - } - - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim, - rightDelim, - scriptLevel - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -// \above is an infix fraction that also defines a fraction bar size. -defineFunction({ - type: "infix", - names: ["\\above"], - props: { - numArgs: 1, - argTypes: ["size"], - infix: true - }, - handler({ parser, funcName, token }, args) { - return { - type: "infix", - mode: parser.mode, - replaceWith: "\\\\abovefrac", - barSize: assertNodeType(args[0], "size").value, - token - }; - } -}); - -defineFunction({ - type: "genfrac", - names: ["\\\\abovefrac"], - props: { - numArgs: 3, - argTypes: ["math", "size", "math"] - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const barSize = assert(assertNodeType(args[1], "infix").barSize); - const denom = args[2]; - - const hasBarLine = barSize.number > 0; - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim: null, - rightDelim: null, - scriptLevel: "auto" - }; - }, - - mathmlBuilder: mathmlBuilder$5 -}); - -const mathmlBuilder$6 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [ - buildGroup(group.base, style), - accentNode - ]); -}; - -// Horizontal stretchy braces -defineFunction({ - type: "horizBrace", - names: ["\\overbrace", "\\underbrace"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "horizBrace", - mode: parser.mode, - label: funcName, - isOver: /^\\over/.test(funcName), - base: args[0] - }; - }, - mathmlBuilder: mathmlBuilder$6 -}); - -defineFunction({ - type: "href", - names: ["\\href"], - props: { - numArgs: 2, - argTypes: ["url", "original"], - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[1]; - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\href", - url: href - }) - ) { - return parser.formatUnsupportedCmd("\\href"); - } - - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - let math = buildExpressionRow(group.body, style); - if (!(math instanceof MathNode)) { - math = new MathNode("mrow", [math]); - } - math.setAttribute("href", group.href); - return math; - } -}); - -defineFunction({ - type: "href", - names: ["\\url"], - props: { - numArgs: 1, - argTypes: ["url"], - allowedInText: true - }, - handler: ({ parser }, args) => { - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\url", - url: href - }) - ) { - return parser.formatUnsupportedCmd("\\url"); - } - - const chars = []; - for (let i = 0; i < href.length; i++) { - let c = href[i]; - if (c === "~") { - c = "\\textasciitilde"; - } - chars.push({ - type: "textord", - mode: "text", - text: c - }); - } - const body = { - type: "text", - mode: parser.mode, - font: "\\texttt", - body: chars - }; - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - } -}); - -defineFunction({ - type: "html", - names: ["\\class", "\\id", "\\style", "\\data"], - props: { - numArgs: 2, - argTypes: ["raw", "original"], - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - const value = assertNodeType(args[0], "raw").string; - const body = args[1]; - - if (parser.settings.strict) { - parser.settings.reportNonstrict( - "htmlExtension", "HTML extension is disabled on strict mode" - ); - } - - let trustContext; - const attributes = {}; - - switch (funcName) { - case "\\class": - attributes.class = value; - trustContext = { - command: "\\class", - class: value - }; - break; - case "\\id": - attributes.id = value; - trustContext = { - command: "\\id", - id: value - }; - break; - case "\\style": - attributes.style = value; - trustContext = { - command: "\\style", - style: value - }; - break; - case "\\data": { - const data = value.split(","); - for (let i = 0; i < data.length; i++) { - const keyVal = data[i].split("="); - if (keyVal.length !== 2) { - throw new ParseError("Error parsing key-value for \\data"); - } - attributes["data-" + keyVal[0].trim()] = keyVal[1].trim(); - } - - trustContext = { - command: "\\data", - attributes - }; - break; - } - default: - throw new Error("Unrecognized html command"); - } - - if (!parser.settings.isTrusted(trustContext)) { - return parser.formatUnsupportedCmd(funcName); - } - return { - type: "html", - mode: parser.mode, - attributes, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const element = buildExpressionRow(group.body, style); - - const classes = []; - if (group.attributes.class) { - classes.push(...group.attributes.class.trim().split(/\s+/)); - } - element.classes = classes; - - for (const attr in group.attributes) { - if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) { - element.setAttribute(attr, group.attributes[attr]); - } - } - - return element; - } -}); - -const sizeData = function(str) { - if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { - // str is a number with no unit specified. - // default unit is bp, per graphix package. - return { number: +str, unit: "bp" } - } else { - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); - if (!match) { - throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); - } - return data - } -}; - -defineFunction({ - type: "includegraphics", - names: ["\\includegraphics"], - props: { - numArgs: 1, - numOptionalArgs: 1, - argTypes: ["raw", "url"], - allowedInText: false - }, - handler: ({ parser }, args, optArgs) => { - let width = { number: 0, unit: "em" }; - let height = { number: 0.9, unit: "em" }; // sorta character sized. - let totalheight = { number: 0, unit: "em" }; - let alt = ""; - - if (optArgs[0]) { - const attributeStr = assertNodeType(optArgs[0], "raw").string; - - // Parser.js does not parse key/value pairs. We get a string. - const attributes = attributeStr.split(","); - for (let i = 0; i < attributes.length; i++) { - const keyVal = attributes[i].split("="); - if (keyVal.length === 2) { - const str = keyVal[1].trim(); - switch (keyVal[0].trim()) { - case "alt": - alt = str; - break - case "width": - width = sizeData(str); - break - case "height": - height = sizeData(str); - break - case "totalheight": - totalheight = sizeData(str); - break - default: - throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics.") - } - } - } - } - - const src = assertNodeType(args[0], "url").url; - - if (alt === "") { - // No alt given. Use the file name. Strip away the path. - alt = src; - alt = alt.replace(/^.*[\\/]/, ""); - alt = alt.substring(0, alt.lastIndexOf(".")); - } - - if ( - !parser.settings.isTrusted({ - command: "\\includegraphics", - url: src - }) - ) { - return parser.formatUnsupportedCmd("\\includegraphics") - } - - return { - type: "includegraphics", - mode: parser.mode, - alt: alt, - width: width, - height: height, - totalheight: totalheight, - src: src - } - }, - mathmlBuilder: (group, style) => { - const height = calculateSize(group.height, style); - const depth = { number: 0, unit: "em" }; - - if (group.totalheight.number > 0) { - if (group.totalheight.unit === height.unit && - group.totalheight.number > height.number) { - depth.number = group.totalheight.number - height.number; - depth.unit = height.unit; - } - } - - let width = 0; - if (group.width.number > 0) { - width = calculateSize(group.width, style); - } - - const graphicStyle = { height: height.number + depth.number + "em" }; - if (width.number > 0) { - graphicStyle.width = width.number + width.unit; - } - if (depth.number > 0) { - graphicStyle.verticalAlign = -depth.number + depth.unit; - } - - const node = new Img(group.src, group.alt, graphicStyle); - node.height = height; - node.depth = depth; - return new mathMLTree.MathNode("mtext", [node]) - } -}); - -// Horizontal spacing commands - -// TODO: \hskip and \mskip should support plus and minus in lengths - -defineFunction({ - type: "kern", - names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], - props: { - numArgs: 1, - argTypes: ["size"], - primitive: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const size = assertNodeType(args[0], "size"); - if (parser.settings.strict) { - const mathFunction = funcName[1] === "m"; // \mkern, \mskip - const muUnit = size.value.unit === "mu"; - if (mathFunction) { - if (!muUnit) { - parser.settings.reportNonstrict( - "mathVsTextUnits", - `LaTeX's ${funcName} supports only mu units, ` + `not ${size.value.unit} units` - ); - } - if (parser.mode !== "math") { - parser.settings.reportNonstrict( - "mathVsTextUnits", - `LaTeX's ${funcName} works only in math mode` - ); - } - } else { - // !mathFunction - if (muUnit) { - parser.settings.reportNonstrict( - "mathVsTextUnits", - `LaTeX's ${funcName} doesn't support mu units` - ); - } - } - } - return { - type: "kern", - mode: parser.mode, - dimension: size.value - }; - }, - mathmlBuilder(group, style) { - const dimension = calculateSize(group.dimension, style); - const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : ""; - if (group.mode === "text" && ch.length > 0) { - const character = new mathMLTree.TextNode(ch); - return new mathMLTree.MathNode("mtext", [character]); - } else { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", dimension.number + dimension.unit); - return node; - } - } -}); - -const spaceCharacter = function(width) { - if (width >= 0.05555 && width <= 0.05556) { - return "\u200a"; //   - } else if (width >= 0.1666 && width <= 0.1667) { - return "\u2009"; //   - } else if (width >= 0.2222 && width <= 0.2223) { - return "\u2005"; //   - } else if (width >= 0.2777 && width <= 0.2778) { - return "\u2005\u200a"; //    - } else { - return ""; - } -}; - -// Limit valid characters to a small set, for safety. -const invalidIdRegEx = /[^A-Za-z_0-9-]/g; - -defineFunction({ - type: "label", - names: ["\\label"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser }, args) { - return { - type: "label", - mode: parser.mode, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Return a no-width, no-ink element with an HTML id. - const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]); - if (group.string.length > 0) { - node.setAttribute("id", group.string); - } - return node - } -}); - -// Horizontal overlap functions - -const textModeLap = ["\\clap", "\\llap", "\\rlap"]; - -defineFunction({ - type: "lap", - names: ["\\mathllap", "\\mathrlap", "\\mathclap", "\\clap", "\\llap", "\\rlap"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser, funcName }, args) => { - if (textModeLap.includes(funcName)) { - if (parser.settings.strict && parser.mode !== "text") { - throw new ParseError(`{${funcName}} can be used only in text mode.`) - } - funcName = funcName.slice(1); - } else { - funcName = funcName.slice(5); - } - const body = args[0]; - return { - type: "lap", - mode: parser.mode, - alignment: funcName, - body - } - }, - mathmlBuilder: (group, style) => { - // mathllap, mathrlap, mathclap - const node = new mathMLTree.MathNode("mpadded", [buildGroup(group.body, style)]); - - if (group.alignment === "rlap") { - if (group.body.body.length > 0 && group.body.body[0].type === "genfrac") { - // In Firefox, a squashes the 3/18em padding of a child \frac. Put it back. - node.setAttribute("lspace", "0.16667em"); - } - } else { - const offset = group.alignment === "llap" ? "-1" : "-0.5"; - node.setAttribute("lspace", offset + "width"); - } - node.setAttribute("width", "0px"); - return node - } -}); - -// Switching from text mode back to math mode -defineFunction({ - type: "ordgroup", - names: ["\\(", "$"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler({ funcName, parser }, args) { - const outerMode = parser.mode; - parser.switchMode("math"); - const close = funcName === "\\(" ? "\\)" : "$"; - const body = parser.parseExpression(false, close); - parser.expect(close); - parser.switchMode(outerMode); - return { - type: "ordgroup", - mode: parser.mode, - body - }; - } -}); - -// Check for extra closing math delimiters -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\)", "\\]"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler(context, args) { - throw new ParseError(`Mismatched ${context.funcName}`); - } -}); - -const chooseStyle = (group, style) => { - switch (style.level) { - case StyleLevel.DISPLAY: // 0 - return group.display; - case StyleLevel.TEXT: // 1 - return group.text; - case StyleLevel.SCRIPT: // 2 - return group.script; - case StyleLevel.SCRIPTSCRIPT: // 3 - return group.scriptscript; - default: - return group.text; - } -}; - -defineFunction({ - type: "mathchoice", - names: ["\\mathchoice"], - props: { - numArgs: 4, - primitive: true - }, - handler: ({ parser }, args) => { - return { - type: "mathchoice", - mode: parser.mode, - display: ordargument(args[0]), - text: ordargument(args[1]), - script: ordargument(args[2]), - scriptscript: ordargument(args[3]) - }; - }, - mathmlBuilder: (group, style) => { - const body = chooseStyle(group, style); - return buildExpressionRow(body, style); - } -}); - -const textAtomTypes = ["text", "textord", "mathord", "atom"]; - -function mathmlBuilder$7(group, style) { - let node; - const inner = buildExpression(group.body, style); - - if (group.mclass === "minner") { - return mathMLTree.newDocumentFragment(inner); - } else if (group.mclass === "mord") { - if (group.isCharacterBox || inner[0].type === "mathord") { - node = inner[0]; - node.type = "mi"; - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - if (group.mustPromote) { - node = inner[0]; - node.type = "mo"; - if (group.isCharacterBox && group.body[0].text && /[A-Za-z]/.test(group.body[0].text)) { - node.setAttribute("mathvariant", "italic"); - } - } else { - node = new mathMLTree.MathNode("mo", inner); - } - - // Set spacing based on what is the most likely adjacent atom type. - // See TeXbook p170. - const doSpacing = style.level < 2; // Operator spacing is zero inside a (sub|super)script. - if (group.mclass === "mbin") { - // medium space - node.attributes.lspace = (doSpacing ? "0.2222em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2222em" : "0"); - } else if (group.mclass === "mrel") { - // thickspace - node.attributes.lspace = (doSpacing ? "0.2778em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2778em" : "0"); - } else if (group.mclass === "mpunct") { - node.attributes.lspace = "0em"; - node.attributes.rspace = (doSpacing ? "0.1667em" : "0"); - } else if (group.mclass === "mopen" || group.mclass === "mclose") { - node.attributes.lspace = "0em"; - node.attributes.rspace = "0em"; - } - if (!(group.mclass === "mopen" || group.mclass === "mclose")) { - delete node.attributes.stretchy; - delete node.attributes.form; - } - } - return node; -} - -// Math class commands except \mathop -defineFunction({ - type: "mclass", - names: [ - "\\mathord", - "\\mathbin", - "\\mathrel", - "\\mathopen", - "\\mathclose", - "\\mathpunct", - "\\mathinner" - ], - props: { - numArgs: 1, - primitive: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - const isCharacterBox = utils.isCharacterBox(body); - // We should not wrap a around a or . That would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - let mustPromote = true; - const mord = { type: "mathord", text: "", mode: parser.mode }; - const arr = (body.body) ? body.body : [body]; - for (const arg of arr) { - if (textAtomTypes.includes(arg.type)) { - if (arg.text) { - mord.text += arg.text; - } else if (arg.body) { - arg.body.map(e => { mord.text += e.text; }); - } - } else { - mustPromote = false; - break - } - } - return { - type: "mclass", - mode: parser.mode, - mclass: "m" + funcName.substr(5), - body: ordargument(mustPromote ? mord : body), - isCharacterBox, - mustPromote - }; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -const binrelClass = (arg) => { - // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. - // (by rendering separately and with {}s before and after, and measuring - // the change in spacing). We'll do roughly the same by detecting the - // atom type directly. - const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; - if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { - return "m" + atom.family; - } else { - return "mord"; - } -}; - -// \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. -// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. -defineFunction({ - type: "mclass", - names: ["\\@binrel"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "mclass", - mode: parser.mode, - mclass: binrelClass(args[0]), - body: ordargument(args[1]), - isCharacterBox: utils.isCharacterBox(args[1]) - }; - } -}); - -// Build a relation or stacked op by placing one symbol on top of another -defineFunction({ - type: "mclass", - names: ["\\stackrel", "\\overset", "\\underset"], - props: { - numArgs: 2 - }, - handler({ parser, funcName }, args) { - const baseArg = args[1]; - const shiftedArg = args[0]; - - const baseOp = { - type: "op", - mode: baseArg.mode, - limits: true, - alwaysHandleSupSub: true, - parentIsSupSub: false, - symbol: false, - stack: true, - suppressBaseShift: funcName !== "\\stackrel", - body: ordargument(baseArg) - }; - - return { - type: "supsub", - mode: shiftedArg.mode, - base: baseOp, - sup: funcName === "\\underset" ? null : shiftedArg, - sub: funcName === "\\underset" ? shiftedArg : null - }; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// Helper function -const buildGroup$1 = (el, style, noneNode) => { - if (!el) { return noneNode } - const node = buildGroup(el, style); - if (node.type === "mrow" && node.children.length === 0) { return noneNode } - return node -}; - -defineFunction({ - type: "multiscript", - names: ["\\sideset", "\\pres@cript"], // See macros.js for \prescript - props: { - numArgs: 3 - }, - handler({ parser, funcName }, args) { - if (args[2].body.length === 0) { - throw new ParseError(funcName + `cannot parse an empty base.`) - } - const base = args[2].body[0]; - if (parser.settings.strict && funcName === "\\sideset" && !base.symbol) { - throw new ParseError(`The base of \\sideset must be a big operator.`) - } - - if ((args[0].body.length > 0 && args[0].body[0].type !== "supsub") || - (args[1].body.length > 0 && args[1].body[0].type !== "supsub")) { - throw new ParseError("\\sideset can parse only subscripts and " + - "superscripts in its first two arguments") - } - - // The prescripts and postscripts come wrapped in a supsub. - const prescripts = args[0].body.length > 0 ? args[0].body[0] : null; - const postscripts = args[1].body.length > 0 ? args[1].body[0] : null; - - if (!prescripts && !postscripts) { - return base - } else if (!prescripts) { - // It's not a multi-script. Get a \textstyle supsub. - return { - type: "styling", - mode: parser.mode, - scriptLevel: "text", - body: [{ - type: "supsub", - mode: parser.mode, - base, - sup: postscripts.sup, - sub: postscripts.sub - }] - } - } else { - return { - type: "multiscript", - mode: parser.mode, - isSideset: funcName === "\\sideset", - prescripts, - postscripts, - base - } - } - }, - mathmlBuilder(group, style) { - const base = buildGroup(group.base, style); - - const prescriptsNode = new mathMLTree.MathNode("mprescripts"); - const noneNode = new mathMLTree.MathNode("none"); - let children = []; - - const preSub = buildGroup$1(group.prescripts.sub, style, noneNode); - const preSup = buildGroup$1(group.prescripts.sup, style, noneNode); - if (group.isSideset) { - // This seems silly, but LaTeX does this. Firefox ignores it, which does not make me sad. - preSub.setAttribute("style", "text-align: left;"); - preSup.setAttribute("style", "text-align: left;"); - } - - if (group.postscripts) { - const postSub = buildGroup$1(group.postscripts.sub, style, noneNode); - const postSup = buildGroup$1(group.postscripts.sup, style, noneNode); - children = [base, postSub, postSup, prescriptsNode, preSub, preSup]; - } else { - children = [base, prescriptsNode, preSub, preSup]; - } - - return new mathMLTree.MathNode("mmultiscripts", children); - } -}); - -defineFunction({ - type: "not", - names: ["\\not"], - props: { - numArgs: 1, - primitive: true, - allowedInText: false - }, - handler({ parser }, args) { - const isCharacterBox = utils.isCharacterBox(args[0]); - let body; - if (isCharacterBox) { - body = ordargument(args[0]); - if (body[0].text.charAt(0) === "\\") { - body[0].text = symbols.math[body[0].text].replace; - } - // \u0338 is the Unicode Combining Long Solidus Overlay - body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1); - } else { - // When the argument is not a character box, TeX does an awkward, poorly placed overlay. - // We'll do the same. - const notNode = { type: "textord", mode: "math", text: "\u0338" }; - const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } }; - body = [notNode, kernNode, args[0]]; - } - return { - type: "not", - mode: parser.mode, - body, - isCharacterBox - }; - }, - mathmlBuilder(group, style) { - if (group.isCharacterBox) { - const inner = buildExpression(group.body, style); - return inner[0] - } else { - return buildExpressionRow(group.body, style, true) - } - } -}); - -// Limits, symbols - -const ordAtomTypes = ["textord", "mathord", "atom"]; - -// Most operators have a large successor symbol, but these don't. -const noSuccessor = ["\\smallint"]; - -// Math operators (e.g. \sin) need a space between these types and themselves: -const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"]; - -// NOTE: Unlike most `builders`s, this one handles not only "op", but also -// "supsub" since some of them (like \int) can affect super/subscripting. - -const mathmlBuilder$8 = (group, style) => { - let node; - - if (group.symbol) { - // This is a symbol. Just add the symbol. - node = new MathNode("mo", [makeText(group.name, group.mode)]); - if (utils.contains(noSuccessor, group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - } else { - // This is a text operator. Add all of the characters from the operator's name. - node = new MathNode("mi", [new TextNode$1(group.name.slice(1))]); - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new MathNode("mo", [makeText("\u2061", "text")]); - if (group.needsLeadingSpace) { - const space = new MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node = newDocumentFragment([space, node, operator]); - } else { - node = newDocumentFragment([node, operator]); - } - } - } - - return node; -}; - -const singleCharBigOps = { - "\u220F": "\\prod", - "\u2210": "\\coprod", - "\u2211": "\\sum", - "\u22c0": "\\bigwedge", - "\u22c1": "\\bigvee", - "\u22c2": "\\bigcap", - "\u22c3": "\\bigcup", - "\u2a00": "\\bigodot", - "\u2a01": "\\bigoplus", - "\u2a02": "\\bigotimes", - "\u2a04": "\\biguplus", - "\u2a05": "\\bigsqcap", - "\u2a06": "\\bigsqcup" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\smallint", - "\u220F", - "\u2210", - "\u2211", - "\u22c0", - "\u22c1", - "\u22c2", - "\u22c3", - "\u2a00", - "\u2a01", - "\u2a02", - "\u2a04", - "\u2a06" - ], - props: { - numArgs: 0 - }, - handler: ({ parser, funcName }, args) => { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharBigOps[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: true, - stack: false, // This is true for \stackrel{}, not here. - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// Note: calling defineFunction with a type that's already been defined only -// works because the same mathmlBuilder is being used. -defineFunction({ - type: "op", - names: ["\\mathop"], - props: { - numArgs: 1, - primitive: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - // It would be convienient to just wrap a around the argument. - // But if the argument is a or , that would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - const arr = (body.body) ? body.body : [body]; - const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type); - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: isSymbol, - stack: false, - name: isSymbol ? arr[0].text : null, - body: isSymbol ? null : ordargument(body) - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// There are 2 flags for operators; whether they produce limits in -// displaystyle, and whether they are symbols and should grow in -// displaystyle. These four groups cover the four possible choices. - -const singleCharIntegrals = { - "\u222b": "\\int", - "\u222c": "\\iint", - "\u222d": "\\iiint", - "\u222e": "\\oint", - "\u222f": "\\oiint", - "\u2230": "\\oiiint", - "\u2231": "\\intclockwise", - "\u2232": "\\varointclockwise", - "\u2a0c": "\\iiiint", - "\u2a0d": "\\intbar", - "\u2a0e": "\\intBar", - "\u2a0f": "\\fint", - "\u2a12": "\\rppolint", - "\u2a13": "\\scpolint", - "\u2a15": "\\pointint", - "\u2a16": "\\sqint", - "\u2a17": "\\intlarhk", - "\u2a18": "\\intx", - "\u2a19": "\\intcap", - "\u2a1a": "\\intcup" -}; - -// No limits, not symbols -defineFunction({ - type: "op", - names: [ - "\\arcsin", - "\\arccos", - "\\arctan", - "\\arctg", - "\\arcctg", - "\\arg", - "\\ch", - "\\cos", - "\\cosec", - "\\cosh", - "\\cot", - "\\cotg", - "\\coth", - "\\csc", - "\\ctg", - "\\cth", - "\\deg", - "\\dim", - "\\exp", - "\\hom", - "\\ker", - "\\lg", - "\\ln", - "\\log", - "\\sec", - "\\sin", - "\\sinh", - "\\sh", - "\\sgn", - "\\tan", - "\\tanh", - "\\tg", - "\\th" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: false, - stack: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// Limits, not symbols -defineFunction({ - type: "op", - names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: false, - stack: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// No limits, symbols -defineFunction({ - type: "op", - names: [ - "\\int", - "\\iint", - "\\iiint", - "\\iiiint", - "\\oint", - "\\oiint", - "\\oiiint", - "\\intclockwise", - "\\varointclockwise", - "\\intbar", - "\\intBar", - "\\fint", - "\\rppolint", - "\\scpolint", - "\\pointint", - "\\sqint", - "\\intlarhk", - "\\intx", - "\\intcap", - "\\intcup", - "\u222b", - "\u222c", - "\u222d", - "\u222e", - "\u222f", - "\u2230", - "\u2231", - "\u2232", - "\u2a0c", - "\u2a0d", - "\u2a0e", - "\u2a0f", - "\u2a12", - "\u2a13", - "\u2a15", - "\u2a16", - "\u2a17", - "\u2a18", - "\u2a19", - "\u2a1a" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharIntegrals[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: true, - stack: false, - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -/** - * All registered global/built-in macros. - * `macros.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `macros.js`. - */ -const _macros = {}; - -// This function might one day accept an additional argument and do more things. -function defineMacro(name, body) { - _macros[name] = body; -} - -// NOTE: Unlike most builders, this one handles not only -// "operatorname", but also "supsub" since \operatorname* can -// affect super/subscripting. - -const mathmlBuilder$9 = (group, style) => { - let expression = buildExpression(group.body, style.withFont("mathrm")); - - // Is expression a string or has it something like a fraction? - let isAllString = true; // default - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - switch (node.type) { - case "mi": - case "mn": - case "ms": - case "mtext": - break; // Do nothing yet. - case "mspace": - { - if (node.attributes.width) { - const width = node.attributes.width.replace("em", ""); - const ch = spaceCharacter(Number(width)); - if (ch === "") { - isAllString = false; - } else { - expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)]); - } - } - } - break - case "mo": { - const child = node.children[0]; - if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { - child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); - } else { - isAllString = false; - } - break - } - default: - isAllString = false; - } - } else { - isAllString = false; - } - } - - if (isAllString) { - // Write a single TextNode instead of multiple nested tags. - const word = expression.map((node) => node.toText()).join(""); - expression = [new mathMLTree.TextNode(word)]; - } else if ( - expression.length === 1 - && utils.contains(["mover", "munder"], expression[0].type) && - (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext") - ) { - expression[0].children[0].type = "mi"; - if (group.parentIsSupSub) { - return new mathMLTree.MathNode("mrow", expression) - } else { - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - return mathMLTree.newDocumentFragment([expression[0], operator]) - } - } - - let wrapper; - if (isAllString) { - wrapper = new mathMLTree.MathNode("mi", expression); - wrapper.setAttribute("mathvariant", "normal"); - } else { - wrapper = new mathMLTree.MathNode("mrow", expression); - } - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (group.needsLeadingSpace) { - // LaTeX gives operator spacing, but a gets ord spacing. - // So add a leading space. - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - return mathMLTree.newDocumentFragment([space, wrapper, operator]) - } else { - return mathMLTree.newDocumentFragment([wrapper, operator]) - } - } - - return wrapper -}; - -// \operatorname -// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ -defineFunction({ - type: "operatorname", - names: ["\\operatorname@", "\\operatornamewithlimits"], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = args[0]; - const prevAtomType = parser.prevAtomType; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$9 -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, true); - } -}); - -defineFunction({ - type: "overline", - names: ["\\overline"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - const body = args[0]; - return { - type: "overline", - mode: parser.mode, - body - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005F")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode( - "mover", - [buildGroup(group.body, style), operator] - ); - node.setAttribute("accent", "true"); - - return node; - } -}); - -defineFunction({ - type: "phantom", - names: ["\\phantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "phantom", - mode: parser.mode, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(group.body, style); - return new mathMLTree.MathNode("mphantom", inner); - } -}); - -defineFunction({ - type: "hphantom", - names: ["\\hphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "hphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("height", "0px"); - node.setAttribute("depth", "0px"); - return node; - } -}); - -defineFunction({ - type: "vphantom", - names: ["\\vphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "vphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("width", "0px"); - return node; - } -}); - -// \pmb is a simulation of bold font. -// The version of \pmb in ambsy.sty works by typesetting three copies of the argument -// with small offsets. We use CSS text-shadow. -// It's a hack. Not as good as a real bold font. Better than nothing. - -defineFunction({ - type: "pmb", - names: ["\\pmb"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "pmb", - mode: parser.mode, - body: ordargument(args[0]) - } - }, - mathmlBuilder(group, style) { - const inner = buildExpression(group.body, style); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px"); - return node - } -}); - -const sign = num => num >= 0 ? "+" : "-"; - -// \raise, \lower, and \raisebox - -const mathmlBuilder$a = (group, style) => { - const newStyle = style.withLevel(StyleLevel.TEXT); - const node = new mathMLTree.MathNode("mpadded", [buildGroup(group.body, newStyle)]); - const dy = calculateSize(group.dy, style); - node.setAttribute("voffset", dy.number + dy.unit); - const dyAbs = Math.abs(dy.number); - node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit); - node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit); - return node -}; - -defineFunction({ - type: "raise", - names: ["\\raise", "\\lower"], - props: { - numArgs: 2, - argTypes: ["size", "primitive"], - primitive: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - if (funcName === "\\lower") { amount.number *= -1; } - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - - -defineFunction({ - type: "raise", - names: ["\\raisebox"], - props: { - numArgs: 2, - argTypes: ["size", "hbox"], - allowedInText: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - -defineFunction({ - type: "ref", - names: ["\\ref", "\\eqref"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser, funcName }, args) { - return { - type: "ref", - mode: parser.mode, - funcName, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Create an empty text node. Set a class and an href. - // The post-processor will populate with the target's tag or equation number. - const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"]; - const node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("")], classes); - node.setAttribute("href", "#" + group.string); - return node - } -}); - -defineFunction({ - type: "internal", - names: ["\\relax"], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser }) { - return { - type: "internal", - mode: parser.mode - }; - } -}); - -defineFunction({ - type: "rule", - names: ["\\rule"], - props: { - numArgs: 2, - numOptionalArgs: 1, - argTypes: ["size", "size", "size"] - }, - handler({ parser }, args, optArgs) { - const shift = optArgs[0]; - const width = assertNodeType(args[0], "size"); - const height = assertNodeType(args[1], "size"); - return { - type: "rule", - mode: parser.mode, - shift: shift && assertNodeType(shift, "size").value, - width: width.value, - height: height.value - }; - }, - mathmlBuilder(group, style) { - const width = calculateSize(group.width, style); - const height = calculateSize(group.height, style); - const shift = group.shift - ? calculateSize(group.shift, style) - : { number: 0, unit: "em" }; - const color = (style.color && style.getColor()) || "black"; - - const rule = new mathMLTree.MathNode("mspace"); - rule.setAttribute("mathbackground", color); - rule.setAttribute("width", width.number + width.unit); - rule.setAttribute("height", height.number + height.unit); - - const wrapper = new mathMLTree.MathNode("mpadded", [rule]); - if (shift.number >= 0) { - wrapper.setAttribute("height", "+" + shift.number + shift.unit); - } else { - wrapper.setAttribute("height", shift.number + shift.unit); - wrapper.setAttribute("depth", "+" + -shift.number + shift.unit); - } - wrapper.setAttribute("voffset", shift.number + shift.unit); - return wrapper; - } -}); - -// The size mappings are taken from TeX with \normalsize=10pt. -// We don't have to track script level. MathML does that. -const sizeMap = { - "\\tiny": 0.5, - "\\sixptsize": 0.6, - "\\Tiny": 0.6, - "\\scriptsize": 0.7, - "\\footnotesize": 0.8, - "\\small": 0.9, - "\\normalsize": 1.0, - "\\large": 1.2, - "\\Large": 1.44, - "\\LARGE": 1.728, - "\\huge": 2.074, - "\\Huge": 2.488 -}; - -defineFunction({ - type: "sizing", - names: [ - "\\tiny", - "\\sixptsize", - "\\Tiny", - "\\scriptsize", - "\\footnotesize", - "\\small", - "\\normalsize", - "\\large", - "\\Large", - "\\LARGE", - "\\huge", - "\\Huge" - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ breakOnTokenText, funcName, parser }, args) => { - const body = parser.parseExpression(false, breakOnTokenText); - return { - type: "sizing", - mode: parser.mode, - funcName, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(group.body, style); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("mathsize", sizeMap[group.funcName] + "em"); - return node; - } -}); - -// smash, with optional [tb], as in AMS - -defineFunction({ - type: "smash", - names: ["\\smash"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args, optArgs) => { - let smashHeight = false; - let smashDepth = false; - const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); - if (tbArg) { - // Optional [tb] argument is engaged. - // ref: amsmath: \renewcommand{\smash}[1][tb]{% - // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% - let letter = ""; - for (let i = 0; i < tbArg.body.length; ++i) { - const node = tbArg.body[i]; - // TODO: Write an AssertSymbolNode - letter = node.text; - if (letter === "t") { - smashHeight = true; - } else if (letter === "b") { - smashDepth = true; - } else { - smashHeight = false; - smashDepth = false; - break; - } - } - } else { - smashHeight = true; - smashDepth = true; - } - - const body = args[0]; - return { - type: "smash", - mode: parser.mode, - body, - smashHeight, - smashDepth - }; - }, - mathmlBuilder: (group, style) => { - const node = new mathMLTree.MathNode("mpadded", [buildGroup(group.body, style)]); - - if (group.smashHeight) { - node.setAttribute("height", "0px"); - } - - if (group.smashDepth) { - node.setAttribute("depth", "0px"); - } - - return node; - } -}); - -defineFunction({ - type: "sqrt", - names: ["\\sqrt"], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser }, args, optArgs) { - const index = optArgs[0]; - const body = args[0]; - return { - type: "sqrt", - mode: parser.mode, - body, - index - }; - }, - mathmlBuilder(group, style) { - const { body, index } = group; - return index - ? new mathMLTree.MathNode("mroot", [ - buildGroup(body, style), - buildGroup(index, style.incrementLevel()) - ]) - : new mathMLTree.MathNode("msqrt", [buildGroup(body, style)]); - } -}); - -const styleMap = { - display: 0, - text: 1, - script: 2, - scriptscript: 3 -}; - -const styleAttributes = { - display: ["0", "true"], - text: ["0", "false"], - script: ["1", "false"], - scriptscript: ["2", "false"] -}; - -defineFunction({ - type: "styling", - names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ breakOnTokenText, funcName, parser }, args) { - // parse out the implicit body - const body = parser.parseExpression(true, breakOnTokenText); - - const scriptLevel = funcName.slice(1, funcName.length - 5); - return { - type: "styling", - mode: parser.mode, - // Figure out what scriptLevel to use by pulling out the scriptLevel from - // the function name - scriptLevel, - body - }; - }, - mathmlBuilder(group, style) { - // Figure out what scriptLevel we're changing to. - const newStyle = style.withLevel(styleMap[group.scriptLevel]); - // The style argument in the next line does NOT directly set a MathML script level. - // It just tracks the style level, in case we need to know it for supsub or mathchoice. - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - - const attr = styleAttributes[group.scriptLevel]; - - // Here is where we set the MathML script level. - node.setAttribute("scriptlevel", attr[0]); - node.setAttribute("displaystyle", attr[1]); - - return node; - } -}); - -/** - * Sometimes, groups perform special rules when they have superscripts or - * subscripts attached to them. This function lets the `supsub` group know that - * Sometimes, groups perform special rules when they have superscripts or - * its inner element should handle the superscripts and subscripts instead of - * handling them itself. - */ - -// Helpers -const symbolRegEx = /^m(over|under|underover)$/; - -// Super scripts and subscripts, whose precise placement can depend on other -// functions that precede them. -defineFunctionBuilders({ - type: "supsub", - mathmlBuilder(group, style) { - // Is the inner group a relevant horizonal brace? - let isBrace = false; - let isOver; - let isSup; - let appendApplyFunction = false; - let needsLeadingSpace = false; - - if (group.base && group.base.type === "horizBrace") { - isSup = !!group.sup; - if (isSup === group.base.isOver) { - isBrace = true; - isOver = group.base.isOver; - } - } - - if (group.base && !group.base.stack && - (group.base.type === "op" || group.base.type === "operatorname")) { - group.base.parentIsSupSub = true; - appendApplyFunction = !group.base.symbol; - needsLeadingSpace = group.base.needsLeadingSpace; - } - - const children = group.base && group.base.stack - ? [buildGroup(group.base.body[0], style)] - : [buildGroup(group.base, style)]; - - const childStyle = style.inSubOrSup(); - if (group.sub) { - children.push(buildGroup(group.sub, childStyle)); - } - - if (group.sup) { - children.push(buildGroup(group.sup, childStyle)); - } - - let nodeType; - if (isBrace) { - nodeType = isOver ? "mover" : "munder"; - } else if (!group.sub) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "mover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "mover"; - } else { - nodeType = "msup"; - } - } else if (!group.sup) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munder"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "munder"; - } else { - nodeType = "msub"; - } - } else { - const base = group.base; - if (base && ((base.type === "op" && base.limits) || base.type === "multiscript") && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munderover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (style.level === StyleLevel.DISPLAY || base.limits) - ) { - nodeType = "munderover"; - } else { - nodeType = "msubsup"; - } - } - - let node = new mathMLTree.MathNode(nodeType, children); - if (appendApplyFunction) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (needsLeadingSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node = mathMLTree.newDocumentFragment([space, node, operator]); - } else { - node = mathMLTree.newDocumentFragment([node, operator]); - } - } else if (symbolRegEx.test(nodeType)) { - // Wrap in a . Otherwise Firefox stretchy parens will not stretch to include limits. - node = new mathMLTree.MathNode("mrow", [node]); - } - - return node - } -}); - -// Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js. - -const short = ["\\shortmid", "\\nshortmid", "\\shortparallel", - "\\nshortparallel", "\\smallsetminus"]; - -defineFunctionBuilders({ - type: "atom", - mathmlBuilder(group, style) { - const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]); - if (group.family === "punct") { - node.setAttribute("separator", "true"); - } else if (group.family === "open" || group.family === "close") { - // Delims built here should not stretch vertically. - // See delimsizing.js for stretchy delims. - if (group.family === "open") { - node.setAttribute("form", "prefix"); - // Set an explicit attribute for stretch. Otherwise Firefox may do it wrong. - node.setAttribute("stretchy", "false"); - } else if (group.family === "close") { - node.setAttribute("form", "postfix"); - node.setAttribute("stretchy", "false"); - } - } else if (group.text === "\\mid") { - // Firefox messes up this spacing if at the end of an . See it explicitly. - node.setAttribute("lspace", "0.22em"); // medium space - node.setAttribute("rspace", "0.22em"); - node.setAttribute("stretchy", "false"); - } else if (short.includes(group.text)) { - node.setAttribute("mathsize", "70%"); - } else if (group.text === ":") { - // ":" is not in the MathML operator dictionary. Give it BIN spacing. - node.attributes.lspace = "0.2222em"; - node.attributes.rspace = "0.2222em"; - } - return node; - } -}); - -/** - * Maps TeX font commands to "mathvariant" attribute in buildMathML.js - */ -const fontMap = { - // styles - mathbf: "bold", - mathrm: "normal", - textit: "italic", - mathit: "italic", - mathnormal: "italic", - - // families - mathbb: "double-struck", - mathcal: "script", - mathfrak: "fraktur", - mathscr: "script", - mathsf: "sans-serif", - mathtt: "monospace", - oldstylenums: "oldstylenums" -}; - -/** - * Returns the math variant as a string or null if none is required. - */ -const getVariant = function(group, style) { - // Handle font specifiers as best we can. - // Chromium does not support the MathML mathvariant attribute. - // So we'll use Unicode replacement characters instead. - // But first, determine the math variant. - - // Deal with the \textit, \textbf, etc., functions. - if (style.fontFamily === "texttt") { - return "monospace" - } else if (style.fontFamily === "textsc") { - return "normal"; // handled via character substitution in symbolsOrd.js. - } else if (style.fontFamily === "textsf") { - if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "sans-serif-bold-italic" - } else if (style.fontShape === "textit") { - return "sans-serif-italic" - } else if (style.fontWeight === "textbf") { - return "sans-serif-bold" - } else { - return "sans-serif" - } - } else if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "bold-italic" - } else if (style.fontShape === "textit") { - return "italic" - } else if (style.fontWeight === "textbf") { - return "bold" - } - - // Deal with the \mathit, mathbf, etc, functions. - const font = style.font; - if (!font || font === "mathnormal") { - return null - } - - const mode = group.mode; - switch (font) { - case "mathit": - return "italic" - case "mathrm": { - const codePoint = group.text.codePointAt(0); - // LaTeX \mathrm returns italic for Greek characters. - return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal" - } - case "greekItalic": - return "italic" - case "up@greek": - return "normal" - case "boldsymbol": - case "mathboldsymbol": - return "bold-italic" - case "mathbf": - return "bold" - case "mathbb": - return "double-struck" - case "mathfrak": - return "fraktur" - case "mathscr": - case "mathcal": - return "script" - case "mathsf": - return "sans-serif" - case "mathtt": - return "monospace" - case "oldstylenums": - return "oldstylenums" - } - - let text = group.text; - if (symbols[mode][text] && symbols[mode][text].replace) { - text = symbols[mode][text].replace; - } - - return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null -}; - -// Chromium does not support the MathML `mathvariant` attribute. -// Instead, we replace ASCII characters with Unicode characters that -// are defined in the font as bold, italic, double-struck, etc. -// This module identifies those Unicode code points. - -// First, a few helpers. -const script = Object.freeze({ - B: 0x20EA, // Offset from ASCII B to Unicode script B - E: 0x20EB, - F: 0x20EB, - H: 0x20C3, - I: 0x20C7, - L: 0x20C6, - M: 0x20E6, - R: 0x20C9, - e: 0x20CA, - g: 0x20A3, - o: 0x20C5 -}); - -const frak = Object.freeze({ - C: 0x20EA, - H: 0x20C4, - I: 0x20C8, - R: 0x20CA, - Z: 0x20CE -}); - -const bbb = Object.freeze({ - C: 0x20BF, // blackboard bold - H: 0x20C5, - N: 0x20C7, - P: 0x20C9, - Q: 0x20C9, - R: 0x20CB, - Z: 0x20CA -}); - -const bold = Object.freeze({ - "\u03f5": 0x1D2E7, // lunate epsilon - "\u03d1": 0x1D30C, // vartheta - "\u03f0": 0x1D2EE, // varkappa - "\u03c6": 0x1D319, // varphi - "\u03f1": 0x1D2EF, // varrho - "\u03d6": 0x1D30B // varpi -}); - -const boldItalic = Object.freeze({ - "\u03f5": 0x1D35B, // lunate epsilon - "\u03d1": 0x1D380, // vartheta - "\u03f0": 0x1D362, // varkappa - "\u03c6": 0x1D38D, // varphi - "\u03f1": 0x1D363, // varrho - "\u03d6": 0x1D37F // varpi -}); - -const boldsf = Object.freeze({ - "\u03f5": 0x1D395, // lunate epsilon - "\u03d1": 0x1D3BA, // vartheta - "\u03f0": 0x1D39C, // varkappa - "\u03c6": 0x1D3C7, // varphi - "\u03f1": 0x1D39D, // varrho - "\u03d6": 0x1D3B9 // varpi -}); - -const bisf = Object.freeze({ - "\u03f5": 0x1D3CF, // lunate epsilon - "\u03d1": 0x1D3F4, // vartheta - "\u03f0": 0x1D3D6, // varkappa - "\u03c6": 0x1D401, // varphi - "\u03f1": 0x1D3D7, // varrho - "\u03d6": 0x1D3F3 // varpi -}); - -// Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf -const offset = Object.freeze({ - upperCaseLatin: { // A-Z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3BF }, - "italic": ch => { return 0x1D3F3 }, - "bold-italic": ch => { return 0x1D427 }, - "script": ch => { return script[ch] || 0x1D45B }, - "script-bold": ch => { return 0x1D48F }, - "fraktur": ch => { return frak[ch] || 0x1D4C3 }, - "fraktur-bold": ch => { return 0x1D52B }, - "double-struck": ch => { return bbb[ch] || 0x1D4F7 }, - "sans-serif": ch => { return 0x1D55F }, - "sans-serif-bold": ch => { return 0x1D593 }, - "sans-serif-italic": ch => { return 0x1D5C7 }, - "sans-serif-bold-italic": ch => { return 0x1D63C }, - "monospace": ch => { return 0x1D62F } - }, - lowerCaseLatin: { // a-z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3B9 }, - "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED }, - "bold-italic": ch => { return 0x1D421 }, - "script": ch => { return script[ch] || 0x1D455 }, - "script-bold": ch => { return 0x1D489 }, - "fraktur": ch => { return 0x1D4BD }, - "fraktur-bold": ch => { return 0x1D525 }, - "double-struck": ch => { return 0x1D4F1 }, - "sans-serif": ch => { return 0x1D559 }, - "sans-serif-bold": ch => { return 0x1D58D }, - "sans-serif-italic": ch => { return 0x1D5C1 }, - "sans-serif-bold-italic": ch => { return 0x1D5F5 }, - "monospace": ch => { return 0x1D629 } - }, - upperCaseGreek: { // A-Ω ∇ - "normal": ch => { return 0 }, - "bold": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "italic": ch => { return ch === "∇" ? 0x1B4F4 : 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-bold": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return ch === "∇" ? 0x1B5A2 : 0x1D3FF }, - "monospace": ch => { return 0 } - }, - lowerCaseGreek: { // α-ω - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D311 }, - "italic": ch => { return 0x1D34B }, - "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return 0x1D3BF }, - "sans-serif-bold": ch => { return 0x1D3BF }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0x1D3F9 }, - "monospace": ch => { return 0 } - }, - varGreek: { // \varGamma, etc - "normal": ch => { return 0 }, - "bold": ch => { return bold[ch] || -51 }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return boldItalic[ch] || 0x3A }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - "sans-serif": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-bold": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE }, - "monospace": ch => { return 0 } - }, - numeral: { // 0-9 - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D79E }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return 0 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0x1D7A8 }, - "sans-serif": ch => { return 0x1D7B2 }, - "sans-serif-bold": ch => { return 0x1D7BC }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0 }, - "monospace": ch => { return 0x1D7C6 } - } -}); - -const variantChar = (ch, variant) => { - const codePoint = ch.codePointAt(0); - const block = 0x40 < codePoint && codePoint < 0x5b - ? "upperCaseLatin" - : 0x60 < codePoint && codePoint < 0x7b - ? "lowerCaseLatin" - : (0x390 < codePoint && codePoint < 0x3AA) || ch === "∇" - ? "upperCaseGreek" - : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5" - ? "lowerCaseGreek" - : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch] - ? "varGreek" - : (0x2F < codePoint && codePoint < 0x3A) - ? "numeral" - : "other"; - return block === "other" - ? ch - : String.fromCodePoint(codePoint + offset[block][variant](ch)) -}; - -const smallCaps = Object.freeze({ - a: "ᴀ", - b: "ʙ", - c: "ᴄ", - d: "ᴅ", - e: "ᴇ", - f: "ꜰ", - g: "ɢ", - h: "ʜ", - i: "ɪ", - j: "ᴊ", - k: "ᴋ", - l: "ʟ", - m: "ᴍ", - n: "ɴ", - o: "ᴏ", - p: "ᴘ", - q: "ǫ", - r: "ʀ", - s: "s", - t: "ᴛ", - u: "ᴜ", - v: "ᴠ", - w: "ᴡ", - x: "x", - y: "ʏ", - z: "ᴢ" -}); - -// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in -// src/symbols.js. - -const numberRegEx = /^\d[\d.]*$/; // Keep in sync with numberRegEx in Parser.js - -const italicNumber = (text, variant) => { - const mn = new mathMLTree.MathNode("mn", [text]); - const wrapper = new mathMLTree.MathNode("mstyle", [mn]); - wrapper.style["font-style"] = "italic"; - wrapper.style["font-family"] = "Cambria, 'Times New Roman', serif"; - if (variant === "bold-italic") { wrapper.style["font-weight"] = "bold"; } - return wrapper -}; - -defineFunctionBuilders({ - type: "mathord", - mathmlBuilder(group, style) { - const text = makeText(group.text, group.mode, style); - const codePoint = text.text.codePointAt(0); - // Test for upper-case Greek - const defaultVariant = (0x0390 < codePoint && codePoint < 0x03aa) ? "normal" : "italic"; - const variant = getVariant(group, style) || defaultVariant; - if (variant === "script") { - text.text = variantChar(text.text, variant); - return new mathMLTree.MathNode("mi", [text], [style.font]) - } else if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - const node = new mathMLTree.MathNode("mi", [text]); - // TODO: Handle U+1D49C - U+1D4CF per https://www.unicode.org/charts/PDF/U1D400.pdf - if (variant === "normal") { - node.setAttribute("mathvariant", "normal"); - } - return node - } -}); - -defineFunctionBuilders({ - type: "textord", - mathmlBuilder(group, style) { - let ch = group.text; - const codePoint = ch.codePointAt(0); - if (style.fontFamily === "textsc") { - // Convert small latin letters to small caps. - if (96 < codePoint && codePoint < 123) { - ch = smallCaps[ch]; - } - } - const text = makeText(ch, group.mode, style); - const variant = getVariant(group, style) || "normal"; - - let node; - if (group.mode === "text") { - if (variant === "italic" || variant === "bold-italic") { - if (numberRegEx.test(group.text)) { - return italicNumber(text, variant) - } - } - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (numberRegEx.test(group.text)) { - if (variant === "oldstylenums") { - const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]); - node = new mathMLTree.MathNode("mn", [ms]); - } else if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode("mn", [text]); - } - } else if (group.text === "\\prime") { - node = new mathMLTree.MathNode("mo", [text]); - } else { - const origText = text.text; - if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mi", [text]); - if (text.text === origText ) { - node.setAttribute("mathvariant", "italic"); - } - } - return node - } -}); - -// A map of CSS-based spacing functions to their CSS class. -const cssSpace = { - "\\nobreak": "nobreak", - "\\allowbreak": "allowbreak" -}; - -// A lookup table to determine whether a spacing function/symbol should be -// treated like a regular space character. If a symbol or command is a key -// in this table, then it should be a regular space character. Furthermore, -// the associated value may have a `className` specifying an extra CSS class -// to add to the created `span`. -const regularSpace = { - " ": {}, - "\\ ": {}, - "~": { - className: "nobreak" - }, - "\\space": {}, - "\\nobreakspace": { - className: "nobreak" - } -}; - -// ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in -// src/symbols.js. -defineFunctionBuilders({ - type: "spacing", - mathmlBuilder(group, style) { - let node; - - if (Object.prototype.hasOwnProperty.call(regularSpace, group.text)) { - // Firefox does not render a space in a . So write a no-break space. - // TODO: If Firefox fixes that bug, uncomment the next line and write ch into the node. - //const ch = (regularSpace[group.text].className === "nobreak") ? "\u00a0" : " " - node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]); - } else if (Object.prototype.hasOwnProperty.call(cssSpace, group.text)) { - // MathML 3.0 calls for nobreak to occur in an , not an - // Ref: https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs - node = new mathMLTree.MathNode("mo"); - if (group.text === "\\nobreak") { - node.setAttribute("linebreak", "nobreak"); - } - } else { - throw new ParseError(`Unknown type of space "${group.text}"`) - } - - return node - } -}); - -defineFunctionBuilders({ - type: "tag" -}); - -// For a \tag, the work usually done in a mathmlBuilder is instead done in buildMathML.js. -// That way, a \tag can be pulled out of the parse tree and wrapped around the outer node. - -// Non-mathy text, possibly in a font -const textFontFamilies = { - "\\text": undefined, - "\\textrm": "textrm", - "\\textsf": "textsf", - "\\texttt": "texttt", - "\\textnormal": "textrm", - "\\textsc": "textsc" // small caps -}; - -const textFontWeights = { - "\\textbf": "textbf", - "\\textmd": "textmd" -}; - -const textFontShapes = { - "\\textit": "textit", - "\\textup": "textup" -}; - -const styleWithFont = (group, style) => { - const font = group.font; - // Checks if the argument is a font family or a font style. - if (!font) { - return style; - } else if (textFontFamilies[font]) { - return style.withTextFontFamily(textFontFamilies[font]); - } else if (textFontWeights[font]) { - return style.withTextFontWeight(textFontWeights[font]); - } else { - return style.withTextFontShape(textFontShapes[font]); - } -}; - -defineFunction({ - type: "text", - names: [ - // Font families - "\\text", - "\\textrm", - "\\textsf", - "\\texttt", - "\\textnormal", - "\\textsc", - // Font weights - "\\textbf", - "\\textmd", - // Font Shapes - "\\textit", - "\\textup" - ], - props: { - numArgs: 1, - argTypes: ["text"], - allowedInArgument: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "text", - mode: parser.mode, - body: ordargument(body), - font: funcName - }; - }, - mathmlBuilder(group, style) { - const newStyle = styleWithFont(group, style); - const mrow = buildExpressionRow(group.body, newStyle); - - // If possible, consolidate adjacent elements into a single element. - // First, check if it is possible. If not, return the . - if (mrow.type !== "mrow") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - const mtext = mrow.children[0]; - if (!mtext.attributes || mtext.type !== "mtext") { return mrow } - const variant = mtext.attributes.mathvariant || ""; - for (let i = 1; i < mrow.children.length; i++) { - const localVariant = mrow.children[i].attributes.mathvariant || ""; - if (localVariant !== variant || mrow.children[i].type !== "mtext") { return mrow } - } - - // Consolidate the elements. - for (let i = 1; i < mrow.children.length; i++) { - mtext.children[0].text += mrow.children[i].children[0].text; - } - mtext.children.splice(1, mtext.children.length - 1); - // Firefox does not render a space at either end of the string. - // To get proper rendering, we replace with no-break spaces. - if (mtext.children[0].text.charAt(0) === " ") { - mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1); - } - const L = mtext.children[0].text.length; - if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") { - mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0"; - } - return mtext - } -}); - -// Two functions included to enable migration from Mathjax. - -defineFunction({ - type: "tip", - names: ["\\mathtip"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup(group.body, style); - const tip = buildGroup(group.tip, style); - // Browsers don't support the tooltip actiontype. - // TODO: Come back and fix \mathtip when it can be done via CSS w/o a JS event. - const node = new mathMLTree.MathNode("maction", [math, tip], ["tml-tip"]); - node.setAttribute("actiontype", "tooltip"); - return node - } -}); - -defineFunction({ - type: "tip", - names: ["\\texttip"], - props: { - numArgs: 2, - argTypes: ["math", "text"] - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup(group.body, style); - const tip = buildGroup(group.tip, style); - // args[1] only accepted text, so tip is a element or a of them. - let str = ""; - if (tip.type === "mtext") { - str = tip.children[0].text; - } else { - for (const child of tip.children) { - str += child.children[0].text; - } - } - // Implement \texttip via a title attribute. - math.setAttribute("title", str); - return math - } -}); - -defineFunctionBuilders({ - type: "toggle", - mathmlBuilder(group, style) { - const expression = buildExpression(group.body, style); - const node = new mathMLTree.MathNode("maction", expression, [], { cursor: "default" }); - node.setAttribute("actiontype", "toggle"); - return node - } -}); - -defineFunction({ - type: "underline", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "underline", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005f")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode("munder", - [buildGroup(group.body, style), operator] - ); - node.setAttribute("accentunder", "true"); - - return node; - } -}); - -defineFunction({ - type: "verb", - names: ["\\verb"], - props: { - numArgs: 0, - allowedInText: true - }, - handler(context, args, optArgs) { - // \verb and \verb* are dealt with directly in Parser.js. - // If we end up here, it's because of a failure to match the two delimiters - // in the regex in Lexer.js. LaTeX raises the following error when \verb is - // terminated by end of line (or file). - throw new ParseError("\\verb ended by end of line instead of matching delimiter"); - }, - mathmlBuilder(group, style) { - const text = new mathMLTree.TextNode(makeVerb(group)); - const node = new mathMLTree.MathNode("mtext", [text]); - node.setAttribute("mathvariant", "monospace"); - return node; - } -}); - -/** - * Converts verb group into body string. - * - * \verb* replaces each space with an open box \u2423 - * \verb replaces each space with a no-break space \xA0 - */ -const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0"); - -/** Include this to ensure that all functions are defined. */ - -const functions = _functions; - -/** - * Lexing or parsing positional information for error reporting. - * This object is immutable. - */ -class SourceLocation { - constructor(lexer, start, end) { - this.lexer = lexer; // Lexer holding the input string. - this.start = start; // Start offset, zero-based inclusive. - this.end = end; // End offset, zero-based exclusive. - } - - /** - * Merges two `SourceLocation`s from location providers, given they are - * provided in order of appearance. - * - Returns the first one's location if only the first is provided. - * - Returns a merged range of the first and the last if both are provided - * and their lexers match. - * - Otherwise, returns null. - */ - static range(first, second) { - if (!second) { - return first && first.loc; - } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { - return null; - } else { - return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); - } - } -} - -/** - * Interface required to break circular dependency between Token, Lexer, and - * ParseError. - */ - -/** - * The resulting token returned from `lex`. - * - * It consists of the token text plus some position information. - * The position information is essentially a range in an input string, - * but instead of referencing the bare input string, we refer to the lexer. - * That way it is possible to attach extra metadata to the input string, - * like for example a file name or similar. - * - * The position information is optional, so it is OK to construct synthetic - * tokens if appropriate. Not providing available position information may - * lead to degraded error reporting, though. - */ -class Token { - constructor( - text, // the text of this token - loc - ) { - this.text = text; - this.loc = loc; - } - - /** - * Given a pair of tokens (this and endToken), compute a `Token` encompassing - * the whole input range enclosed by these two. - */ - range( - endToken, // last token of the range, inclusive - text // the text of the newly constructed token - ) { - return new Token(text, SourceLocation.range(this, endToken)); - } -} - -/** - * The Lexer class handles tokenizing the input in various ways. Since our - * parser expects us to be able to backtrack, the lexer allows lexing from any - * given starting point. - * - * Its main exposed function is the `lex` function, which takes a position to - * lex from and a type of token to lex. It defers to the appropriate `_innerLex` - * function. - * - * The various `_innerLex` functions perform the actual lexing of different - * kinds. - */ - -/* The following tokenRegex - * - matches typical whitespace (but not NBSP etc.) using its first two groups - * - does not match any control character \x00-\x1f except whitespace - * - does not match a bare backslash - * - matches any ASCII character except those just mentioned - * - does not match the BMP private use area \uE000-\uF8FF - * - does not match bare surrogate code units - * - matches any BMP character except for those just described - * - matches any valid Unicode surrogate pair - * - mathches numerals - * - matches a backslash followed by one or more whitespace characters - * - matches a backslash followed by one or more letters then whitespace - * - matches a backslash followed by any BMP character - * Capturing groups: - * [1] regular whitespace - * [2] backslash followed by whitespace - * [3] anything else, which may include: - * [4] left character of \verb* - * [5] left character of \verb - * [6] backslash followed by word, excluding any trailing whitespace - * Just because the Lexer matches something doesn't mean it's valid input: - * If there is no matching function or symbol definition, the Parser will - * still reject the input. - */ -const spaceRegexString = "[ \r\n\t]"; -const controlWordRegexString = "\\\\[a-zA-Z@]+"; -const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; -const controlWordWhitespaceRegexString = `(${controlWordRegexString})${spaceRegexString}*`; -const controlSpaceRegexString = "\\\\(\n|[ \r\t]+\n?)[ \r\t]*"; -const combiningDiacriticalMarkString = "[\u0300-\u036f]"; -const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); -const tokenRegexString = - `(${spaceRegexString}+)|` + // whitespace - `${controlSpaceRegexString}|` + // whitespace - "(\\d[\\d.]*" + // numbers (in non-strict mode) - "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|\\\\verb\\*([^]).*?\\4" + // \verb* - "|\\\\verb([^*a-zA-Z]).*?\\5" + // \verb unstarred - `|${controlWordWhitespaceRegexString}` + // \macroName + spaces - `|${controlSymbolRegexString})`; // \\, \', etc. - -/** Main Lexer class */ -class Lexer { - constructor(input, settings) { - // Separate accents from characters - this.input = input; - this.settings = settings; - this.tokenRegex = new RegExp( - // Strict Temml, like TeX, lexes one numeral at a time. - // Default Temml lexes contiguous numerals into a single element. - tokenRegexString.replace("\\d[\\d.]*|", settings.strict ? "" : "\\d[\\d.]*|"), - "g" - ); - // Category codes. The lexer only supports comment characters (14) for now. - // MacroExpander additionally distinguishes active (13). - this.catcodes = { - "%": 14, // comment character - "~": 13 // active character - }; - } - - setCatcode(char, code) { - this.catcodes[char] = code; - } - - /** - * This function lexes a single token. - */ - lex() { - const input = this.input; - const pos = this.tokenRegex.lastIndex; - if (pos === input.length) { - return new Token("EOF", new SourceLocation(this, pos, pos)); - } - const match = this.tokenRegex.exec(input); - if (match === null || match.index !== pos) { - throw new ParseError( - `Unexpected character: '${input[pos]}'`, - new Token(input[pos], new SourceLocation(this, pos, pos + 1)) - ); - } - const text = match[6] || match[3] || (match[2] ? "\\ " : " "); - - if (this.catcodes[text] === 14) { - // comment character - const nlIndex = input.indexOf("\n", this.tokenRegex.lastIndex); - if (nlIndex === -1) { - this.tokenRegex.lastIndex = input.length; // EOF - this.settings.reportNonstrict( - "commentAtEnd", - "% comment has no terminating newline; LaTeX would " + - "fail because of commenting the end of math mode (e.g. $)" - ); - } else { - this.tokenRegex.lastIndex = nlIndex + 1; - } - return this.lex(); - } - - return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); - } -} - -/** - * A `Namespace` refers to a space of nameable things like macros or lengths, - * which can be `set` either globally or local to a nested group, using an - * undo stack similar to how TeX implements this functionality. - * Performance-wise, `get` and `set` take constant time. - */ - -class Namespace { - /** - * Both arguments are optional. The first argument is an object of - * built-in mappings which never change. The second argument is an object - * of initial (global-level) mappings, which will constantly change - * according to any global/top-level `set`s done. - */ - constructor(builtins = {}, globalMacros = {}) { - this.current = globalMacros; - this.builtins = builtins; - this.undefStack = []; - } - - /** - * Start a new nested group, affecting future local `set`s. - */ - beginGroup() { - this.undefStack.push({}); - } - - /** - * End current nested group, restoring values before the group began. - */ - endGroup() { - if (this.undefStack.length === 0) { - throw new ParseError( - "Unbalanced namespace destruction: attempt " + - "to pop global namespace; please report this as a bug" - ); - } - const undefs = this.undefStack.pop(); - for (const undef in undefs) { - if (Object.prototype.hasOwnProperty.call(undefs, undef )) { - if (undefs[undef] === undefined) { - delete this.current[undef]; - } else { - this.current[undef] = undefs[undef]; - } - } - } - } - - /** - * Detect whether `name` has a definition. Equivalent to - * `get(name) != null`. - */ - has(name) { - return Object.prototype.hasOwnProperty.call(this.current, name ) || - Object.prototype.hasOwnProperty.call(this.builtins, name ); - } - - /** - * Get the current value of a name, or `undefined` if there is no value. - * - * Note: Do not use `if (namespace.get(...))` to detect whether a macro - * is defined, as the definition may be the empty string which evaluates - * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or - * `if (namespace.has(...))`. - */ - get(name) { - if (Object.prototype.hasOwnProperty.call(this.current, name )) { - return this.current[name]; - } else { - return this.builtins[name]; - } - } - - /** - * Set the current value of a name, and adds an undo - * operation to the undo stack. - */ - set(name, value) { - // Undo this set at end of this group (possibly to `undefined`), - // unless an undo is already in place, in which case that older - // value is the correct one. - const top = this.undefStack[this.undefStack.length - 1]; - if (top && !Object.prototype.hasOwnProperty.call(top, name )) { - top[name] = this.current[name]; - } - this.current[name] = value; - } -} - -/** - * Predefined macros for Temml. - * This can be used to define some commands in terms of others. - */ -const macros = _macros; - -////////////////////////////////////////////////////////////////////// -// macro tools - -defineMacro("\\noexpand", function(context) { - // The expansion is the token itself; but that token is interpreted - // as if its meaning were ‘\relax’ if it is a control sequence that - // would ordinarily be expanded by TeX’s expansion rules. - const t = context.popToken(); - if (context.isExpandable(t.text)) { - t.noexpand = true; - t.treatAsRelax = true; - } - return { tokens: [t], numArgs: 0 }; -}); - -defineMacro("\\expandafter", function(context) { - // TeX first reads the token that comes immediately after \expandafter, - // without expanding it; let’s call this token t. Then TeX reads the - // token that comes after t (and possibly more tokens, if that token - // has an argument), replacing it by its expansion. Finally TeX puts - // t back in front of that expansion. - const t = context.popToken(); - context.expandOnce(true); // expand only an expandable token - return { tokens: [t], numArgs: 0 }; -}); - -// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 -// TeX source: \long\def\@firstoftwo#1#2{#1} -defineMacro("\\@firstoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[0], numArgs: 0 }; -}); - -// LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 -// TeX source: \long\def\@secondoftwo#1#2{#2} -defineMacro("\\@secondoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[1], numArgs: 0 }; -}); - -// LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) -// symbol that isn't a space, consuming any spaces but not consuming the -// first nonspace character. If that nonspace character matches #1, then -// the macro expands to #2; otherwise, it expands to #3. -defineMacro("\\@ifnextchar", function(context) { - const args = context.consumeArgs(3); // symbol, if, else - context.consumeSpaces(); - const nextToken = context.future(); - if (args[0].length === 1 && args[0][0].text === nextToken.text) { - return { tokens: args[1], numArgs: 0 }; - } else { - return { tokens: args[2], numArgs: 0 }; - } -}); - -// LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. -// If it is `*`, then it consumes the symbol, and the macro expands to #1; -// otherwise, the macro expands to #2 (without consuming the symbol). -// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} -defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); - -// LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode -defineMacro("\\TextOrMath", function(context) { - const args = context.consumeArgs(2); - if (context.mode === "text") { - return { tokens: args[0], numArgs: 0 }; - } else { - return { tokens: args[1], numArgs: 0 }; - } -}); - -const stringFromArg = arg => { - // Reverse the order of the arg and return a string. - let str = ""; - for (let i = arg.length - 1; i > -1; i--) { - str += arg[i].text; - } - return str -}; - -// Lookup table for parsing numbers in base 8 through 16 -const digitToNumber = { - 0: 0, - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - a: 10, - A: 10, - b: 11, - B: 11, - c: 12, - C: 12, - d: 13, - D: 13, - e: 14, - E: 14, - f: 15, - F: 15 -}; - -const nextCharNumber = context => { - const numStr = context.future().text; - if (numStr === "EOF") { return [null, ""] } - return [digitToNumber[numStr.charAt(0)], numStr] -}; - -const appendCharNumbers = (number, numStr, base) => { - for (let i = 1; i < numStr.length; i++) { - const digit = digitToNumber[numStr.charAt(i)]; - number *= base; - number += digit; - } - return number -}; - -// TeX \char makes a literal character (catcode 12) using the following forms: -// (see The TeXBook, p. 43) -// \char123 -- decimal -// \char'123 -- octal -// \char"123 -- hex -// \char`x -- character that can be written (i.e. isn't active) -// \char`\x -- character that cannot be written (e.g. %) -// These all refer to characters from the font, so we turn them into special -// calls to a function \@char dealt with in the Parser. -defineMacro("\\char", function(context) { - let token = context.popToken(); - let base; - let number = ""; - if (token.text === "'") { - base = 8; - token = context.popToken(); - } else if (token.text === '"') { - base = 16; - token = context.popToken(); - } else if (token.text === "`") { - token = context.popToken(); - if (token.text[0] === "\\") { - number = token.text.charCodeAt(1); - } else if (token.text === "EOF") { - throw new ParseError("\\char` missing argument"); - } else { - number = token.text.charCodeAt(0); - } - } else { - base = 10; - } - if (base) { - // Parse a number in the given base, starting with first `token`. - let numStr = token.text; - number = digitToNumber[numStr.charAt(0)]; - if (number == null || number >= base) { - throw new ParseError(`Invalid base-${base} digit ${token.text}`); - } - number = appendCharNumbers(number, numStr, base); - let digit; - [digit, numStr] = nextCharNumber(context); - while (digit != null && digit < base) { - number *= base; - number += digit; - number = appendCharNumbers(number, numStr, base); - context.popToken(); - [digit, numStr] = nextCharNumber(context); - } - } - return `\\@char{${number}}`; -}); - -defineMacro("\\hbox", "\\text{#1}"); - -// Per TeXbook p.122, "/" gets zero operator spacing. -// And MDN recommends using U+2044 instead of / for inline -defineMacro("/", "{\u2044}"); - -// Since Temml has no \par, ignore \long. -defineMacro("\\long", ""); - -////////////////////////////////////////////////////////////////////// -// Grouping -// \let\bgroup={ \let\egroup=} -defineMacro("\\bgroup", "{"); -defineMacro("\\egroup", "}"); - -// Symbols from latex.ltx: -// \def~{\nobreakspace{}} -// \def\lq{`} -// \def\rq{'} -// \def \aa {\r a} -defineMacro("~", "\\nobreakspace"); -defineMacro("\\lq", "`"); -defineMacro("\\rq", "'"); -defineMacro("\\aa", "\\r a"); - -defineMacro("\\Bbbk", "\\Bbb{k}"); - -// \mathstrut from the TeXbook, p 360 -defineMacro("\\mathstrut", "\\vphantom{(}"); - -// \underbar from TeXbook p 353 -defineMacro("\\underbar", "\\underline{\\text{#1}}"); - -////////////////////////////////////////////////////////////////////// -// LaTeX_2ε - -// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ -// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} -// We'll call \varvdots, which gets a glyph from symbols.js. -// The zero-width rule gets us an equivalent to the vertical 6pt kern. -defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); -defineMacro("\u22ee", "\\vdots"); - -////////////////////////////////////////////////////////////////////// -// amsmath.sty -// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf - -//\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} -defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); - -// \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} -defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); - -// \def\iff{\DOTSB\;\Longleftrightarrow\;} -// \def\implies{\DOTSB\;\Longrightarrow\;} -// \def\impliedby{\DOTSB\;\Longleftarrow\;} -defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); -defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); -defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); - -// AMSMath's automatic \dots, based on \mdots@@ macro. -const dotsByToken = { - ",": "\\dotsc", - "\\not": "\\dotsb", - // \keybin@ checks for the following: - "+": "\\dotsb", - "=": "\\dotsb", - "<": "\\dotsb", - ">": "\\dotsb", - "-": "\\dotsb", - "*": "\\dotsb", - ":": "\\dotsb", - // Symbols whose definition starts with \DOTSB: - "\\DOTSB": "\\dotsb", - "\\coprod": "\\dotsb", - "\\bigvee": "\\dotsb", - "\\bigwedge": "\\dotsb", - "\\biguplus": "\\dotsb", - "\\bigcap": "\\dotsb", - "\\bigcup": "\\dotsb", - "\\prod": "\\dotsb", - "\\sum": "\\dotsb", - "\\bigotimes": "\\dotsb", - "\\bigoplus": "\\dotsb", - "\\bigodot": "\\dotsb", - "\\bigsqcap": "\\dotsb", - "\\bigsqcup": "\\dotsb", - "\\And": "\\dotsb", - "\\longrightarrow": "\\dotsb", - "\\Longrightarrow": "\\dotsb", - "\\longleftarrow": "\\dotsb", - "\\Longleftarrow": "\\dotsb", - "\\longleftrightarrow": "\\dotsb", - "\\Longleftrightarrow": "\\dotsb", - "\\mapsto": "\\dotsb", - "\\longmapsto": "\\dotsb", - "\\hookrightarrow": "\\dotsb", - "\\doteq": "\\dotsb", - // Symbols whose definition starts with \mathbin: - "\\mathbin": "\\dotsb", - // Symbols whose definition starts with \mathrel: - "\\mathrel": "\\dotsb", - "\\relbar": "\\dotsb", - "\\Relbar": "\\dotsb", - "\\xrightarrow": "\\dotsb", - "\\xleftarrow": "\\dotsb", - // Symbols whose definition starts with \DOTSI: - "\\DOTSI": "\\dotsi", - "\\int": "\\dotsi", - "\\oint": "\\dotsi", - "\\iint": "\\dotsi", - "\\iiint": "\\dotsi", - "\\iiiint": "\\dotsi", - "\\idotsint": "\\dotsi", - // Symbols whose definition starts with \DOTSX: - "\\DOTSX": "\\dotsx" -}; - -defineMacro("\\dots", function(context) { - // TODO: If used in text mode, should expand to \textellipsis. - // However, in Temml, \textellipsis and \ldots behave the same - // (in text mode), and it's unlikely we'd see any of the math commands - // that affect the behavior of \dots when in text mode. So fine for now - // (until we support \ifmmode ... \else ... \fi). - let thedots = "\\dotso"; - const next = context.expandAfterFuture().text; - if (next in dotsByToken) { - thedots = dotsByToken[next]; - } else if (next.substr(0, 4) === "\\not") { - thedots = "\\dotsb"; - } else if (next in symbols.math) { - if (utils.contains(["bin", "rel"], symbols.math[next].group)) { - thedots = "\\dotsb"; - } - } - return thedots; -}); - -const spaceAfterDots = { - // \rightdelim@ checks for the following: - ")": true, - "]": true, - "\\rbrack": true, - "\\}": true, - "\\rbrace": true, - "\\rangle": true, - "\\rceil": true, - "\\rfloor": true, - "\\rgroup": true, - "\\rmoustache": true, - "\\right": true, - "\\bigr": true, - "\\biggr": true, - "\\Bigr": true, - "\\Biggr": true, - // \extra@ also tests for the following: - $: true, - // \extrap@ checks for the following: - ";": true, - ".": true, - ",": true -}; - -defineMacro("\\dotso", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\dotsc", function(context) { - const next = context.future().text; - // \dotsc uses \extra@ but not \extrap@, instead specially checking for - // ';' and '.', but doesn't check for ','. - if (next in spaceAfterDots && next !== ",") { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\cdots", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\@cdots\\,"; - } else { - return "\\@cdots"; - } -}); - -defineMacro("\\dotsb", "\\cdots"); -defineMacro("\\dotsm", "\\cdots"); -defineMacro("\\dotsi", "\\!\\cdots"); -defineMacro("\\idotsint", "\\dotsi"); -// amsmath doesn't actually define \dotsx, but \dots followed by a macro -// starting with \DOTSX implies \dotso, and then \extra@ detects this case -// and forces the added `\,`. -defineMacro("\\dotsx", "\\ldots\\,"); - -// \let\DOTSI\relax -// \let\DOTSB\relax -// \let\DOTSX\relax -defineMacro("\\DOTSI", "\\relax"); -defineMacro("\\DOTSB", "\\relax"); -defineMacro("\\DOTSX", "\\relax"); - -// Spacing, based on amsmath.sty's override of LaTeX defaults -// \DeclareRobustCommand{\tmspace}[3]{% -// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} -defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); -// \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\,", "\\tmspace+{3mu}{.1667em}"); -// \let\thinspace\, -defineMacro("\\thinspace", "\\,"); -// \def\>{\mskip\medmuskip} -// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} -// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\>", "\\mskip{4mu}"); -defineMacro("\\:", "\\tmspace+{4mu}{.2222em}"); -// \let\medspace\: -defineMacro("\\medspace", "\\:"); -// \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip = 5mu plus 5mu -defineMacro("\\;", "\\tmspace+{5mu}{.2777em}"); -// \let\thickspace\; -defineMacro("\\thickspace", "\\;"); -// \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\!", "\\tmspace-{3mu}{.1667em}"); -// \let\negthinspace\! -defineMacro("\\negthinspace", "\\!"); -// \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} -// TODO: math mode should use \medmuskip -defineMacro("\\negmedspace", "\\tmspace-{4mu}{.2222em}"); -// \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip -defineMacro("\\negthickspace", "\\tmspace-{5mu}{.277em}"); -// \def\enspace{\kern.5em } -defineMacro("\\enspace", "\\kern.5em "); -// \def\enskip{\hskip.5em\relax} -defineMacro("\\enskip", "\\hskip.5em\\relax"); -// \def\quad{\hskip1em\relax} -defineMacro("\\quad", "\\hskip1em\\relax"); -// \def\qquad{\hskip2em\relax} -defineMacro("\\qquad", "\\hskip2em\\relax"); - -// \tag@in@display form of \tag -defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); -defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); -defineMacro("\\tag@literal", (context) => { - if (context.macros.get("\\df@tag")) { - throw new ParseError("Multiple \\tag"); - } - return "\\def\\df@tag{\\text{#1}}"; -}); - -// \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin -// {\operator@font mod}\penalty900 -// \mkern5mu\nonscript\mskip-\medmuskip} -// \newcommand{\pod}[1]{\allowbreak -// \if@display\mkern18mu\else\mkern8mu\fi(#1)} -// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} -// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu -// \else\mkern12mu\fi{\operator@font mod}\,\,#1} -// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\bmod", "\\mathbin{\\text{mod}}"); -defineMacro( - "\\pod", - "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)" -); -defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); -defineMacro( - "\\mod", - "\\allowbreak" + - "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + - "{\\rm mod}\\,\\,#1" -); - -////////////////////////////////////////////////////////////////////// -// LaTeX source2e - -// \expandafter\let\expandafter\@normalcr -// \csname\expandafter\@gobble\string\\ \endcsname -// \DeclareRobustCommand\newline{\@normalcr\relax} -defineMacro("\\newline", "\\\\\\relax"); - -// \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} -// TODO: Doesn't normally work in math mode because \@ fails. -defineMacro("\\TeX", "\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"); - -defineMacro( - "\\LaTeX", - "\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX" -); - -defineMacro( - "\\Temml", - // eslint-disable-next-line max-len - "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}" -); - -// \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} -// \def\@hspace#1{\hskip #1\relax} -// \def\@hspacer#1{\vrule \@width\z@\nobreak -// \hskip #1\hskip \z@skip} -defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); -defineMacro("\\@hspace", "\\hskip #1\\relax"); -defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); - -////////////////////////////////////////////////////////////////////// -// mathtools.sty - -defineMacro("\\prescript", "\\pres@cript{_{#1}^{#2}}{}{#3}"); - -//\providecommand\ordinarycolon{:} -defineMacro("\\ordinarycolon", ":"); -//\def\vcentcolon{\mathrel{\mathop\ordinarycolon}} -//TODO(edemaine): Not yet centered. Fix via \raisebox or #726 -defineMacro("\\vcentcolon", "\\mathrel{\\mathrel\\ordinarycolon}"); -// \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\coloneq", '\\mathrel{\\char"3a\\char"2212}'); -// \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\Coloneq", '\\mathrel{\\char"2237\\char"2212}'); -// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqqcolon", '\\mathrel{\\char"3d\\char"2237}'); -// \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqcolon", '\\mathrel{\\char"2212\\char"2237}'); -// \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\colonapprox", '\\mathrel{\\char"3a\\char"2248}'); -// \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\Colonapprox", '\\mathrel{\\char"2237\\char"2248}'); -// \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\colonsim", '\\mathrel{\\char"3a\\char"223c}'); -// \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\Colonsim", '\\mathrel{\\char"2237\\char"223c}'); - -////////////////////////////////////////////////////////////////////// -// colonequals.sty - -// Alternate names for mathtools's macros: -defineMacro("\\ratio", "\\vcentcolon"); -defineMacro("\\coloncolon", "\\dblcolon"); -defineMacro("\\colonequals", "\\coloneqq"); -defineMacro("\\coloncolonequals", "\\Coloneqq"); -defineMacro("\\equalscolon", "\\eqqcolon"); -defineMacro("\\equalscoloncolon", "\\Eqqcolon"); -defineMacro("\\colonminus", "\\coloneq"); -defineMacro("\\coloncolonminus", "\\Coloneq"); -defineMacro("\\minuscolon", "\\eqcolon"); -defineMacro("\\minuscoloncolon", "\\Eqcolon"); -// \colonapprox name is same in mathtools and colonequals. -defineMacro("\\coloncolonapprox", "\\Colonapprox"); -// \colonsim name is same in mathtools and colonequals. -defineMacro("\\coloncolonsim", "\\Colonsim"); - -// Present in newtxmath, pxfonts and txfonts -defineMacro("\\notni", "\\mathrel{\\char`\u220C}"); -defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); -defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); - -////////////////////////////////////////////////////////////////////// -// From amsopn.sty -defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}"); -defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}"); -defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"); -defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"); -defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"); -defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"); - - -////////////////////////////////////////////////////////////////////// -// statmath.sty -// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf - -defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); -defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); -defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}"); - -////////////////////////////////////////////////////////////////////// -// braket.sty -// http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf - -defineMacro("\\bra", "\\mathinner{\\langle{#1}|}"); -defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}"); -defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}"); -defineMacro("\\Bra", "\\left\\langle#1\\right|"); -defineMacro("\\Ket", "\\left|#1\\right\\rangle"); -const braketHelper = (one) => (context) => { - const left = context.consumeArg().tokens; - const middle = context.consumeArg().tokens; - const middleDouble = context.consumeArg().tokens; - const right = context.consumeArg().tokens; - const oldMiddle = context.macros.get("|"); - const oldMiddleDouble = context.macros.get("\\|"); - context.macros.beginGroup(); - const midMacro = (double) => (context) => { - if (one) { - // Only modify the first instance of | or \| - context.macros.set("|", oldMiddle); - if (middleDouble.length) { - context.macros.set("\\|", oldMiddleDouble); - } - } - let doubled = double; - if (!double && middleDouble.length) { - // Mimic \@ifnextchar - const nextToken = context.future(); - if (nextToken.text === "|") { - context.popToken(); - doubled = true; - } - } - return { - tokens: doubled ? middleDouble : middle, - numArgs: 0 - }; - }; - context.macros.set("|", midMacro(false)); - if (middleDouble.length) { - context.macros.set("\\|", midMacro(true)); - } - const arg = context.consumeArg().tokens; - const expanded = context.expandTokens([...right, ...arg, ...left]); // reversed - context.macros.endGroup(); - return { - tokens: expanded.reverse(), - numArgs: 0 - }; -}; -defineMacro("\\bra@ket", braketHelper(false)); -defineMacro("\\bra@set", braketHelper(true)); -defineMacro("\\Braket", "\\bra@ket{\\left\\langle}" + - "{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"); -defineMacro("\\Set", "\\bra@set{\\left\\{\\:}" + - "{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"); -defineMacro("\\set", "\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"); - // has no support for special || or \| - -////////////////////////////////////////////////////////////////////// -// actuarialangle.dtx -defineMacro("\\angln", "{\\angl n}"); - -////////////////////////////////////////////////////////////////////// -// derivative.sty -defineMacro("\\odv", "\\@ifstar\\odv@next\\odv@numerator"); -defineMacro("\\odv@numerator", "\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}"); -defineMacro("\\odv@next", "\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1"); -defineMacro("\\pdv", "\\@ifstar\\pdv@next\\pdv@numerator"); - -const pdvHelper = args => { - const numerator = args[0][0].text; - const denoms = stringFromArg(args[1]).split(","); - const power = String(denoms.length); - const numOp = power === "1" ? "\\partial" : `\\partial^${power}`; - let denominator = ""; - denoms.map(e => { denominator += "\\partial " + e.trim() + "\\,";}); - return [numerator, numOp, denominator.replace(/\\,$/, "")] -}; -defineMacro("\\pdv@numerator", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp} ${numerator}}{${denominator}}` -}); -defineMacro("\\pdv@next", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp}}{${denominator}} ${numerator}` -}); - -////////////////////////////////////////////////////////////////////// -// upgreek.dtx -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\upbeta", "\\up@greek{\\beta}"); -defineMacro("\\upgamma", "\\up@greek{\\gamma}"); -defineMacro("\\updelta", "\\up@greek{\\delta}"); -defineMacro("\\upepsilon", "\\up@greek{\\epsilon}"); -defineMacro("\\upzeta", "\\up@greek{\\zeta}"); -defineMacro("\\upeta", "\\up@greek{\\eta}"); -defineMacro("\\uptheta", "\\up@greek{\\theta}"); -defineMacro("\\upiota", "\\up@greek{\\iota}"); -defineMacro("\\upkappa", "\\up@greek{\\kappa}"); -defineMacro("\\uplambda", "\\up@greek{\\lambda}"); -defineMacro("\\upmu", "\\up@greek{\\mu}"); -defineMacro("\\upnu", "\\up@greek{\\nu}"); -defineMacro("\\upxi", "\\up@greek{\\xi}"); -defineMacro("\\upomicron", "\\up@greek{\\omicron}"); -defineMacro("\\uppi", "\\up@greek{\\pi}"); -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\uprho", "\\up@greek{\\rho}"); -defineMacro("\\upsigma", "\\up@greek{\\sigma}"); -defineMacro("\\uptau", "\\up@greek{\\tau}"); -defineMacro("\\upupsilon", "\\up@greek{\\upsilon}"); -defineMacro("\\upphi", "\\up@greek{\\phi}"); -defineMacro("\\upchi", "\\up@greek{\\chi}"); -defineMacro("\\uppsi", "\\up@greek{\\psi}"); -defineMacro("\\upomega", "\\up@greek{\\omega}"); - -////////////////////////////////////////////////////////////////////// -// chemstyle package -defineMacro("\\standardstate", "{\\tiny\\char`⦵}"); - -/* eslint-disable */ -/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ - -/************************************************************* - * - * Temml mhchem.js - * - * This file implements a Temml version of mhchem version 3.3.0. - * It is adapted from MathJax/extensions/TeX/mhchem.js - * It differs from the MathJax version as follows: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. - * 3. The reaction arrow code is simplified. All reaction arrows are rendered - * using Temml extensible arrows instead of building non-extensible arrows. - * 4. SVG path geometry is supplied for \equilibriumRight & \equilibriumLeft. - * 5. \tripledash uses Unicode character U+2504, ┄. - * 6. Two dashes in _getBond are wrapped in braces to suppress spacing. i.e., {-} - * 7. The electron dot uses \textbullet instead of \bullet. - * - * This code, as other Temml code, is released under the MIT license. - * - * /************************************************************* - * - * MathJax/extensions/TeX/mhchem.js - * - * Implements the \ce command for handling chemical formulas - * from the mhchem LaTeX package. - * - * --------------------------------------------------------------------- - * - * Copyright (c) 2011-2015 The MathJax Consortium - * Copyright (c) 2015-2018 Martin Hensel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Coding Style -// - use '' for identifiers that can by minified/uglified -// - use "" for strings that need to stay untouched - -// version: "3.3.0" for MathJax and Temml - - -// Add \ce, \pu, and \tripledash to the Temml macros. - -defineMacro("\\ce", function(context) { - return chemParse(context.consumeArgs(1)[0], "ce") -}); - -defineMacro("\\pu", function(context) { - return chemParse(context.consumeArgs(1)[0], "pu"); -}); - -// Needed for \bond for the ~ forms -// Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not -// a mathematical minus, U+2212. So we need that extra 0.56. -defineMacro("\\tripledash", '\\mathord{\\kern2mu\\raise{0.5mu}{\\char"2504}\\kern2mu}'); - -// Use the Temml macro system to send SVG path geometry for equilibrium arrows. -defineMacro("longRightleftharpoonsLeft", `M507,435c-4,4,-6.3,8.7,-7,14 -c0,5.3,0.7,9,2,11c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 -c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 -c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 -c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z -M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`) -defineMacro("longRightleftharpoonsRight", `M0,241 l0,40c399126,0,399993,0,399993,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`) -defineMacro("longLeftrightharpoonsLeft", `M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 -c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, -1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, --152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z -M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`) -defineMacro("longLeftrightharpoonsRight", `M53,241l0,40c398570,0,399437,0,399437,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`) - - -const path = { - "\\equilibriumRight" : { - left: `M507,435c-4,4,-6.3,8.7,-7,14 -c0,5.3,0.7,9,2,11c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 -c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 -c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 -c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z -M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`, - right: `M0,241 l0,40c399126,0,399993,0,399993,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z` - }, - "\\equilibriumLeft": { - left: `M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 -c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, -1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, --152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z -M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`, - right: `M53,241l0,40c398570,0,399437,0,399437,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z` - } -} - -const svg = (name, end) => { - const svg = { - type: "svg", - attributes: { - xmlns: "http://www.w3.org/2000/svg", - width: "400em", - height: "0.716em", - viewBox: "0 0 400000 716", - preserveAspectRatio: `x${end === "left" ? "Min" : "Max"}yMin slice`, - fill: "currrentColor", - "fill-rule": "non-zero", - "fill-opacity" : 1 - }, - style: { position: "absolute" }, - children: [{ - type: "path", - attributes: { d: path[name][end], stroke: "none" }, - children: [] - }] - } - if (end === "left") { svg.style.left = 0 } else { svg.style.right = 0 } - return svg -} - -const endSpan = (name, end) => { - const span = { - type: "span", - attributes: {}, - style: { position: "absolute", width: "50.2%", height: "0.716em", overflow: "hidden" }, - children: [svg(name, end)] - } - if (end === "left") { span.style.left = 0 } else { span.style.right = 0 } - return span -} - -const arrowNode = name => { - return JSON.stringify({ - type: "span", - attributes: {}, - style: { display: "block", position: "relative", width: "100%", height: "0.716em", "min-width": "1.75em" }, - children: [endSpan(name, "left"), endSpan(name, "right")] - }) -} - -defineMacro("\\@equilibriumRight", arrowNode("\\equilibriumRight")) -defineMacro("\\@equilibriumLeft", arrowNode("\\equilibriumLeft")) - - // - // This is the main function for handing the \ce and \pu commands. - // It takes the argument to \ce or \pu and returns the corresponding TeX string. - // - - var chemParse = function (tokens, stateMachine) { - // Recreate the argument string from Temml's array of tokens. - var str = ""; - var expectedLoc = tokens[tokens.length - 1].loc.start - for (var i = tokens.length - 1; i >= 0; i--) { - if(tokens[i].loc.start > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = tokens[i].loc.start; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - // Call the mhchem core parser. - var tex = texify.go(mhchemParser.go(str, stateMachine)); - return tex; - }; - - // - // Core parser for mhchem syntax (recursive) - // - /** @type {MhchemParser} */ - var mhchemParser = { - // - // Parses mchem \ce syntax - // - // Call like - // go("H2O"); - // - go: function (input, stateMachine) { - if (!input) { return []; } - if (stateMachine === undefined) { stateMachine = 'ce'; } - var state = '0'; - - // - // String buffers for parsing: - // - // buffer.a == amount - // buffer.o == element - // buffer.b == left-side superscript - // buffer.p == left-side subscript - // buffer.q == right-side subscript - // buffer.d == right-side superscript - // - // buffer.r == arrow - // buffer.rdt == arrow, script above, type - // buffer.rd == arrow, script above, content - // buffer.rqt == arrow, script below, type - // buffer.rq == arrow, script below, content - // - // buffer.text_ - // buffer.rm - // etc. - // - // buffer.parenthesisLevel == int, starting at 0 - // buffer.sb == bool, space before - // buffer.beginsWithBond == bool - // - // These letters are also used as state names. - // - // Other states: - // 0 == begin of main part (arrow/operator unlikely) - // 1 == next entity - // 2 == next entity (arrow/operator unlikely) - // 3 == next atom - // c == macro - // - /** @type {Buffer} */ - var buffer = {}; - buffer['parenthesisLevel'] = 0; - - input = input.replace(/\n/g, " "); - input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); - input = input.replace(/[\u2026]/g, "..."); - - // - // Looks through mhchemParser.transitions, to execute a matching action - // (recursive) - // - var lastInput; - var watchdog = 10; - /** @type {ParserOutput[]} */ - var output = []; - while (true) { - if (lastInput !== input) { - watchdog = 10; - lastInput = input; - } else { - watchdog--; - } - // - // Find actions in transition table - // - var machine = mhchemParser.stateMachines[stateMachine]; - var t = machine.transitions[state] || machine.transitions['*']; - iterateTransitions: - for (var i=0; i 0) { - if (!task.revisit) { - input = matches.remainder; - } - if (!task.toContinue) { - break iterateTransitions; - } - } else { - return output; - } - } - } - // - // Prevent infinite loop - // - if (watchdog <= 0) { - throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character - } - } - }, - concatArray: function (a, b) { - if (b) { - if (Array.isArray(b)) { - for (var iB=0; iB': /^[=<>]/, - '#': /^[#\u2261]/, - '+': /^\+/, - '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation - '-9': /^-(?=[0-9])/, - '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, - '-': /^-/, - 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, - 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, - 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, - '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, - '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, - 'CMT': /^[CMT](?=\[)/, - '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, - '1st-level escape': /^(&|\\\\|\\hline)\s*/, - '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before - '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, - '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, - '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, - '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, - 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway - 'others': /^[\/~|]/, - '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, - '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, - '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, - '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, - '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, - '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); }, - '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, - '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, - 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, - 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge - 'roman numeral': /^[IVX]+/, - '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, - 'amount': function (input) { - var match; - // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing - match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); - if (a) { // e.g. $2n-1$, $-$ - match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - } - return null; - }, - 'amount2': function (input) { return this['amount'](input); }, - '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, - 'formula$': function (input) { - if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula - var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - return null; - }, - 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, - '/': /^\s*(\/)\s*/, - '//': /^\s*(\/\/)\s*/, - '*': /^\s*[*.]\s*/ - }, - findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { - /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ - var _match = function (input, pattern) { - if (typeof pattern === "string") { - if (input.indexOf(pattern) !== 0) { return null; } - return pattern; - } else { - var match = input.match(pattern); - if (!match) { return null; } - return match[0]; - } - }; - /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ - var _findObserveGroups = function (input, i, endChars) { - var braces = 0; - while (i < input.length) { - var a = input.charAt(i); - var match = _match(input.substr(i), endChars); - if (match !== null && braces === 0) { - return { endMatchBegin: i, endMatchEnd: i + match.length }; - } else if (a === "{") { - braces++; - } else if (a === "}") { - if (braces === 0) { - throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; - } else { - braces--; - } - } - i++; - } - if (braces > 0) { - return null; - } - return null; - }; - var match = _match(input, begExcl); - if (match === null) { return null; } - input = input.substr(match.length); - match = _match(input, begIncl); - if (match === null) { return null; } - var e = _findObserveGroups(input, match.length, endIncl || endExcl); - if (e === null) { return null; } - var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); - if (!(beg2Excl || beg2Incl)) { - return { - match_: match1, - remainder: input.substr(e.endMatchEnd) - }; - } else { - var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); - if (group2 === null) { return null; } - /** @type {string[]} */ - var matchRet = [match1, group2.match_]; - return { - match_: (combine ? matchRet.join("") : matchRet), - remainder: group2.remainder - }; - } - }, - - // - // Matching function - // e.g. match("a", input) will look for the regexp called "a" and see if it matches - // returns null or {match_:"a", remainder:"bc"} - // - match_: function (m, input) { - var pattern = mhchemParser.patterns.patterns[m]; - if (pattern === undefined) { - throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern - } else if (typeof pattern === "function") { - return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser - } else { // RegExp - var match = input.match(pattern); - if (match) { - var mm; - if (match[2]) { - mm = [ match[1], match[2] ]; - } else if (match[1]) { - mm = match[1]; - } else { - mm = match[0]; - } - return { match_: mm, remainder: input.substr(match[0].length) }; - } - return null; - } - } - }, - - // - // Generic state machine actions - // - actions: { - 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; }, - 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; }, - 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; }, - 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; }, - 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; }, - 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; }, - 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; }, - 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; }, - 'insert': function (buffer, m, a) { return { type_: a }; }, - 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; }, - 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, - 'copy': function (buffer, m) { return m; }, - 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; }, - 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); }, - '{text}': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); - ret.push("}"); - return ret; - }, - 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); }, - 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); }, - 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, - 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; }, - 'ce': function (buffer, m) { return mhchemParser.go(m); }, - '1/2': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m.match(/^[+\-]/)) { - ret.push(m.substr(0, 1)); - m = m.substr(1); - } - var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); - n[1] = n[1].replace(/\$/g, ""); - ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); - if (n[3]) { - n[3] = n[3].replace(/\$/g, ""); - ret.push({ type_: 'tex-math', p1: n[3] }); - } - return ret; - }, - '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); } - }, - // - // createTransitions - // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } - // with expansion of 'a|b' to 'a' and 'b' (at 2 places) - // - createTransitions: function (o) { - var pattern, state; - /** @type {string[]} */ - var stateArray; - var i; - // - // 1. Collect all states - // - /** @type {Transitions} */ - var transitions = {}; - for (pattern in o) { - for (state in o[pattern]) { - stateArray = state.split("|"); - o[pattern][state].stateArray = stateArray; - for (i=0; i': { - '0|1|2|3': { action_: 'r=', nextState: 'r' }, - 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' }, - '*': { action_: [ 'output', 'r=' ], nextState: 'r' } }, - '+': { - 'o': { action_: 'd= kv', nextState: 'd' }, - 'd|D': { action_: 'd=', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd|qD': { action_: 'd=', nextState: 'qd' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' }, - '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - 'amount': { - '0|2': { action_: 'a=', nextState: 'a' } }, - 'pm-operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } }, - 'operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - '-$': { - 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' }, - 'd': { action_: 'd=', nextState: 'd' }, - 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd': { action_: 'd=', nextState: 'qd' }, - 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - '-9': { - '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } }, - '- orbital overlap': { - 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } }, - '-': { - '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' }, - '3': { action_: { type_: 'bond', option: "-" } }, - 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' }, - 'b': { action_: 'b=' }, - 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, - 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - 'amount2': { - '1|3': { action_: 'a=', nextState: 'a' } }, - 'letters': { - '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, - 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, - 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, - 'digits': { - 'o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q': { action_: [ 'output', 'o=' ], nextState: 'o' }, - 'a': { action_: 'o=', nextState: 'o' } }, - 'space A': { - 'b|p|bp': {} }, - 'space': { - 'a': { nextState: 'as' }, - '0': { action_: 'sb=false' }, - '1|2': { action_: 'sb=true' }, - 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, - '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} }, - '1st-level escape': { - '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] }, - '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } }, - '[(...)]': { - 'r|rt': { action_: 'rd=', nextState: 'rd' }, - 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, - '...': { - 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' }, - '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } }, - '. |* ': { - '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } }, - 'state of aggregation $': { - '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } }, - '{[(': { - 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } }, - ')]}': { - '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' }, - 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } }, - ', ': { - '*': { action_: [ 'output', 'comma' ], nextState: '0' } }, - '^_': { // ^ and _ without a sensible argument - '*': { } }, - '^{(...)}|^($...$)': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'D' }, - 'q': { action_: 'd=', nextState: 'qD' }, - 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } }, - '^a|^\\x{}{}|^\\x{}|^\\x|\'': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'd|qd|D|qD': { action_: 'd=' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } }, - '_{(state of aggregation)}$': { - 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { - '0|1|2|as': { action_: 'p=', nextState: 'p' }, - 'b': { action_: 'p=', nextState: 'bp' }, - '3|o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '=<>': { - '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } }, - '#': { - '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } }, - '{}': { - '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, - '{...}': { - '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, - 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '$...$': { - 'a': { action_: 'a=' }, // 2$n$ - '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount' - 'as|o': { action_: 'o=' }, - 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '\\bond{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } }, - '\\frac{(...)}': { - '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } }, - '\\overset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } }, - '\\underset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } }, - '\\underbrace{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } }, - '\\color{(...)}0': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } }, - '\\ce{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } }, - '\\,': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } }, - '\\x{}{}|\\x{}|\\x': { - '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' }, - '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } }, - 'others': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } }, - 'else2': { - 'a': { action_: 'a to o', nextState: 'o', revisit: true }, - 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true }, - 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true }, - '*': { action_: [ 'output', 'copy' ], nextState: '3' } } - }), - actions: { - 'o after d': function (buffer, m) { - var ret; - if ((buffer.d || "").match(/^[0-9]+$/)) { - var tmp = buffer.d; - buffer.d = undefined; - ret = this['output'](buffer); - buffer.b = tmp; - } else { - ret = this['output'](buffer); - } - mhchemParser.actions['o='](buffer, m); - return ret; - }, - 'd= kv': function (buffer, m) { - buffer.d = m; - buffer.dType = 'kv'; - }, - 'charge or bond': function (buffer, m) { - if (buffer['beginsWithBond']) { - /** @type {ParserOutput[]} */ - var ret = []; - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - return ret; - } else { - buffer.d = m; - } - }, - '- after o/d': function (buffer, m, isAfterD) { - var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); - var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); - var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); - var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); - var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 ); - if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { - buffer.o = '$' + buffer.o + '$'; - } - /** @type {ParserOutput[]} */ - var ret = []; - if (hyphenFollows) { - mhchemParser.concatArray(ret, this['output'](buffer)); - ret.push({ type_: 'hyphen' }); - } else { - c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); - if (isAfterD && c1 && c1.remainder==='') { - mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); - mhchemParser.concatArray(ret, this['output'](buffer)); - } else { - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - } - } - return ret; - }, - 'a to o': function (buffer) { - buffer.o = buffer.a; - buffer.a = undefined; - }, - 'sb=true': function (buffer) { buffer.sb = true; }, - 'sb=false': function (buffer) { buffer.sb = false; }, - 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; }, - 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; }, - 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; }, - 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; }, - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') }; - }, - 'comma': function (buffer, m) { - var a = m.replace(/\s*$/, ''); - var withSpace = (a !== m); - if (withSpace && buffer['parenthesisLevel'] === 0) { - return { type_: 'comma enumeration L', p1: a }; - } else { - return { type_: 'comma enumeration M', p1: a }; - } - }, - 'output': function (buffer, m, entityFollows) { - // entityFollows: - // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) - // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) - // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - if (!buffer.r) { - ret = []; - if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { - //ret = []; - } else { - if (buffer.sb) { - ret.push({ type_: 'entitySkip' }); - } - if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) { - buffer.o = buffer.a; - buffer.a = undefined; - } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { - buffer.o = buffer.a; - buffer.d = buffer.b; - buffer.q = buffer.p; - buffer.a = buffer.b = buffer.p = undefined; - } else { - if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { - buffer.dType = 'oxidation'; - } else if (buffer.o && buffer.dType==='kv' && !buffer.q) { - buffer.dType = undefined; - } - } - ret.push({ - type_: 'chemfive', - a: mhchemParser.go(buffer.a, 'a'), - b: mhchemParser.go(buffer.b, 'bd'), - p: mhchemParser.go(buffer.p, 'pq'), - o: mhchemParser.go(buffer.o, 'o'), - q: mhchemParser.go(buffer.q, 'pq'), - d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), - dType: buffer.dType - }); - } - } else { // r - /** @type {ParserOutput[]} */ - var rd; - if (buffer.rdt === 'M') { - rd = mhchemParser.go(buffer.rd, 'tex-math'); - } else if (buffer.rdt === 'T') { - rd = [ { type_: 'text', p1: buffer.rd || "" } ]; - } else { - rd = mhchemParser.go(buffer.rd); - } - /** @type {ParserOutput[]} */ - var rq; - if (buffer.rqt === 'M') { - rq = mhchemParser.go(buffer.rq, 'tex-math'); - } else if (buffer.rqt === 'T') { - rq = [ { type_: 'text', p1: buffer.rq || ""} ]; - } else { - rq = mhchemParser.go(buffer.rq); - } - ret = { - type_: 'arrow', - r: buffer.r, - rd: rd, - rq: rq - }; - } - for (var p in buffer) { - if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { - delete buffer[p]; - } - } - return ret; - }, - 'oxidation-output': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); - ret.push("}"); - return ret; - }, - 'frac-output': function (buffer, m) { - return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'overset-output': function (buffer, m) { - return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underset-output': function (buffer, m) { - return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underbrace-output': function (buffer, m) { - return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) }; - }, - 'r=': function (buffer, m) { buffer.r = m; }, - 'rdt=': function (buffer, m) { buffer.rdt = m; }, - 'rd=': function (buffer, m) { buffer.rd = m; }, - 'rqt=': function (buffer, m) { buffer.rqt = m; }, - 'rq=': function (buffer, m) { buffer.rq = m; }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } - } - }, - 'a': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - '$(...)$': { - '*': { action_: 'tex-math tight', nextState: '1' } }, - ',': { - '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'o': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - 'letters': { - '*': { action_: 'rm' } }, - '\\ca': { - '*': { action_: { type_: 'insert', option: 'circa' } } }, - '\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: '{text}' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'text': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '{...}': { - '*': { action_: 'text=' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '\\greek': { - '*': { action_: [ 'output', 'rm' ] } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: [ 'output', 'copy' ] } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.text_) { - /** @type {ParserOutput} */ - var ret = { type_: 'text', p1: buffer.text_ }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'pq': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'state of aggregation $': { - '*': { action_: 'state of aggregation' } }, - 'i$': { - '0': { nextState: '!f', revisit: true } }, - '(KV letters),': { - '0': { action_: 'rm', nextState: '0' } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'letters': { - '*': { action_: 'rm' } }, - '-9.,9': { - '*': { action_: '9,9' } }, - ',': { - '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') }; - } - } - }, - 'bd': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'x$': { - '0': { nextState: '!f', revisit: true } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '-9.,9 no missing 0': { - '*': { action_: '9,9' } }, - '.': { - '*': { action_: { type_: 'insert', option: 'electron dot' } } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'x': { - '*': { action_: { type_: 'insert', option: 'KV x' } } }, - 'letters': { - '*': { action_: 'rm' } }, - '\'': { - '*': { action_: { type_: 'insert', option: 'prime' } } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') }; - } - } - }, - 'oxidation': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'roman numeral': { - '*': { action_: 'roman-numeral' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; } - } - }, - 'tex-math': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'tex-math tight': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - '-|+': { - '*': { action_: 'tight operator' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; }, - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - '9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - ',': { - '*': { action_: 'comma' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; } - } - }, - //#endregion - // - // \pu state machines - // - //#region pu - 'pu': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - 'space$': { - '*': { action_: [ 'output', 'space' ] } }, - '{[(|)]}': { - '0|a': { action_: 'copy' } }, - '(-)(9)^(-9)': { - '0': { action_: 'number^', nextState: 'a' } }, - '(-)(9.,9)(e)(99)': { - '0': { action_: 'enumber', nextState: 'a' } }, - 'space': { - '0|a': {} }, - 'pm-operator': { - '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } }, - 'operator': { - '0|a': { action_: 'copy', nextState: '0' } }, - '//': { - 'd': { action_: 'o=', nextState: '/' } }, - '/': { - 'd': { action_: 'o=', nextState: '/' } }, - '{...}|else': { - '0|d': { action_: 'd=', nextState: 'd' }, - 'a': { action_: [ 'space', 'd=' ], nextState: 'd' }, - '/|q': { action_: 'q=', nextState: 'q' } } - }), - actions: { - 'enumber': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - if (m[1]) { - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - if (m[2]) { - if (m[2].match(/[,.]/)) { - mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); - } else { - ret.push(m[2]); - } - } - m[3] = m[4] || m[3]; - if (m[3]) { - m[3] = m[3].trim(); - if (m[3] === "e" || m[3].substr(0, 1) === "*") { - ret.push({ type_: 'cdot' }); - } else { - ret.push({ type_: 'times' }); - } - } - } - if (m[3]) { - ret.push("10^{"+m[5]+"}"); - } - return ret; - }, - 'number^': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - ret.push("^{"+m[2]+"}"); - return ret; - }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }, - 'space': function () { return { type_: 'pu-space-1' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); - if (md && md.remainder === '') { buffer.d = md.match_; } - var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); - if (mq && mq.remainder === '') { buffer.q = mq.match_; } - if (buffer.d) { - buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - } - if (buffer.q) { // fraction - buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - var b5 = { - d: mhchemParser.go(buffer.d, 'pu'), - q: mhchemParser.go(buffer.q, 'pu') - }; - if (buffer.o === '//') { - ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q }; - } else { - ret = b5.d; - if (b5.d.length > 1 || b5.q.length > 1) { - ret.push({ type_: ' / ' }); - } else { - ret.push({ type_: '/' }); - } - mhchemParser.concatArray(ret, b5.q); - } - } else { // no fraction - ret = mhchemParser.go(buffer.d, 'pu-2'); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-2': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '*': { - '*': { action_: [ 'output', 'cdot' ], nextState: '0' } }, - '\\x': { - '*': { action_: 'rm=' } }, - 'space': { - '*': { action_: [ 'output', 'space' ], nextState: '0' } }, - '^{(...)}|^(-1)': { - '1': { action_: '^(-1)' } }, - '-9.,9': { - '0': { action_: 'rm=', nextState: '0' }, - '1': { action_: '^(-1)', nextState: '0' } }, - '{...}|else': { - '*': { action_: 'rm=', nextState: '1' } } - }), - actions: { - 'cdot': function () { return { type_: 'tight cdot' }; }, - '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; }, - 'space': function () { return { type_: 'pu-space-2' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret = []; - if (buffer.rm) { - var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); - if (mrm && mrm.remainder === '') { - ret = mhchemParser.go(mrm.match_, 'pu'); - } else { - ret = { type_: 'rm', p1: buffer.rm }; - } - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '0': { action_: 'output-0' }, - 'o': { action_: 'output-o' } }, - ',': { - '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } }, - '.': { - '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; }, - 'output-0': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length % 3; - if (a === 0) { a = 3; } - for (var i=buffer.text_.length-3; i>0; i-=3) { - ret.push(buffer.text_.substr(i, 3)); - ret.push({ type_: '1000 separator' }); - } - ret.push(buffer.text_.substr(0, a)); - ret.reverse(); - } else { - ret.push(buffer.text_); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - }, - 'output-o': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length - 3; - for (var i=0; i, so we change \vphantom{X} to {} - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - } else { - if (b5.q) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - if (b5.d) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "^{"+b5.d+"}"; - } - } - break; - case 'rm': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'text': - if (buf.p1.match(/[\^_]/)) { - buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}"); - res = "\\mathrm{"+buf.p1+"}"; - } else { - res = "\\text{"+buf.p1+"}"; - } - break; - case 'roman numeral': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'state of aggregation': - res = "\\mskip2mu "+texify._goInner(buf.p1); - break; - case 'state of aggregation subscript': - res = "\\mskip1mu "+texify._goInner(buf.p1); - break; - case 'bond': - res = texify._getBond(buf.kind_); - if (!res) { - throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"]; - } - break; - case 'frac': - var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}"; - res = "\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}"; - break; - case 'pu-frac': - var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - res = "\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}"; - break; - case 'tex-math': - res = buf.p1 + " "; - break; - case 'frac-ce': - res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'overset': - res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underset': - res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underbrace': - res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}"; - break; - case 'color': - res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}"; - break; - case 'color0': - res = "\\color{" + buf.color + "}"; - break; - case 'arrow': - var b6 = { - rd: texify._goInner(buf.rd), - rq: texify._goInner(buf.rq) - }; - var arrow = texify._getArrow(buf.r); - if (b6.rq) { arrow += "[{\\rm " + b6.rq + "}]"; } - if (b6.rd) { - arrow += "{\\rm " + b6.rd + "}"; - } else { - arrow += "{}"; - } - res = arrow; - break; - case 'operator': - res = texify._getOperator(buf.kind_); - break; - case '1st-level escape': - res = buf.p1+" "; // &, \\\\, \\hlin - break; - case 'space': - res = " "; - break; - case 'entitySkip': - res = "~"; - break; - case 'pu-space-1': - res = "~"; - break; - case 'pu-space-2': - res = "\\mkern3mu "; - break; - case '1000 separator': - res = "\\mkern2mu "; - break; - case 'commaDecimal': - res = "{,}"; - break; - case 'comma enumeration L': - res = "{"+buf.p1+"}\\mkern6mu "; - break; - case 'comma enumeration M': - res = "{"+buf.p1+"}\\mkern3mu "; - break; - case 'comma enumeration S': - res = "{"+buf.p1+"}\\mkern1mu "; - break; - case 'hyphen': - res = "\\text{-}"; - break; - case 'addition compound': - res = "\\,{\\cdot}\\,"; - break; - case 'electron dot': - res = "\\mkern1mu \\text{\\textbullet}\\mkern1mu "; - break; - case 'KV x': - res = "{\\times}"; - break; - case 'prime': - res = "\\prime "; - break; - case 'cdot': - res = "\\cdot "; - break; - case 'tight cdot': - res = "\\mkern1mu{\\cdot}\\mkern1mu "; - break; - case 'times': - res = "\\times "; - break; - case 'circa': - res = "{\\sim}"; - break; - case '^': - res = "uparrow"; - break; - case 'v': - res = "downarrow"; - break; - case 'ellipsis': - res = "\\ldots "; - break; - case '/': - res = "/"; - break; - case ' / ': - res = "\\,/\\,"; - break; - default: - assertNever(buf); - throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output - } - assertString(res); - return res; - }, - _getArrow: function (a) { - switch (a) { - case "->": return "\\yields"; - case "\u2192": return "\\yields"; - case "\u27F6": return "\\yields"; - case "<-": return "\\yieldsLeft"; - case "<->": return "\\mesomerism"; - case "<-->": return "\\yieldsLeftRight"; - case "<=>": return "\\equilibrium"; - case "\u21CC": return "\\equilibrium"; - case "<=>>": return "\\equilibriumRight"; - case "<<=>": return "\\equilibriumLeft"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getBond: function (a) { - switch (a) { - case "-": return "{-}"; - case "1": return "{-}"; - case "=": return "{=}"; - case "2": return "{=}"; - case "#": return "{\\equiv}"; - case "3": return "{\\equiv}"; - case "~": return "{\\tripledash}"; - case "~-": return "{\\mathrlap{\\raise{-.1em}{-}}\\raise{.1em}{\\tripledash}}"; - case "~=": return "{\\mathrlap{\\raise{-.2em}{-}}\\mathrlap{\\raise{.2em}{\\tripledash}}{-}}"; - case "~--": return "{\\mathrlap{\\raise{-.2em}{-}}\\mathrlap{\\raise{.2em}{\\tripledash}}{-}}"; - case "-~-": return "{\\mathrlap{\\raise{-.2em}{-}}\\mathrlap{\\raise{.2em}{-}}\\tripledash}"; - case "...": return "{{\\cdot}{\\cdot}{\\cdot}}"; - case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; - case "->": return "{\\rightarrow}"; - case "<-": return "{\\leftarrow}"; - case "<": return "{<}"; - case ">": return "{>}"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getOperator: function (a) { - switch (a) { - case "+": return " {}+{} "; - case "-": return " {}-{} "; - case "=": return " {}={} "; - case "<": return " {}<{} "; - case ">": return " {}>{} "; - case "<<": return " {}\\ll{} "; - case ">>": return " {}\\gg{} "; - case "\\pm": return " {}\\pm{} "; - case "\\approx": return " {}\\approx{} "; - case "$\\approx$": return " {}\\approx{} "; - case "v": return " \\downarrow{} "; - case "(v)": return " \\downarrow{} "; - case "^": return " \\uparrow{} "; - case "(^)": return " \\uparrow{} "; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - - // - // Helpers for code anaylsis - // Will show type error at calling position - // - /** @param {number} a */ - function assertNever(a) {} - /** @param {string} a */ - function assertString(a) {} - -/* eslint-disable no-undef */ - -////////////////////////////////////////////////////////////////////// -// texvc.sty - -// The texvc package contains macros available in mediawiki pages. -// We omit the functions deprecated at -// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax - -// We also omit texvc's \O, which conflicts with \text{\O} - -defineMacro("\\darr", "\\downarrow"); -defineMacro("\\dArr", "\\Downarrow"); -defineMacro("\\Darr", "\\Downarrow"); -defineMacro("\\lang", "\\langle"); -defineMacro("\\rang", "\\rangle"); -defineMacro("\\uarr", "\\uparrow"); -defineMacro("\\uArr", "\\Uparrow"); -defineMacro("\\Uarr", "\\Uparrow"); -defineMacro("\\N", "\\mathbb{N}"); -defineMacro("\\R", "\\mathbb{R}"); -defineMacro("\\Z", "\\mathbb{Z}"); -defineMacro("\\alef", "\\aleph"); -defineMacro("\\alefsym", "\\aleph"); -defineMacro("\\bull", "\\bullet"); -defineMacro("\\clubs", "\\clubsuit"); -defineMacro("\\cnums", "\\mathbb{C}"); -defineMacro("\\Complex", "\\mathbb{C}"); -defineMacro("\\Dagger", "\\ddagger"); -defineMacro("\\diamonds", "\\diamondsuit"); -defineMacro("\\empty", "\\emptyset"); -defineMacro("\\exist", "\\exists"); -defineMacro("\\harr", "\\leftrightarrow"); -defineMacro("\\hArr", "\\Leftrightarrow"); -defineMacro("\\Harr", "\\Leftrightarrow"); -defineMacro("\\hearts", "\\heartsuit"); -defineMacro("\\image", "\\Im"); -defineMacro("\\infin", "\\infty"); -defineMacro("\\isin", "\\in"); -defineMacro("\\larr", "\\leftarrow"); -defineMacro("\\lArr", "\\Leftarrow"); -defineMacro("\\Larr", "\\Leftarrow"); -defineMacro("\\lrarr", "\\leftrightarrow"); -defineMacro("\\lrArr", "\\Leftrightarrow"); -defineMacro("\\Lrarr", "\\Leftrightarrow"); -defineMacro("\\natnums", "\\mathbb{N}"); -defineMacro("\\plusmn", "\\pm"); -defineMacro("\\rarr", "\\rightarrow"); -defineMacro("\\rArr", "\\Rightarrow"); -defineMacro("\\Rarr", "\\Rightarrow"); -defineMacro("\\real", "\\Re"); -defineMacro("\\reals", "\\mathbb{R}"); -defineMacro("\\Reals", "\\mathbb{R}"); -defineMacro("\\sdot", "\\cdot"); -defineMacro("\\sect", "\\S"); -defineMacro("\\spades", "\\spadesuit"); -defineMacro("\\sub", "\\subset"); -defineMacro("\\sube", "\\subseteq"); -defineMacro("\\supe", "\\supseteq"); -defineMacro("\\thetasym", "\\vartheta"); -defineMacro("\\weierp", "\\wp"); - -/* eslint-disable no-undef */ - -/**************************************************** - * - * physics.js - * - * Implements the Physics Package for LaTeX input. - * - * --------------------------------------------------------------------- - * - * The original version of this file is licensed as follows: - * Copyright (c) 2015-2016 Kolen Cheung . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * --------------------------------------------------------------------- - * - * This file has been revised from the original in the following ways: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \Re and \Im are not used, to avoid conflict with existing LaTeX letters. - * - * This revision of the file is released under the MIT license. - * https://mit-license.org/ - */ -defineMacro("\\quantity", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\qty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\pqty", "{\\left( #1 \\right)}"); -defineMacro("\\bqty", "{\\left[ #1 \\right]}"); -defineMacro("\\vqty", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\Bqty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\absolutevalue", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\abs", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\norm", "{\\left\\Vert #1 \\right\\Vert}"); -defineMacro("\\evaluated", "{\\left.#1 \\right\\vert}"); -defineMacro("\\eval", "{\\left.#1 \\right\\vert}"); -defineMacro("\\order", "{\\mathcal{O} \\left( #1 \\right)}"); -defineMacro("\\commutator", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\comm", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\anticommutator", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\acomm", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\poissonbracket", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\pb", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\vectorbold", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vb", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vectorarrow", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\va", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\vectorunit", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\vu", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\dotproduct", "\\mathbin{\\boldsymbol\\cdot}"); -defineMacro("\\vdot", "{\\boldsymbol\\cdot}"); -defineMacro("\\crossproduct", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cross", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cp", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\gradient", "{\\boldsymbol\\nabla}"); -defineMacro("\\grad", "{\\boldsymbol\\nabla}"); -defineMacro("\\divergence", "{\\grad\\vdot}"); -//defineMacro("\\div", "{\\grad\\vdot}"); Not included in Temml. Conflicts w/LaTeX \div -defineMacro("\\curl", "{\\grad\\cross}"); -defineMacro("\\laplacian", "\\nabla^2"); -defineMacro("\\tr", "{\\operatorname{tr}}"); -defineMacro("\\Tr", "{\\operatorname{Tr}}"); -defineMacro("\\rank", "{\\operatorname{rank}}"); -defineMacro("\\erf", "{\\operatorname{erf}}"); -defineMacro("\\Res", "{\\operatorname{Res}}"); -defineMacro("\\principalvalue", "{\\mathcal{P}}"); -defineMacro("\\pv", "{\\mathcal{P}}"); -defineMacro("\\PV", "{\\operatorname{P.V.}}"); -// Temml does not use the next two lines. They conflict with LaTeX letters. -//defineMacro("\\Re", "{\\operatorname{Re} \\left\\{ #1 \\right\\}}"); -//defineMacro("\\Im", "{\\operatorname{Im} \\left\\{ #1 \\right\\}}"); -defineMacro("\\qqtext", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qq", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qcomma", "{\\text{,}\\quad}"); -defineMacro("\\qc", "{\\text{,}\\quad}"); -defineMacro("\\qcc", "{\\quad\\text{c.c.}\\quad}"); -defineMacro("\\qif", "{\\quad\\text{if}\\quad}"); -defineMacro("\\qthen", "{\\quad\\text{then}\\quad}"); -defineMacro("\\qelse", "{\\quad\\text{else}\\quad}"); -defineMacro("\\qotherwise", "{\\quad\\text{otherwise}\\quad}"); -defineMacro("\\qunless", "{\\quad\\text{unless}\\quad}"); -defineMacro("\\qgiven", "{\\quad\\text{given}\\quad}"); -defineMacro("\\qusing", "{\\quad\\text{using}\\quad}"); -defineMacro("\\qassume", "{\\quad\\text{assume}\\quad}"); -defineMacro("\\qsince", "{\\quad\\text{since}\\quad}"); -defineMacro("\\qlet", "{\\quad\\text{let}\\quad}"); -defineMacro("\\qfor", "{\\quad\\text{for}\\quad}"); -defineMacro("\\qall", "{\\quad\\text{all}\\quad}"); -defineMacro("\\qeven", "{\\quad\\text{even}\\quad}"); -defineMacro("\\qodd", "{\\quad\\text{odd}\\quad}"); -defineMacro("\\qinteger", "{\\quad\\text{integer}\\quad}"); -defineMacro("\\qand", "{\\quad\\text{and}\\quad}"); -defineMacro("\\qor", "{\\quad\\text{or}\\quad}"); -defineMacro("\\qas", "{\\quad\\text{as}\\quad}"); -defineMacro("\\qin", "{\\quad\\text{in}\\quad}"); -defineMacro("\\differential", "{\\text{d}}"); -defineMacro("\\dd", "{\\text{d}}"); -defineMacro("\\derivative", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\dv", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\partialderivative", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}"); -defineMacro("\\variation", "{\\delta}"); -defineMacro("\\var", "{\\delta}"); -defineMacro("\\functionalderivative", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\fdv", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\innerproduct", "{\\left\\langle {#1} \\mid { #2} \\right\\rangle}"); -defineMacro("\\outerproduct", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\dyad", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\ketbra", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\op", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\expectationvalue", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\expval", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\ev", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\matrixelement", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\matrixel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\mel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); - -/** - * This file contains the “gullet” where macros are expanded - * until only non-macro tokens remain. - */ - -// List of commands that act like macros but aren't defined as a macro, -// function, or symbol. Used in `isDefined`. -const implicitCommands = { - "^": true, // Parser.js - _: true, // Parser.js - "\\limits": true, // Parser.js - "\\nolimits": true // Parser.js -}; - -class MacroExpander { - constructor(input, settings, mode) { - this.settings = settings; - this.expansionCount = 0; - this.feed(input); - // Make new global namespace - this.macros = new Namespace(macros, settings.macros); - this.mode = mode; - this.stack = []; // contains tokens in REVERSE order - } - - /** - * Feed a new input string to the same MacroExpander - * (with existing macros etc.). - */ - feed(input) { - this.lexer = new Lexer(input, this.settings); - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - } - - /** - * Start a new group nesting within all namespaces. - */ - beginGroup() { - this.macros.beginGroup(); - } - - /** - * End current group nesting within all namespaces. - */ - endGroup() { - this.macros.endGroup(); - } - - /** - * Returns the topmost token on the stack, without expanding it. - * Similar in behavior to TeX's `\futurelet`. - */ - future() { - if (this.stack.length === 0) { - this.pushToken(this.lexer.lex()); - } - return this.stack[this.stack.length - 1] - } - - /** - * Remove and return the next unexpanded token. - */ - popToken() { - this.future(); // ensure non-empty stack - return this.stack.pop(); - } - - /** - * Add a given token to the token stack. In particular, this get be used - * to put back a token returned from one of the other methods. - */ - pushToken(token) { - this.stack.push(token); - } - - /** - * Append an array of tokens to the token stack. - */ - pushTokens(tokens) { - this.stack.push(...tokens); - } - - /** - * Find an macro argument without expanding tokens and append the array of - * tokens to the token stack. Uses Token as a container for the result. - */ - scanArgument(isOptional) { - let start; - let end; - let tokens; - if (isOptional) { - this.consumeSpaces(); // \@ifnextchar gobbles any space following it - if (this.future().text !== "[") { - return null; - } - start = this.popToken(); // don't include [ in tokens - ({ tokens, end } = this.consumeArg(["]"])); - } else { - ({ tokens, start, end } = this.consumeArg()); - } - - // indicate the end of an argument - this.pushToken(new Token("EOF", end.loc)); - - this.pushTokens(tokens); - return start.range(end, ""); - } - - /** - * Consume all following space tokens, without expansion. - */ - consumeSpaces() { - for (;;) { - const token = this.future(); - if (token.text === " ") { - this.stack.pop(); - } else { - break; - } - } - } - - /** - * Consume an argument from the token stream, and return the resulting array - * of tokens and start/end token. - */ - consumeArg(delims) { - // The argument for a delimited parameter is the shortest (possibly - // empty) sequence of tokens with properly nested {...} groups that is - // followed ... by this particular list of non-parameter tokens. - // The argument for an undelimited parameter is the next nonblank - // token, unless that token is ‘{’, when the argument will be the - // entire {...} group that follows. - const tokens = []; - const isDelimited = delims && delims.length > 0; - if (!isDelimited) { - // Ignore spaces between arguments. As the TeXbook says: - // "After you have said ‘\def\row#1#2{...}’, you are allowed to - // put spaces between the arguments (e.g., ‘\row x n’), because - // TeX doesn’t use single spaces as undelimited arguments." - this.consumeSpaces(); - } - const start = this.future(); - let tok; - let depth = 0; - let match = 0; - do { - tok = this.popToken(); - tokens.push(tok); - if (tok.text === "{") { - ++depth; - } else if (tok.text === "}") { - --depth; - if (depth === -1) { - throw new ParseError("Extra }", tok); - } - } else if (tok.text === "EOF") { - throw new ParseError( - "Unexpected end of input in a macro argument" + - ", expected '" + - (delims && isDelimited ? delims[match] : "}") + - "'", - tok - ); - } - if (delims && isDelimited) { - if ((depth === 0 || (depth === 1 && delims[match] === "{")) && tok.text === delims[match]) { - ++match; - if (match === delims.length) { - // don't include delims in tokens - tokens.splice(-match, match); - break; - } - } else { - match = 0; - } - } - } while (depth !== 0 || isDelimited); - // If the argument found ... has the form ‘{}’, - // ... the outermost braces enclosing the argument are removed - if (start.text === "{" && tokens[tokens.length - 1].text === "}") { - tokens.pop(); - tokens.shift(); - } - tokens.reverse(); // to fit in with stack order - return { tokens, start, end: tok }; - } - - /** - * Consume the specified number of (delimited) arguments from the token - * stream and return the resulting array of arguments. - */ - consumeArgs(numArgs, delimiters) { - if (delimiters) { - if (delimiters.length !== numArgs + 1) { - throw new ParseError("The length of delimiters doesn't match the number of args!"); - } - const delims = delimiters[0]; - for (let i = 0; i < delims.length; i++) { - const tok = this.popToken(); - if (delims[i] !== tok.text) { - throw new ParseError("Use of the macro doesn't match its definition", tok); - } - } - } - - const args = []; - for (let i = 0; i < numArgs; i++) { - args.push(this.consumeArg(delimiters && delimiters[i + 1]).tokens); - } - return args; - } - - /** - * Expand the next token only once if possible. - * - * If the token is expanded, the resulting tokens will be pushed onto - * the stack in reverse order and will be returned as an array, - * also in reverse order. - * - * If not, the next token will be returned without removing it - * from the stack. This case can be detected by a `Token` return value - * instead of an `Array` return value. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty. - * - * Used to implement `expandAfterFuture` and `expandNextToken`. - * - * If expandableOnly, only expandable tokens are expanded and - * an undefined control sequence results in an error. - */ - expandOnce(expandableOnly) { - const topToken = this.popToken(); - const name = topToken.text; - const expansion = !topToken.noexpand ? this._getExpansion(name) : null; - if (expansion == null || (expandableOnly && expansion.unexpandable)) { - if (expandableOnly && expansion == null && name[0] === "\\" && !this.isDefined(name)) { - throw new ParseError("Undefined control sequence: " + name); - } - this.pushToken(topToken); - return topToken; - } - this.expansionCount++; - if (this.expansionCount > this.settings.maxExpand) { - throw new ParseError( - "Too many expansions: infinite loop or " + "need to increase maxExpand setting" - ); - } - let tokens = expansion.tokens; - const args = this.consumeArgs(expansion.numArgs, expansion.delimiters); - if (expansion.numArgs) { - // paste arguments in place of the placeholders - tokens = tokens.slice(); // make a shallow copy - for (let i = tokens.length - 1; i >= 0; --i) { - let tok = tokens[i]; - if (tok.text === "#") { - if (i === 0) { - throw new ParseError("Incomplete placeholder at end of macro body", tok); - } - tok = tokens[--i]; // next token on stack - if (tok.text === "#") { - // ## → # - tokens.splice(i + 1, 1); // drop first # - } else if (/^[1-9]$/.test(tok.text)) { - // replace the placeholder with the indicated argument - tokens.splice(i, 2, ...args[+tok.text - 1]); - } else { - throw new ParseError("Not a valid argument number", tok); - } - } - } - } - // Concatenate expansion onto top of stack. - this.pushTokens(tokens); - return tokens; - } - - /** - * Expand the next token only once (if possible), and return the resulting - * top token on the stack (without removing anything from the stack). - * Similar in behavior to TeX's `\expandafter\futurelet`. - * Equivalent to expandOnce() followed by future(). - */ - expandAfterFuture() { - this.expandOnce(); - return this.future(); - } - - /** - * Recursively expand first token, then return first non-expandable token. - */ - expandNextToken() { - for (;;) { - const expanded = this.expandOnce(); - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (expanded.treatAsRelax) { - expanded.text = "\\relax"; - } - return this.stack.pop(); // === expanded - } - } - - // This pathway is impossible. - throw new Error(); // eslint-disable-line no-unreachable - } - - /** - * Fully expand the given macro name and return the resulting list of - * tokens, or return `undefined` if no such macro is defined. - */ - expandMacro(name) { - return this.macros.has(name) ? this.expandTokens([new Token(name)]) : undefined; - } - - /** - * Fully expand the given token stream and return the resulting list of - * tokens. Note that the input tokens are in reverse order, but the - * output tokens are in forward order. - */ - expandTokens(tokens) { - const output = []; - const oldStackLength = this.stack.length; - this.pushTokens(tokens); - while (this.stack.length > oldStackLength) { - const expanded = this.expandOnce(true); // expand only expandable tokens - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - if (expanded.treatAsRelax) { - // the expansion of \noexpand is the token itself - expanded.noexpand = false; - expanded.treatAsRelax = false; - } - output.push(this.stack.pop()); - } - } - return output; - } - - /** - * Fully expand the given macro name and return the result as a string, - * or return `undefined` if no such macro is defined. - */ - expandMacroAsText(name) { - const tokens = this.expandMacro(name); - if (tokens) { - return tokens.map((token) => token.text).join(""); - } else { - return tokens; - } - } - - /** - * Returns the expanded macro as a reversed array of tokens and a macro - * argument count. Or returns `null` if no such macro. - */ - _getExpansion(name) { - const definition = this.macros.get(name); - if (definition == null) { - // mainly checking for undefined here - return definition; - } - // If a single character has an associated catcode other than 13 - // (active character), then don't expand it. - if (name.length === 1) { - const catcode = this.lexer.catcodes[name]; - if (catcode != null && catcode !== 13) { - return - } - } - const expansion = typeof definition === "function" ? definition(this) : definition; - if (typeof expansion === "string") { - let numArgs = 0; - if (expansion.indexOf("#") !== -1) { - const stripped = expansion.replace(/##/g, ""); - while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { - ++numArgs; - } - } - const bodyLexer = new Lexer(expansion, this.settings); - const tokens = []; - let tok = bodyLexer.lex(); - while (tok.text !== "EOF") { - tokens.push(tok); - tok = bodyLexer.lex(); - } - tokens.reverse(); // to fit in with stack using push and pop - const expanded = { tokens, numArgs }; - return expanded; - } - - return expansion; - } - - /** - * Determine whether a command is currently "defined" (has some - * functionality), meaning that it's a macro (in the current group), - * a function, a symbol, or one of the special commands listed in - * `implicitCommands`. - */ - isDefined(name) { - return ( - this.macros.has(name) || - Object.prototype.hasOwnProperty.call(functions, name ) || - Object.prototype.hasOwnProperty.call(symbols.math, name ) || - Object.prototype.hasOwnProperty.call(symbols.text, name ) || - Object.prototype.hasOwnProperty.call(implicitCommands, name ) - ); - } - - /** - * Determine whether a command is expandable. - */ - isExpandable(name) { - const macro = this.macros.get(name); - return macro != null - ? typeof macro === "string" || typeof macro === "function" || !macro.unexpandable - : Object.prototype.hasOwnProperty.call(functions, name ) && !functions[name].primitive; - } -} - -/* - * This file defines the Unicode scripts and script families that we - * support. To add new scripts or families, just add a new entry to the - * scriptData array below. Adding scripts to the scriptData array allows - * characters from that script to appear in \text{} environments. - */ - -/** - * Each script or script family has a name and an array of blocks. - * Each block is an array of two numbers which specify the start and - * end points (inclusive) of a block of Unicode codepoints. - -/** - * Unicode block data for the families of scripts we support in \text{}. - * Scripts only need to appear here if they do not have font metrics. - */ -const scriptData = [ - { - // Latin characters beyond the Latin-1 characters we have metrics for. - // Needed for Czech, Hungarian and Turkish text, for example. - name: "latin", - blocks: [ - [0x0100, 0x024f], // Latin Extended-A and Latin Extended-B - [0x0300, 0x036f] // Combining Diacritical marks - ] - }, - { - // The Cyrillic script used by Russian and related languages. - // A Cyrillic subset used to be supported as explicitly defined - // symbols in symbols.js - name: "cyrillic", - blocks: [[0x0400, 0x04ff]] - }, - { - // Armenian - name: "armenian", - blocks: [[0x0530, 0x058f]] - }, - { - // The Brahmic scripts of South and Southeast Asia - // Devanagari (0900–097F) - // Bengali (0980–09FF) - // Gurmukhi (0A00–0A7F) - // Gujarati (0A80–0AFF) - // Oriya (0B00–0B7F) - // Tamil (0B80–0BFF) - // Telugu (0C00–0C7F) - // Kannada (0C80–0CFF) - // Malayalam (0D00–0D7F) - // Sinhala (0D80–0DFF) - // Thai (0E00–0E7F) - // Lao (0E80–0EFF) - // Tibetan (0F00–0FFF) - // Myanmar (1000–109F) - name: "brahmic", - blocks: [[0x0900, 0x109f]] - }, - { - name: "georgian", - blocks: [[0x10a0, 0x10ff]] - }, - { - // Chinese and Japanese. - // The "k" in cjk is for Korean, but we've separated Korean out - name: "cjk", - blocks: [ - [0x3000, 0x30ff], // CJK symbols and punctuation, Hiragana, Katakana - [0x4e00, 0x9faf], // CJK ideograms - [0xff00, 0xff60] // Fullwidth punctuation - // TODO: add halfwidth Katakana and Romanji glyphs - ] - }, - { - // Korean - name: "hangul", - blocks: [[0xac00, 0xd7af]] - } -]; - -/** - * A flattened version of all the supported blocks in a single array. - * This is an optimization to make supportedCodepoint() fast. - */ -const allBlocks = []; -scriptData.forEach((s) => s.blocks.forEach((b) => allBlocks.push(...b))); - -/** - * Given a codepoint, return true if it falls within one of the - * scripts or script families defined above and false otherwise. - * - * Micro benchmarks shows that this is faster than - * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() - * in Firefox, Chrome and Node. - */ -function supportedCodepoint(codepoint) { - for (let i = 0; i < allBlocks.length; i += 2) { - if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { - return true; - } - } - return false; -} - -// Mapping of Unicode accent characters to their LaTeX equivalent in text and -// math mode (when they exist). -var unicodeAccents = { - "\u0301": { text: "\\'", math: "\\acute" }, - "\u0300": { text: "\\`", math: "\\grave" }, - "\u0308": { text: '\\"', math: "\\ddot" }, - "\u0303": { text: "\\~", math: "\\tilde" }, - "\u0304": { text: "\\=", math: "\\bar" }, - "\u0306": { text: "\\u", math: "\\breve" }, - "\u030c": { text: "\\v", math: "\\check" }, - "\u0302": { text: "\\^", math: "\\hat" }, - "\u0307": { text: "\\.", math: "\\dot" }, - "\u030a": { text: "\\r", math: "\\mathring" }, - "\u030b": { text: "\\H" }, - '\u0327': { text: '\\c' } -}; - -var unicodeSymbols = { - "á": "á", - "à": "à", - "ä": "ä", - "ǟ": "ǟ", - "ã": "ã", - "ā": "ā", - "ă": "ă", - "ắ": "ắ", - "ằ": "ằ", - "ẵ": "ẵ", - "ǎ": "ǎ", - "â": "â", - "ấ": "ấ", - "ầ": "ầ", - "ẫ": "ẫ", - "ȧ": "ȧ", - "ǡ": "ǡ", - "å": "å", - "ǻ": "ǻ", - "ḃ": "ḃ", - "ć": "ć", - "č": "č", - "ĉ": "ĉ", - "ċ": "ċ", - "ď": "ď", - "ḋ": "ḋ", - "é": "é", - "è": "è", - "ë": "ë", - "ẽ": "ẽ", - "ē": "ē", - "ḗ": "ḗ", - "ḕ": "ḕ", - "ĕ": "ĕ", - "ě": "ě", - "ê": "ê", - "ế": "ế", - "ề": "ề", - "ễ": "ễ", - "ė": "ė", - "ḟ": "ḟ", - "ǵ": "ǵ", - "ḡ": "ḡ", - "ğ": "ğ", - "ǧ": "ǧ", - "ĝ": "ĝ", - "ġ": "ġ", - "ḧ": "ḧ", - "ȟ": "ȟ", - "ĥ": "ĥ", - "ḣ": "ḣ", - "í": "í", - "ì": "ì", - "ï": "ï", - "ḯ": "ḯ", - "ĩ": "ĩ", - "ī": "ī", - "ĭ": "ĭ", - "ǐ": "ǐ", - "î": "î", - "ǰ": "ǰ", - "ĵ": "ĵ", - "ḱ": "ḱ", - "ǩ": "ǩ", - "ĺ": "ĺ", - "ľ": "ľ", - "ḿ": "ḿ", - "ṁ": "ṁ", - "ń": "ń", - "ǹ": "ǹ", - "ñ": "ñ", - "ň": "ň", - "ṅ": "ṅ", - "ó": "ó", - "ò": "ò", - "ö": "ö", - "ȫ": "ȫ", - "õ": "õ", - "ṍ": "ṍ", - "ṏ": "ṏ", - "ȭ": "ȭ", - "ō": "ō", - "ṓ": "ṓ", - "ṑ": "ṑ", - "ŏ": "ŏ", - "ǒ": "ǒ", - "ô": "ô", - "ố": "ố", - "ồ": "ồ", - "ỗ": "ỗ", - "ȯ": "ȯ", - "ȱ": "ȱ", - "ő": "ő", - "ṕ": "ṕ", - "ṗ": "ṗ", - "ŕ": "ŕ", - "ř": "ř", - "ṙ": "ṙ", - "ś": "ś", - "ṥ": "ṥ", - "š": "š", - "ṧ": "ṧ", - "ŝ": "ŝ", - "ṡ": "ṡ", - "ẗ": "ẗ", - "ť": "ť", - "ṫ": "ṫ", - "ú": "ú", - "ù": "ù", - "ü": "ü", - "ǘ": "ǘ", - "ǜ": "ǜ", - "ǖ": "ǖ", - "ǚ": "ǚ", - "ũ": "ũ", - "ṹ": "ṹ", - "ū": "ū", - "ṻ": "ṻ", - "ŭ": "ŭ", - "ǔ": "ǔ", - "û": "û", - "ů": "ů", - "ű": "ű", - "ṽ": "ṽ", - "ẃ": "ẃ", - "ẁ": "ẁ", - "ẅ": "ẅ", - "ŵ": "ŵ", - "ẇ": "ẇ", - "ẘ": "ẘ", - "ẍ": "ẍ", - "ẋ": "ẋ", - "ý": "ý", - "ỳ": "ỳ", - "ÿ": "ÿ", - "ỹ": "ỹ", - "ȳ": "ȳ", - "ŷ": "ŷ", - "ẏ": "ẏ", - "ẙ": "ẙ", - "ź": "ź", - "ž": "ž", - "ẑ": "ẑ", - "ż": "ż", - "Á": "Á", - "À": "À", - "Ä": "Ä", - "Ǟ": "Ǟ", - "Ã": "Ã", - "Ā": "Ā", - "Ă": "Ă", - "Ắ": "Ắ", - "Ằ": "Ằ", - "Ẵ": "Ẵ", - "Ǎ": "Ǎ", - "Â": "Â", - "Ấ": "Ấ", - "Ầ": "Ầ", - "Ẫ": "Ẫ", - "Ȧ": "Ȧ", - "Ǡ": "Ǡ", - "Å": "Å", - "Ǻ": "Ǻ", - "Ḃ": "Ḃ", - "Ć": "Ć", - "Č": "Č", - "Ĉ": "Ĉ", - "Ċ": "Ċ", - "Ď": "Ď", - "Ḋ": "Ḋ", - "É": "É", - "È": "È", - "Ë": "Ë", - "Ẽ": "Ẽ", - "Ē": "Ē", - "Ḗ": "Ḗ", - "Ḕ": "Ḕ", - "Ĕ": "Ĕ", - "Ě": "Ě", - "Ê": "Ê", - "Ế": "Ế", - "Ề": "Ề", - "Ễ": "Ễ", - "Ė": "Ė", - "Ḟ": "Ḟ", - "Ǵ": "Ǵ", - "Ḡ": "Ḡ", - "Ğ": "Ğ", - "Ǧ": "Ǧ", - "Ĝ": "Ĝ", - "Ġ": "Ġ", - "Ḧ": "Ḧ", - "Ȟ": "Ȟ", - "Ĥ": "Ĥ", - "Ḣ": "Ḣ", - "Í": "Í", - "Ì": "Ì", - "Ï": "Ï", - "Ḯ": "Ḯ", - "Ĩ": "Ĩ", - "Ī": "Ī", - "Ĭ": "Ĭ", - "Ǐ": "Ǐ", - "Î": "Î", - "İ": "İ", - "Ĵ": "Ĵ", - "Ḱ": "Ḱ", - "Ǩ": "Ǩ", - "Ĺ": "Ĺ", - "Ľ": "Ľ", - "Ḿ": "Ḿ", - "Ṁ": "Ṁ", - "Ń": "Ń", - "Ǹ": "Ǹ", - "Ñ": "Ñ", - "Ň": "Ň", - "Ṅ": "Ṅ", - "Ó": "Ó", - "Ò": "Ò", - "Ö": "Ö", - "Ȫ": "Ȫ", - "Õ": "Õ", - "Ṍ": "Ṍ", - "Ṏ": "Ṏ", - "Ȭ": "Ȭ", - "Ō": "Ō", - "Ṓ": "Ṓ", - "Ṑ": "Ṑ", - "Ŏ": "Ŏ", - "Ǒ": "Ǒ", - "Ô": "Ô", - "Ố": "Ố", - "Ồ": "Ồ", - "Ỗ": "Ỗ", - "Ȯ": "Ȯ", - "Ȱ": "Ȱ", - "Ő": "Ő", - "Ṕ": "Ṕ", - "Ṗ": "Ṗ", - "Ŕ": "Ŕ", - "Ř": "Ř", - "Ṙ": "Ṙ", - "Ś": "Ś", - "Ṥ": "Ṥ", - "Š": "Š", - "Ṧ": "Ṧ", - "Ŝ": "Ŝ", - "Ṡ": "Ṡ", - "Ť": "Ť", - "Ṫ": "Ṫ", - "Ú": "Ú", - "Ù": "Ù", - "Ü": "Ü", - "Ǘ": "Ǘ", - "Ǜ": "Ǜ", - "Ǖ": "Ǖ", - "Ǚ": "Ǚ", - "Ũ": "Ũ", - "Ṹ": "Ṹ", - "Ū": "Ū", - "Ṻ": "Ṻ", - "Ŭ": "Ŭ", - "Ǔ": "Ǔ", - "Û": "Û", - "Ů": "Ů", - "Ű": "Ű", - "Ṽ": "Ṽ", - "Ẃ": "Ẃ", - "Ẁ": "Ẁ", - "Ẅ": "Ẅ", - "Ŵ": "Ŵ", - "Ẇ": "Ẇ", - "Ẍ": "Ẍ", - "Ẋ": "Ẋ", - "Ý": "Ý", - "Ỳ": "Ỳ", - "Ÿ": "Ÿ", - "Ỹ": "Ỹ", - "Ȳ": "Ȳ", - "Ŷ": "Ŷ", - "Ẏ": "Ẏ", - "Ź": "Ź", - "Ž": "Ž", - "Ẑ": "Ẑ", - "Ż": "Ż", - "ά": "ά", - "ὰ": "ὰ", - "ᾱ": "ᾱ", - "ᾰ": "ᾰ", - "έ": "έ", - "ὲ": "ὲ", - "ή": "ή", - "ὴ": "ὴ", - "ί": "ί", - "ὶ": "ὶ", - "ϊ": "ϊ", - "ΐ": "ΐ", - "ῒ": "ῒ", - "ῑ": "ῑ", - "ῐ": "ῐ", - "ό": "ό", - "ὸ": "ὸ", - "ύ": "ύ", - "ὺ": "ὺ", - "ϋ": "ϋ", - "ΰ": "ΰ", - "ῢ": "ῢ", - "ῡ": "ῡ", - "ῠ": "ῠ", - "ώ": "ώ", - "ὼ": "ὼ", - "Ύ": "Ύ", - "Ὺ": "Ὺ", - "Ϋ": "Ϋ", - "Ῡ": "Ῡ", - "Ῠ": "Ῠ", - "Ώ": "Ώ", - "Ὼ": "Ὼ" -}; - -/* eslint no-constant-condition:0 */ - -const numberRegEx$1 = /^\d[\d.]*$/; // Keep in sync with numberRegEx in symbolsOrd.js - -/** - * This file contains the parser used to parse out a TeX expression from the - * input. Since TeX isn't context-free, standard parsers don't work particularly - * well. - * - * The strategy of this parser is as such: - * - * The main functions (the `.parse...` ones) take a position in the current - * parse string to parse tokens from. The lexer (found in Lexer.js, stored at - * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When - * individual tokens are needed at a position, the lexer is called to pull out a - * token, which is then used. - * - * The parser has a property called "mode" indicating the mode that - * the parser is currently in. Currently it has to be one of "math" or - * "text", which denotes whether the current environment is a math-y - * one or a text-y one (e.g. inside \text). Currently, this serves to - * limit the functions which can be used in text mode. - * - * The main functions then return an object which contains the useful data that - * was parsed at its given point, and a new position at the end of the parsed - * data. The main functions can call each other and continue the parsing by - * using the returned position as a new starting point. - * - * There are also extra `.handle...` functions, which pull out some reused - * functionality into self-contained functions. - * - * The functions return ParseNodes. - */ - -class Parser { - constructor(input, settings, isPreamble = false) { - // Start in math mode - this.mode = "math"; - // Create a new macro expander (gullet) and (indirectly via that) also a - // new lexer (mouth) for this parser (stomach, in the language of TeX) - this.gullet = new MacroExpander(input, settings, this.mode); - // Store the settings for use in parsing - this.settings = settings; - // Are we defining a preamble? - this.isPreamble = isPreamble; - // Count leftright depth (for \middle errors) - this.leftrightDepth = 0; - this.prevAtomType = ""; - } - - /** - * Checks a result to make sure it has the right type, and throws an - * appropriate error otherwise. - */ - expect(text, consume = true) { - if (this.fetch().text !== text) { - throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); - } - if (consume) { - this.consume(); - } - } - - /** - * Discards the current lookahead token, considering it consumed. - */ - consume() { - this.nextToken = null; - } - - /** - * Return the current lookahead token, or if there isn't one (at the - * beginning, or if the previous lookahead token was consume()d), - * fetch the next token as the new lookahead token and return it. - */ - fetch() { - if (this.nextToken == null) { - this.nextToken = this.gullet.expandNextToken(); - } - return this.nextToken; - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - this.gullet.switchMode(newMode); - } - - /** - * Main parsing function, which parses an entire input. - */ - parse() { - // Create a group namespace for every $...$, $$...$$, \[...\].) - // A \def is then valid only within that pair of delimiters. - this.gullet.beginGroup(); - - if (this.settings.colorIsTextColor) { - // Use old \color behavior (same as LaTeX's \textcolor) if requested. - // We do this within the group for the math expression, so it doesn't - // pollute settings.macros. - this.gullet.macros.set("\\color", "\\textcolor"); - } - - // Try to parse the input - const parse = this.parseExpression(false); - - // If we succeeded, make sure there's an EOF at the end - this.expect("EOF"); - - if (this.isPreamble) { - const macros = Object.create(null); - Object.entries(this.gullet.macros.current).forEach(([key, value]) => { - macros[key] = value; - }); - this.gullet.endGroup(); - return macros - } - - // The only local macro that we want to save is from \tag. - const tag = this.gullet.macros.get("\\df@tag"); - - // End the group namespace for the expression - this.gullet.endGroup(); - - if (tag) { this.gullet.macros.current["\\df@tag"] = tag; } - - return parse; - } - - static get endOfExpression() { - return ["}", "\\endgroup", "\\end", "\\right", "\\endtoggle", "&"]; - } - - /** - * Parses an "expression", which is a list of atoms. - * - * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This - * happens when functions have higher precendence han infix - * nodes in implicit parses. - * - * `breakOnTokenText`: The text of the token that the expression should end - * with, or `null` if something else should end the - * expression. - */ - parseExpression(breakOnInfix, breakOnTokenText) { - const body = []; - // Keep adding atoms to the body until we can't parse any more atoms (either - // we reached the end, a }, or a \right) - while (true) { - // Ignore spaces in math mode - if (this.mode === "math") { - this.consumeSpaces(); - } - const lex = this.fetch(); - if (Parser.endOfExpression.indexOf(lex.text) !== -1) { - break; - } - if (breakOnTokenText && lex.text === breakOnTokenText) { - break; - } - if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { - break; - } - const atom = this.parseAtom(breakOnTokenText); - if (!atom) { - break; - } else if (atom.type === "internal") { - continue; - } - body.push(atom); - // Keep a record of the atom type, so that op.js can set correct spacing. - this.prevAtomType = atom.type === "atom" ? atom.family : atom.type; - } - if (this.mode === "text") { - this.formLigatures(body); - } - return this.handleInfixNodes(body); - } - - /** - * Rewrites infix operators such as \over with corresponding commands such - * as \frac. - * - * There can only be one infix operator per group. If there's more than one - * then the expression is ambiguous. This can be resolved by adding {}. - */ - handleInfixNodes(body) { - let overIndex = -1; - let funcName; - - for (let i = 0; i < body.length; i++) { - if (body[i].type === "infix") { - if (overIndex !== -1) { - throw new ParseError("only one infix operator per group", body[i].token); - } - overIndex = i; - funcName = body[i].replaceWith; - } - } - - if (overIndex !== -1 && funcName) { - let numerNode; - let denomNode; - - const numerBody = body.slice(0, overIndex); - const denomBody = body.slice(overIndex + 1); - - if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { - numerNode = numerBody[0]; - } else { - numerNode = { type: "ordgroup", mode: this.mode, body: numerBody }; - } - - if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { - denomNode = denomBody[0]; - } else { - denomNode = { type: "ordgroup", mode: this.mode, body: denomBody }; - } - - let node; - if (funcName === "\\\\abovefrac") { - node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); - } else { - node = this.callFunction(funcName, [numerNode, denomNode], []); - } - return [node]; - } else { - return body; - } - } - - /** - * Handle a subscript or superscript with nice errors. - */ - handleSupSubscript( - name // For error reporting. - ) { - const symbolToken = this.fetch(); - const symbol = symbolToken.text; - this.consume(); - this.consumeSpaces(); // ignore spaces before sup/subscript argument - const group = this.parseGroup(name); - - if (!group) { - throw new ParseError("Expected group after '" + symbol + "'", symbolToken); - } - - return group; - } - - /** - * Converts the textual input of an unsupported command into a text node - * contained within a color node whose color is determined by errorColor - */ - formatUnsupportedCmd(text) { - const textordArray = []; - - for (let i = 0; i < text.length; i++) { - textordArray.push({ type: "textord", mode: "text", text: text[i] }); - } - - const textNode = { - type: "text", - mode: this.mode, - body: textordArray - }; - - const colorNode = { - type: "color", - mode: this.mode, - color: this.settings.errorColor, - body: [textNode] - }; - - return colorNode; - } - - /** - * Parses a group with optional super/subscripts. - */ - parseAtom(breakOnTokenText) { - // The body of an atom is an implicit group, so that things like - // \left(x\right)^2 work correctly. - const base = this.parseGroup("atom", breakOnTokenText); - - // In text mode, we don't have superscripts or subscripts - if (this.mode === "text") { - return base; - } - - // Note that base may be empty (i.e. null) at this point. - - let superscript; - let subscript; - while (true) { - // Guaranteed in math mode, so eat any spaces first. - this.consumeSpaces(); - - // Lex the first token - const lex = this.fetch(); - - if (lex.text === "\\limits" || lex.text === "\\nolimits") { - // We got a limit control - if (base && base.type === "op") { - const limits = lex.text === "\\limits"; - base.limits = limits; - base.alwaysHandleSupSub = true; - } else if (base && base.type === "operatorname") { - if (base.alwaysHandleSupSub) { - base.limits = lex.text === "\\limits"; - } - } else { - throw new ParseError("Limit controls must follow a math operator", lex); - } - this.consume(); - } else if (lex.text === "^") { - // We got a superscript start - if (superscript) { - throw new ParseError("Double superscript", lex); - } - superscript = this.handleSupSubscript("superscript"); - } else if (lex.text === "_") { - // We got a subscript start - if (subscript) { - throw new ParseError("Double subscript", lex); - } - subscript = this.handleSupSubscript("subscript"); - } else if (lex.text === "'") { - // We got a prime - if (superscript) { - throw new ParseError("Double superscript", lex); - } - const prime = { type: "textord", mode: this.mode, text: "\\prime" }; - - // Many primes can be grouped together, so we handle this here - const primes = [prime]; - this.consume(); - // Keep lexing tokens until we get something that's not a prime - while (this.fetch().text === "'") { - // For each one, add another prime to the list - primes.push(prime); - this.consume(); - } - // If there's a superscript following the primes, combine that - // superscript in with the primes. - if (this.fetch().text === "^") { - primes.push(this.handleSupSubscript("superscript")); - } - // Put everything into an ordgroup as the superscript - superscript = { type: "ordgroup", mode: this.mode, body: primes }; - } else { - // If it wasn't ^, _, or ', stop parsing super/subscripts - break; - } - } - - if (superscript || subscript) { - if (base && base.type === "multiscript" && !base.postscripts) { - // base is the result of a \prescript function. - // Write the sub- & superscripts into the multiscript element. - base.postscripts = { sup: superscript, sub: subscript }; - return base - } else { - // We got either a superscript or subscript, create a supsub - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript - } - } - } else { - // Otherwise return the original body - return base; - } - } - - /** - * Parses an entire function, including its base and all of its arguments. - */ - parseFunction( - breakOnTokenText, - name // For determining its context - ) { - const token = this.fetch(); - const func = token.text; - const funcData = functions[func]; - if (!funcData) { - return null; - } - this.consume(); // consume command token - - if (name && name !== "atom" && !funcData.allowedInArgument) { - throw new ParseError( - "Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), - token - ); - } else if (this.mode === "text" && !funcData.allowedInText) { - throw new ParseError("Can't use function '" + func + "' in text mode", token); - } else if (this.mode === "math" && funcData.allowedInMath === false) { - throw new ParseError("Can't use function '" + func + "' in math mode", token); - } - - const prevAtomType = this.prevAtomType; - const { args, optArgs } = this.parseArguments(func, funcData); - this.prevAtomType = prevAtomType; - return this.callFunction(func, args, optArgs, token, breakOnTokenText); - } - - /** - * Call a function handler with a suitable context and arguments. - */ - callFunction(name, args, optArgs, token, breakOnTokenText) { - const context = { - funcName: name, - parser: this, - token, - breakOnTokenText - }; - const func = functions[name]; - if (func && func.handler) { - return func.handler(context, args, optArgs); - } else { - throw new ParseError(`No function handler for ${name}`); - } - } - - /** - * Parses the arguments of a function or environment - */ - parseArguments( - func, // Should look like "\name" or "\begin{name}". - funcData - ) { - const totalArgs = funcData.numArgs + funcData.numOptionalArgs; - if (totalArgs === 0) { - return { args: [], optArgs: [] }; - } - - const args = []; - const optArgs = []; - - for (let i = 0; i < totalArgs; i++) { - let argType = funcData.argTypes && funcData.argTypes[i]; - const isOptional = i < funcData.numOptionalArgs; - - if ( - (funcData.primitive && argType == null) || - // \sqrt expands into primitive if optional argument doesn't exist - (funcData.type === "sqrt" && i === 1 && optArgs[0] == null) - ) { - argType = "primitive"; - } - - const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional); - if (isOptional) { - optArgs.push(arg); - } else if (arg != null) { - args.push(arg); - } else { - // should be unreachable - throw new ParseError("Null argument, please report this as a bug"); - } - } - - return { args, optArgs }; - } - - /** - * Parses a group when the mode is changing. - */ - parseGroupOfType(name, type, optional) { - switch (type) { - case "size": - return this.parseSizeGroup(optional); - case "url": - return this.parseUrlGroup(optional); - case "math": - case "text": - return this.parseArgumentGroup(optional, type); - case "hbox": { - // hbox argument type wraps the argument in the equivalent of - // \hbox, which is like \text but switching to \textstyle size. - const group = this.parseArgumentGroup(optional, "text"); - return group != null - ? { - type: "styling", - mode: group.mode, - body: [group], - scriptLevel: "text" // simulate \textstyle - } - : null; - } - case "raw": { - const token = this.parseStringGroup("raw", optional); - return token != null - ? { - type: "raw", - mode: "text", - string: token.text - } - : null; - } - case "primitive": { - if (optional) { - throw new ParseError("A primitive argument cannot be optional"); - } - const group = this.parseGroup(name); - if (group == null) { - throw new ParseError("Expected group as " + name, this.fetch()); - } - return group; - } - case "original": - case null: - case undefined: - return this.parseArgumentGroup(optional); - default: - throw new ParseError("Unknown group type as " + name, this.fetch()); - } - } - - /** - * Discard any space tokens, fetching the next non-space token. - */ - consumeSpaces() { - while (this.fetch().text === " ") { - this.consume(); - } - } - - /** - * Parses a group, essentially returning the string formed by the - * brace-enclosed tokens plus some position information. - */ - parseStringGroup( - modeName, // Used to describe the mode in error messages. - optional - ) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF") { - str += nextToken.text; - this.consume(); - } - this.consume(); // consume the end of the argument - argToken.text = str; - return argToken; - } - - /** - * Parses a regex-delimited group: the largest sequence of tokens - * whose concatenated strings match `regex`. Returns the string - * formed by the tokens plus some position information. - */ - parseRegexGroup( - regex, - modeName // Used to describe the mode in error messages. - ) { - const firstToken = this.fetch(); - let lastToken = firstToken; - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { - lastToken = nextToken; - str += lastToken.text; - this.consume(); - } - if (str === "") { - throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); - } - return firstToken.range(lastToken, str); - } - - /** - * Parses a size specification, consisting of magnitude and unit. - */ - parseSizeGroup(optional) { - let res; - let isBlank = false; - // don't expand before parseStringGroup - this.gullet.consumeSpaces(); - if (!optional && this.gullet.future().text !== "{") { - res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); - } else { - res = this.parseStringGroup("size", optional); - } - if (!res) { - return null; - } - if (!optional && res.text.length === 0) { - // Because we've tested for what is !optional, this block won't - // affect \kern, \hspace, etc. It will capture the mandatory arguments - // to \genfrac and \above. - res.text = "0pt"; // Enable \above{} - isBlank = true; // This is here specifically for \genfrac - } - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); - if (!match) { - throw new ParseError("Invalid size: '" + res.text + "'", res); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "'", res); - } - return { - type: "size", - mode: this.mode, - value: data, - isBlank - }; - } - - /** - * Parses an URL, checking escaped letters and allowed protocols, - * and setting the catcode of % as an active character (as in \hyperref). - */ - parseUrlGroup(optional) { - this.gullet.lexer.setCatcode("%", 13); // active character - this.gullet.lexer.setCatcode("~", 12); // other character - const res = this.parseStringGroup("url", optional); - this.gullet.lexer.setCatcode("%", 14); // comment character - this.gullet.lexer.setCatcode("~", 13); // active character - if (res == null) { - return null; - } - // hyperref package allows backslashes alone in href, but doesn't - // generate valid links in such cases; we interpret this as - // "undefined" behaviour, and keep them as-is. Some browser will - // replace backslashes with forward slashes. - let url = res.text.replace(/\\([#$%&~_^{}])/g, "$1"); - url = res.text.replace(/{\u2044}/g, "/"); - return { - type: "url", - mode: this.mode, - url - }; - } - - /** - * Parses an argument with the mode specified. - */ - parseArgumentGroup(optional, mode) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - const outerMode = this.mode; - if (mode) { - // Switch to specified mode - this.switchMode(mode); - } - - this.gullet.beginGroup(); - const expression = this.parseExpression(false, "EOF"); - // TODO: find an alternative way to denote the end - this.expect("EOF"); // expect the end of the argument - this.gullet.endGroup(); - const result = { - type: "ordgroup", - mode: this.mode, - loc: argToken.loc, - body: expression - }; - - if (mode) { - // Switch mode back - this.switchMode(outerMode); - } - return result; - } - - /** - * Parses an ordinary group, which is either a single nucleus (like "x") - * or an expression in braces (like "{x+y}") or an implicit group, a group - * that starts at the current position, and ends right before a higher explicit - * group ends, or at EOF. - */ - parseGroup( - name, // For error reporting. - breakOnTokenText - ) { - const firstToken = this.fetch(); - const text = firstToken.text; - - let result; - // Try to parse an open brace or \begingroup - if (text === "{" || text === "\\begingroup" || text === "\\toggle") { - this.consume(); - const groupEnd = text === "{" - ? "}" - : text === "\\begingroup" - ? "\\endgroup" - : "\\endtoggle"; - - this.gullet.beginGroup(); - // If we get a brace, parse an expression - const expression = this.parseExpression(false, groupEnd); - const lastToken = this.fetch(); - this.expect(groupEnd); // Check that we got a matching closing brace - this.gullet.endGroup(); - result = { - type: (lastToken.text === "\\endtoggle" ? "toggle" : "ordgroup"), - mode: this.mode, - loc: SourceLocation.range(firstToken, lastToken), - body: expression, - // A group formed by \begingroup...\endgroup is a semi-simple group - // which doesn't affect spacing in math mode, i.e., is transparent. - // https://tex.stackexchange.com/questions/1930/when-should-one- - // use-begingroup-instead-of-bgroup - semisimple: text === "\\begingroup" || undefined - }; - } else { - // If there exists a function with this name, parse the function. - // Otherwise, just return a nucleus - result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol(); - if (result == null && text[0] === "\\" && - !Object.prototype.hasOwnProperty.call(implicitCommands, text )) { - result = this.formatUnsupportedCmd(text); - this.consume(); - } - } - return result; - } - - /** - * Form ligature-like combinations of characters for text mode. - * This includes inputs like "--", "---", "``" and "''". - * The result will simply replace multiple textord nodes with a single - * character in each value by a single textord node having multiple - * characters in its value. The representation is still ASCII source. - * The group will be modified in place. - */ - formLigatures(group) { - let n = group.length - 1; - for (let i = 0; i < n; ++i) { - const a = group[i]; - const v = a.text; - if (v === "-" && group[i + 1].text === "-") { - if (i + 1 < n && group[i + 2].text === "-") { - group.splice(i, 3, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 2]), - text: "---" - }); - n -= 2; - } else { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: "--" - }); - n -= 1; - } - } - if ((v === "'" || v === "`") && group[i + 1].text === v) { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: v + v - }); - n -= 1; - } - } - } - - /** - * Parse a single symbol out of the string. Here, we handle single character - * symbols and special functions like \verb. - */ - parseSymbol() { - const nucleus = this.fetch(); - let text = nucleus.text; - - if (/^\\verb[^a-zA-Z]/.test(text)) { - this.consume(); - let arg = text.slice(5); - const star = arg.charAt(0) === "*"; - if (star) { - arg = arg.slice(1); - } - // Lexer's tokenRegex is constructed to always have matching - // first/last characters. - if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { - throw new ParseError(`\\verb assertion failed -- - please report what input caused this bug`); - } - arg = arg.slice(1, -1); // remove first and last char - return { - type: "verb", - mode: "text", - body: arg, - star - }; - } - // At this point, we should have a symbol, possibly with accents. - // First expand any accented base symbol according to unicodeSymbols. - if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0] ) && - !symbols[this.mode][text[0]]) { - // This behavior is not strict (XeTeX-compatible) in math mode. - if (this.settings.strict && this.mode === "math") { - this.settings.reportNonstrict( - "unicodeTextInMathMode", - `Accented Unicode text character "${text[0]}" used in ` + `math mode`, - nucleus - ); - } - text = unicodeSymbols[text[0]] + text.substr(1); - } - // Strip off any combining characters - const match = combiningDiacriticalMarksEndRegex.exec(text); - if (match) { - text = text.substring(0, match.index); - if (text === "i") { - text = "\u0131"; // dotless i, in math and text mode - } else if (text === "j") { - text = "\u0237"; // dotless j, in math and text mode - } - } - // Recognize base symbol - let symbol; - if (symbols[this.mode][text]) { - const group = symbols[this.mode][text].group; - const loc = SourceLocation.range(nucleus); - let s; - if (Object.prototype.hasOwnProperty.call(ATOMS, group )) { - const family = group; - s = { - type: "atom", - mode: this.mode, - family, - loc, - text - }; - } else { - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (!this.strict && numberRegEx$1.test(text)) { - // A number. Wrap in a - this.consume(); - return { - type: "textord", - mode: "math", - loc: SourceLocation.range(nucleus), - text - } - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict) { - if (!supportedCodepoint(text.charCodeAt(0))) { - this.settings.reportNonstrict( - "unknownSymbol", - `Unrecognized Unicode character "${text[0]}"` + ` (${text.charCodeAt(0)})`, - nucleus - ); - } else if (this.mode === "math") { - this.settings.reportNonstrict( - "unicodeTextInMathMode", - `Unicode text character "${text[0]}" used in math mode`, - nucleus - ); - } - } - // All nonmathematical Unicode characters are rendered as if they - // are in text mode (wrapped in \text) because that's what it - // takes to render them in LaTeX. - symbol = { - type: "textord", - mode: "text", - loc: SourceLocation.range(nucleus), - text - }; - } else { - return null; // EOF, ^, _, {, }, etc. - } - this.consume(); - // Transform combining characters into accents - if (match) { - for (let i = 0; i < match[0].length; i++) { - const accent = match[0][i]; - if (!unicodeAccents[accent]) { - throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); - } - const command = unicodeAccents[accent][this.mode] || - unicodeAccents[accent].text; - if (!command) { - throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); - } - symbol = { - type: "accent", - mode: this.mode, - loc: SourceLocation.range(nucleus), - label: command, - isStretchy: false, - isShifty: true, - base: symbol - }; - } - } - return symbol; - } -} - -/** - * Parses an expression using a Parser, then returns the parsed result. - */ -const parseTree = function(toParse, settings) { - if (!(typeof toParse === "string" || toParse instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(toParse, settings); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - - let tree = parser.parse(); - - // LaTeX ignores a \tag placed outside an AMS environment. - if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) { - // If the input used \tag, it will set the \df@tag macro to the tag. - // In this case, we separately parse the tag and wrap the tree. - if (parser.gullet.macros.get("\\df@tag")) { - if (!settings.displayMode) { - throw new ParseError("\\tag works only in display equations") - } - parser.gullet.feed("\\df@tag"); - tree = [ - { - type: "tag", - mode: "text", - body: tree, - tag: parser.parse() - } - ]; - } - } - - return tree -}; - -/** - * This file contains information about the style that the Parser carries - * around with it while parsing. Data is held in an `Style` object, and when - * recursing, a new `Style` object can be created with the `.with*` functions. - */ - -const subOrSupLevel = [2, 2, 3, 3]; - -/** - * This is the main Style class. It contains the current style.level, color, and font. - * - * Style objects should not be modified. To create a new Style with - * different properties, call a `.with*` method. - */ -class Style { - constructor(data) { - // Style.level can be 0 | 1 | 2 | 3, which correspond to - // displaystyle, textstyle, scriptstyle, and scriptscriptstyle. - // style.level does not directly set MathML's script level. MathML does that itself. - // We use style.level to track, not set, math style so that we can get the - // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em. - this.level = data.level; - this.color = data.color; // string | void - // A font family applies to a group of fonts (i.e. SansSerif), while a font - // represents a specific font (i.e. SansSerif Bold). - // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm - this.font = data.font || ""; // string - this.fontFamily = data.fontFamily || ""; // string - this.fontWeight = data.fontWeight || ""; - this.fontShape = data.fontShape || ""; - this.maxSize = data.maxSize; // number - } - - /** - * Returns a new style object with the same properties as "this". Properties - * from "extension" will be copied to the new style object. - */ - extend(extension) { - const data = { - level: this.level, - color: this.color, - font: this.font, - fontFamily: this.fontFamily, - fontWeight: this.fontWeight, - fontShape: this.fontShape, - maxSize: this.maxSize - }; - - for (const key in extension) { - if (Object.prototype.hasOwnProperty.call(extension, key)) { - data[key] = extension[key]; - } - } - - return new Style(data); - } - - withLevel(n) { - return this.extend({ - level: n - }); - } - - incrementLevel() { - return this.extend({ - level: Math.min(this.level + 1, 3) - }); - } - - inSubOrSup() { - return this.extend({ - level: subOrSupLevel[this.level] - }) - } - - /** - * Create a new style object with the given color. - */ - withColor(color) { - return this.extend({ - color: color - }); - } - - /** - * Creates a new style object with the given math font or old text font. - * @type {[type]} - */ - withFont(font) { - return this.extend({ - font - }); - } - - /** - * Create a new style objects with the given fontFamily. - */ - withTextFontFamily(fontFamily) { - return this.extend({ - fontFamily, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontWeight(fontWeight) { - return this.extend({ - fontWeight, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontShape(fontShape) { - return this.extend({ - fontShape, - font: "" - }); - } - - /** - * Gets the CSS color of the current style object - */ - getColor() { - return this.color; - } -} - -/* Temml Post Process - * Perform two tasks not done by Temml when it created each individual Temml element. - * Given a block of block, - * 1. At each AMS auto-numbered environment, assign an id. - * 2. Populate the text contents of each \ref & \eqref - * - * As with other Temml code, this file is released under terms of the MIT license. - * https://mit-license.org/ - */ - -const version = "0.4.2"; - -function postProcess(block) { - const labelMap = {}; - let i = 0; - - // Get a collection of the parents of each \tag & auto-numbered equation - const parents = block.getElementsByClassName("tml-tageqn"); - for (const parent of parents) { - const eqns = parent.getElementsByClassName("tml-eqn"); - if (eqns. length > 0 ) { - // AMS automatically numbered equation. - // Assign an id. - i += 1; - eqns[0].id = "tml-eqn-" + i; - // No need to write a number into the text content of the element. - // A CSS counter does that even if this postProcess() function is not used. - } - // If there is a \label, add it to labelMap - const labels = parent.getElementsByClassName("tml-label"); - if (labels.length === 0) { continue } - if (eqns.length > 0) { - labelMap[labels[0].id] = String(i); - } else { - const tags = parent.getElementsByClassName("tml-tag"); - if (tags.length > 0) { - labelMap[labels[0].id] = tags[0].textContent; - } - } - } - - // Populate \ref & \eqref text content - const refs = block.getElementsByClassName("tml-ref"); - [...refs].forEach(ref => { - let str = labelMap[ref.getAttribute("href").slice(1)]; - if (ref.className.indexOf("tml-eqref") === -1) { - // \ref. Omit parens. - str = str.replace(/^\(/, ""); - str = str.replace(/\($/, ""); - } { - // \eqref. Include parens - if (str.charAt(0) !== "(") { str = "(" + str; } - if (str.slice(-1) !== ")") { str = str + ")"; } - } - ref.textContent = str; - }); -} - -/* eslint no-console:0 */ - -/** - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options) { - baseNode.textContent = ""; - const math = renderToMathMLTree(expression, options); - if (options.elementIsMath) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else { - baseNode.appendChild(math.toNode()); - } -}; - -// Temml's styles don't work properly in quirks mode. Print out an error, and -// disable rendering. -if (typeof document !== "undefined") { - if (document.compatMode !== "CSS1Compat") { - typeof console !== "undefined" && - console.warn( - "Warning: Temml doesn't work in quirks mode. Make sure your " + - "website has a suitable doctype." - ); - - render = function() { - throw new ParseError("Temml doesn't work in quirks mode."); - }; - } -} - -/** - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * Take an expression which contains a preamble. - * Parse it and return the macros. - */ -const definePreamble = function(expression, options) { - const settings = new Settings(options); - settings.macros = {}; - if (!(typeof expression === "string" || expression instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(expression, settings, true); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - const macros = parser.parse(); - return macros -}; - -/** - * If the given error is a Temml ParseError, - * renders the invalid LaTeX as a span with hover title giving the Temml - * error message. Otherwise, simply throws the error. - */ -const renderError = function(error, expression, options) { - if (options.throwOnError || !(error instanceof ParseError)) { - throw error; - } - const node = new Span(["temml-error"], [new TextNode(expression)]); - node.setAttribute("title", error.toString()); - node.setAttribute("style", `color:${options.errorColor}`); - return node; -}; - -/** - * Generates and returns the Temml build tree. This is used for advanced - * use cases (like rendering to custom output). - */ -const renderToMathMLTree = function(expression, options) { - const settings = new Settings(options); - try { - const tree = parseTree(expression, settings); - const style = new Style({ - level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT, - maxSize: settings.maxSize - }); - return buildMathML(tree, expression, style, settings); - } catch (error) { - return renderError(error, expression, settings); - } -}; - -var temml = { - /** - * Current Temml version - */ - version: version, - /** - * Renders the given LaTeX into MathML, and adds - * it as a child to the specified DOM node. - */ - render, - /** - * Renders the given LaTeX into MathML string, - * for sending to the client. - */ - renderToString, - /** - * Post-process an entire HTML block. - * Writes AMS auto-numbers and implements \ref{}. - * Typcally called once, after a loop has rendered many individual spans. - */ - postProcess, - /** - * Temml error, usually during parsing. - */ - ParseError, - /** - * Creates a set of macros with document-wide scope. - */ - definePreamble, - /** - * Parses the given LaTeX into Temml's internal parse tree structure, - * without rendering to HTML or MathML. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __parse: generateParseTree, - /** - * Renders the given LaTeX into a MathML internal DOM tree - * representation, without flattening that representation to a string. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __renderToMathMLTree: renderToMathMLTree, - /** - * adds a new symbol to builtin symbols table - */ - __defineSymbol: defineSymbol, - /** - * adds a new macro to builtin macro list - */ - __defineMacro: defineMacro -}; - -module.exports = temml; diff --git a/utils/temml.mjs b/utils/temml.mjs deleted file mode 100644 index 66eb508a..00000000 --- a/utils/temml.mjs +++ /dev/null @@ -1,13099 +0,0 @@ -/** - * This is the ParseError class, which is the main error thrown by Temml - * functions when something has gone wrong. This is used to distinguish internal - * errors from errors in the expression that the user provided. - * - * If possible, a caller should provide a Token or ParseNode with information - * about where in the source string the problem occurred. - */ -class ParseError { - constructor( - message, // The error message - token // An object providing position information - ) { - let error = " " + message; - let start; - - const loc = token && token.loc; - if (loc && loc.start <= loc.end) { - // If we have the input and a position, make the error a bit fancier - - // Get the input - const input = loc.lexer.input; - - // Prepend some information - start = loc.start; - const end = loc.end; - if (start === input.length) { - error += " at end of input: "; - } else { - error += " at position " + (start + 1) + ": "; - } - - // Underline token in question using combining underscores - const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); - - // Extract some context from the input and add it to the error - let left; - if (start > 15) { - left = "…" + input.slice(start - 15, start); - } else { - left = input.slice(0, start); - } - let right; - if (end + 15 < input.length) { - right = input.slice(end, end + 15) + "…"; - } else { - right = input.slice(end); - } - error += left + underlined + right; - } - - // Some hackery to make ParseError a prototype of Error - // See http://stackoverflow.com/a/8460753 - const self = new Error(error); - self.name = "ParseError"; - self.__proto__ = ParseError.prototype; - self.position = start; - return self; - } -} - -ParseError.prototype.__proto__ = Error.prototype; - -// -/** - * This file contains a list of utility functions which are useful in other - * files. - */ - -/** - * Return whether an element is contained in a list - */ -const contains = function(list, elem) { - return list.indexOf(elem) !== -1; -}; - -/** - * Provide a default value if a setting is undefined - */ -const deflt = function(setting, defaultIfUndefined) { - return setting === undefined ? defaultIfUndefined : setting; -}; - -// hyphenate and escape adapted from Facebook's React under Apache 2 license - -const uppercase = /([A-Z])/g; -const hyphenate = function(str) { - return str.replace(uppercase, "-$1").toLowerCase(); -}; - -const ESCAPE_LOOKUP = { - "&": "&", - ">": ">", - "<": "<", - '"': """, - "'": "'" -}; - -const ESCAPE_REGEX = /[&><"']/g; - -/** - * Escapes text to prevent scripting attacks. - */ -function escape(text) { - return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); -} - -/** - * Sometimes we want to pull out the innermost element of a group. In most - * cases, this will just be the group itself, but when ordgroups and colors have - * a single element, we want to pull that out. - */ -const getBaseElem = function(group) { - if (group.type === "ordgroup") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "color") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "font") { - return getBaseElem(group.body); - } else { - return group; - } -}; - -/** - * TeXbook algorithms often reference "character boxes", which are simply groups - * with a single character in them. To decide if something is a character box, - * we find its innermost group, and see if it is a single character. - */ -const isCharacterBox = function(group) { - const baseElem = getBaseElem(group); - - // These are all the types of groups which hold single characters - return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom" -}; - -const assert = function(value) { - if (!value) { - throw new Error("Expected non-null, but got " + String(value)); - } - return value; -}; - -/** - * Return the protocol of a URL, or "_relative" if the URL does not specify a - * protocol (and thus is relative). - */ -const protocolFromUrl = function(url) { - const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); - return protocol != null ? protocol[1] : "_relative"; -}; - -/** - * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook - * gives an acceptable rounding error of 100sp (which would be the nearest - * 1/6551.6em with our ptPerEm = 10): - * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69 - */ -const round = function(n) { - return +n.toFixed(4); -}; - -const consolidateText = mrow => { - // If possible, consolidate adjacent elements into a single element. - if (mrow.type !== "mrow") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - const mtext = mrow.children[0]; - if (!mtext.attributes || mtext.type !== "mtext") { return mrow } - const variant = mtext.attributes.mathvariant || ""; - for (let i = 1; i < mrow.children.length; i++) { - // Check each child and, if possible, copy the character into child[0]. - const localVariant = mrow.children[i].attributes.mathvariant || ""; - if (mrow.children[i].type === "mrow") { - const childRow = mrow.children[i]; - for (let j = 0; j < childRow.children.length; j++) { - // We'll also check the children of a mrow. One level only. No recursion. - const childVariant = childRow.children[j].attributes.mathvariant || ""; - if (childVariant !== variant || childRow.children[j].type !== "mtext") { - return mrow // At least one element cannot be consolidated. Get out. - } else { - mtext.children[0].text += childRow.children[j].children[0].text; - } - } - } else if (localVariant !== variant || mrow.children[i].type !== "mtext") { - return mrow - } else { - mtext.children[0].text += mrow.children[i].children[0].text; - } - } - // Since we have gotten here, the text has been loaded into a single mtext node. - // Next, consolidate the children into a single element. - mtext.children.splice(1, mtext.children.length - 1); - // Firefox does not render a space at either end of an string. - // To get proper rendering, we replace leading or trailing spaces with no-break spaces. - if (mtext.children[0].text.charAt(0) === " ") { - mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1); - } - const L = mtext.children[0].text.length; - if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") { - mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0"; - } - return mtext -}; - -var utils = { - contains, - deflt, - escape, - hyphenate, - getBaseElem, - isCharacterBox, - protocolFromUrl, - round, - consolidateText -}; - -/** - * This is a module for storing settings passed into Temml. It correctly handles - * default settings. - */ - -/** - * The main Settings object - */ -class Settings { - constructor(options) { - // allow null options - options = options || {}; - this.displayMode = utils.deflt(options.displayMode, false); // boolean - this.annotate = utils.deflt(options.annotate, false); // boolean - this.elementIsMath = utils.deflt(options.elementIsMath, false); // boolean - this.leqno = utils.deflt(options.leqno, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.preventTagLap = utils.deflt(options.preventTagLap, false); // boolean - this.macros = options.macros || {}; - this.xml = utils.deflt(options.xml, false); // boolean - this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean - this.strict = utils.deflt(options.strict, false); // boolean - this.trust = utils.deflt(options.trust, false); // trust context. See html.js. - this.maxSize = (options.maxSize === undefined - ? [Infinity, Infinity] - : Array.isArray(options.maxSize) - ? options.maxSize - : [Infinity, Infinity] - ); - this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number - } - - /** - * Check whether to test potentially dangerous input, and return - * `true` (trusted) or `false` (untrusted). The sole argument `context` - * should be an object with `command` field specifying the relevant LaTeX - * command (as a string starting with `\`), and any other arguments, etc. - * If `context` has a `url` field, a `protocol` field will automatically - * get added by this function (changing the specified object). - */ - isTrusted(context) { - if (context.url && !context.protocol) { - context.protocol = utils.protocolFromUrl(context.url); - } - const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; - return Boolean(trust); - } -} - -/** - * All registered functions. - * `functions.js` just exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary. - */ -const _functions = {}; - -/** - * All MathML builders. Should be only used in the `define*` and the `build*ML` - * functions. - */ -const _mathmlGroupBuilders = {}; - -function defineFunction({ - type, - names, - props, - handler, - mathmlBuilder -}) { - // Set default values of functions - const data = { - type, - numArgs: props.numArgs, - argTypes: props.argTypes, - allowedInArgument: !!props.allowedInArgument, - allowedInText: !!props.allowedInText, - allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, - numOptionalArgs: props.numOptionalArgs || 0, - infix: !!props.infix, - primitive: !!props.primitive, - handler: handler - }; - for (let i = 0; i < names.length; ++i) { - _functions[names[i]] = data; - } - if (type) { - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } - } -} - -/** - * Use this to register only the MathML builder for a function(e.g. - * if the function's ParseNode is generated in Parser.js rather than via a - * stand-alone handler provided to `defineFunction`). - */ -function defineFunctionBuilders({ type, mathmlBuilder }) { - defineFunction({ - type, - names: [], - props: { numArgs: 0 }, - handler() { - throw new Error("Should never be called.") - }, - mathmlBuilder - }); -} - -const normalizeArgument = function(arg) { - return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg -}; - -// Since the corresponding buildMathML function expects a -// list of elements, we normalize for different kinds of arguments -const ordargument = function(arg) { - return arg.type === "ordgroup" ? arg.body : [arg] -}; - -/** - * This node represents a document fragment, which contains elements, but when - * placed into the DOM doesn't have any representation itself. It only contains - * children and doesn't have any DOM node properties. - */ -class DocumentFragment { - constructor(children) { - this.children = children; - this.classes = []; - this.style = {}; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - /** Convert the fragment into a node. */ - toNode() { - const frag = document.createDocumentFragment(); - - for (let i = 0; i < this.children.length; i++) { - frag.appendChild(this.children[i].toNode()); - } - - return frag; - } - - /** Convert the fragment into HTML markup. */ - toMarkup() { - let markup = ""; - - // Simply concatenate the markup for the children together. - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText. Applies to - * MathDomNode's only. - */ - toText() { - // To avoid this, we would subclass documentFragment separately for - // MathML, but polyfills for subclassing is expensive per PR 1469. - const toText = (child) => child.toText(); - return this.children.map(toText).join(""); - } -} - -/** - * These objects store the data about the DOM nodes we create, as well as some - * extra data. They can then be transformed into real DOM nodes with the - * `toNode` function or HTML markup using `toMarkup`. They are useful for both - * storing extra properties on the nodes, as well as providing a way to easily - * work with the DOM. - * - * Similar functions for working with MathML nodes exist in mathMLTree.js. - * - */ - -/** - * Create an HTML className based on a list of classes. In addition to joining - * with spaces, we also remove empty classes. - */ -const createClass = function(classes) { - return classes.filter((cls) => cls).join(" "); -}; - -const initNode = function(classes, style) { - this.classes = classes || []; - this.attributes = {}; - this.style = style || {}; -}; - -/** - * Convert into an HTML node - */ -const toNode = function(tagName) { - const node = document.createElement(tagName); - - // Apply the class - node.className = createClass(this.classes); - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - // Apply attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - // Append the children, also as HTML nodes - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; -}; - -/** - * Convert into an HTML markup string - */ -const toMarkup = function(tagName) { - let markup = `<${tagName}`; - - // Add the class - if (this.classes.length) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; - } - } - - markup += ">"; - - // Add the markup of the children, also as markup - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ``; - - return markup; -}; - -/** - * This node represents a span node, with a className, a list of children, and - * an inline style. - * - */ -class Span { - constructor(classes, children, style) { - initNode.call(this, classes, style); - this.children = children || []; - } - - setAttribute(attribute, value) { - this.attributes[attribute] = value; - } - - toNode() { - return toNode.call(this, "span"); - } - - toMarkup() { - return toMarkup.call(this, "span"); - } -} - -class TextNode$1 { - constructor(text) { - this.text = text; - } - toNode() { - return document.createTextNode(this.text); - } - toMarkup() { - return utils.escape(this.text); - } -} - -/** - * This node represents an image embed () element. - */ -class Img { - constructor(src, alt, style) { - this.alt = alt; - this.src = src; - this.classes = ["mord"]; - this.style = style; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - toNode() { - const node = document.createElement("img"); - node.src = this.src; - node.alt = this.alt; - node.className = "mord"; - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - return node; - } - - toMarkup() { - let markup = `${this.alt}` and - * `` tags). - */ -class MathNode { - constructor(type, children, classes, style) { - this.type = type; - this.attributes = {}; - this.children = children || []; - this.classes = classes || []; - this.style = style || {}; // Used for elements - } - - /** - * Sets an attribute on a MathML node. MathML depends on attributes to convey a - * semantic content, so this is used heavily. - */ - setAttribute(name, value) { - this.attributes[name] = value; - } - - /** - * Gets an attribute on a MathML node. - */ - getAttribute(name) { - return this.attributes[name]; - } - - /** - * Converts the math node into a MathML-namespaced DOM element. - */ - toNode() { - const node = document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); - - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - if (this.classes.length > 0) { - node.className = createClass(this.classes); - } - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; - } - - /** - * Converts the math node into an HTML markup string. - */ - toMarkup() { - let markup = "<" + this.type; - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - markup += " " + attr + '="'; - markup += utils.escape(this.attributes[attr]); - markup += '"'; - } - } - - if (this.classes.length > 0) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - markup += ">"; - - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ""; - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText, but escaped. - */ - toText() { - return this.children.map((child) => child.toText()).join(""); - } -} - -/** - * This node represents a piece of text. - */ -class TextNode { - constructor(text) { - this.text = text; - } - - /** - * Converts the text node into a DOM text node. - */ - toNode() { - return document.createTextNode(this.text); - } - - /** - * Converts the text node into escaped HTML markup - * (representing the text itself). - */ - toMarkup() { - return utils.escape(this.toText()); - } - - /** - * Converts the text node into a string - * (representing the text iteself). - */ - toText() { - return this.text; - } -} - -// Do not make an the only child of a . -// An acts as its own implicit . -const wrapWithMstyle = expression => { - let node; - if (expression.length === 1 && expression[0].type === "mrow") { - node = expression.pop(); - node.type = "mstyle"; - } else { - node = new MathNode("mstyle", expression); - } - return node -}; - -var mathMLTree = { - MathNode, - TextNode, - newDocumentFragment -}; - -/** - * This file provides support for building horizontal stretchy elements. - */ - -const stretchyCodePoint = { - widehat: "^", - widecheck: "ˇ", - widetilde: "~", - wideparen: "⏜", // \u23dc - utilde: "~", - overleftarrow: "\u2190", - underleftarrow: "\u2190", - xleftarrow: "\u2190", - overrightarrow: "\u2192", - underrightarrow: "\u2192", - xrightarrow: "\u2192", - underbrace: "\u23df", - overbrace: "\u23de", - overgroup: "\u23e0", - overparen: "⏜", - undergroup: "\u23e1", - underparen: "\u23dd", - overleftrightarrow: "\u2194", - underleftrightarrow: "\u2194", - xleftrightarrow: "\u2194", - Overrightarrow: "\u21d2", - xRightarrow: "\u21d2", - overleftharpoon: "\u21bc", - xleftharpoonup: "\u21bc", - overrightharpoon: "\u21c0", - xrightharpoonup: "\u21c0", - xLeftarrow: "\u21d0", - xLeftrightarrow: "\u21d4", - xhookleftarrow: "\u21a9", - xhookrightarrow: "\u21aa", - xmapsto: "\u21a6", - xrightharpoondown: "\u21c1", - xleftharpoondown: "\u21bd", - xtwoheadleftarrow: "\u219e", - xtwoheadrightarrow: "\u21a0", - xlongequal: "=", - xrightleftarrows: "\u21c4", - yields: "\u2192", - yieldsLeft: "\u2190", - mesomerism: "\u2194", - longrightharpoonup: "\u21c0", - longleftharpoondown: "\u21bd", - eqrightharpoonup: "\u21c0", - eqleftharpoondown: "\u21bd", - "\\cdrightarrow": "\u2192", - "\\cdleftarrow": "\u2190", - "\\cdlongequal": "=" -}; - -const mathMLnode = function(label) { - const child = new mathMLTree.TextNode(stretchyCodePoint[label.slice(1)]); - const node = new mathMLTree.MathNode("mo", [child]); - node.setAttribute("stretchy", "true"); - return node -}; - -var stretchy = { - mathMLnode -}; - -/** - * This file holds a list of all no-argument functions and single-character - * symbols (like 'a' or ';'). - * - * For each of the symbols, there are two properties they can have: - * - group (required): the ParseNode group type the symbol should have (i.e. - "textord", "mathord", etc). - * - replace: the character that this symbol or function should be - * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi - * character in the main font). - * - * The outermost map in the table indicates what mode the symbols should be - * accepted in (e.g. "math" or "text"). - */ - -// Some of these have a "-token" suffix since these are also used as `ParseNode` -// types for raw text tokens, and we want to avoid conflicts with higher-level -// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by -// looking up the `symbols` map. -const ATOMS = { - bin: 1, - close: 1, - inner: 1, - open: 1, - punct: 1, - rel: 1 -}; -const NON_ATOMS = { - "accent-token": 1, - mathord: 1, - "op-token": 1, - spacing: 1, - textord: 1 -}; - -const symbols = { - math: {}, - text: {} -}; - -/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ -function defineSymbol(mode, group, replace, name, acceptUnicodeChar) { - symbols[mode][name] = { group, replace }; - - if (acceptUnicodeChar && replace) { - symbols[mode][replace] = symbols[mode][name]; - } -} - -// Some abbreviations for commonly used strings. -// This helps minify the code, and also spotting typos using jshint. - -// modes: -const math = "math"; -const text = "text"; - -// groups: -const accent = "accent-token"; -const bin = "bin"; -const close = "close"; -const inner = "inner"; -const mathord = "mathord"; -const op = "op-token"; -const open = "open"; -const punct = "punct"; -const rel = "rel"; -const spacing = "spacing"; -const textord = "textord"; - -// Now comes the symbol table - -// Relation Symbols -defineSymbol(math, rel, "\u2261", "\\equiv", true); -defineSymbol(math, rel, "\u227a", "\\prec", true); -defineSymbol(math, rel, "\u227b", "\\succ", true); -defineSymbol(math, rel, "\u223c", "\\sim", true); -defineSymbol(math, rel, "\u27c2", "\\perp", true); -defineSymbol(math, rel, "\u2aaf", "\\preceq", true); -defineSymbol(math, rel, "\u2ab0", "\\succeq", true); -defineSymbol(math, rel, "\u2243", "\\simeq", true); -defineSymbol(math, rel, "\u224c", "\\backcong", true); -defineSymbol(math, rel, "|", "\\mid", true); -defineSymbol(math, rel, "\u226a", "\\ll", true); -defineSymbol(math, rel, "\u226b", "\\gg", true); -defineSymbol(math, rel, "\u224d", "\\asymp", true); -defineSymbol(math, rel, "\u2225", "\\parallel"); -defineSymbol(math, rel, "\u22c8", "\\bowtie", true); -defineSymbol(math, rel, "\u2323", "\\smile", true); -defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true); -defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true); -defineSymbol(math, rel, "\u2250", "\\doteq", true); -defineSymbol(math, rel, "\u2322", "\\frown", true); -defineSymbol(math, rel, "\u220b", "\\ni", true); -defineSymbol(math, rel, "\u220c", "\\notni", true); -defineSymbol(math, rel, "\u221d", "\\propto", true); -defineSymbol(math, rel, "\u22a2", "\\vdash", true); -defineSymbol(math, rel, "\u22a3", "\\dashv", true); -defineSymbol(math, rel, "\u220b", "\\owns"); -defineSymbol(math, rel, "\u2258", "\\arceq", true); -defineSymbol(math, rel, "\u2259", "\\wedgeq", true); -defineSymbol(math, rel, "\u225a", "\\veeeq", true); -defineSymbol(math, rel, "\u225b", "\\stareq", true); -defineSymbol(math, rel, "\u225d", "\\eqdef", true); -defineSymbol(math, rel, "\u225e", "\\measeq", true); -defineSymbol(math, rel, "\u225f", "\\questeq", true); -defineSymbol(math, rel, "\u2260", "\\ne", true); -defineSymbol(math, rel, "\u2260", "\\neq"); -// mathtools.sty -defineSymbol(math, rel, "\u2237", "\\dblcolon", true); -defineSymbol(math, rel, "\u2254", "\\coloneqq", true); -defineSymbol(math, rel, "\u2255", "\\eqqcolon", true); -defineSymbol(math, rel, "\u2239", "\\eqcolon", true); -defineSymbol(math, rel, "\u2A74", "\\Coloneqq", true); - -// Punctuation -defineSymbol(math, punct, "\u002e", "\\ldotp"); -defineSymbol(math, punct, "\u00b7", "\\cdotp"); - -// Misc Symbols -defineSymbol(math, textord, "\u0023", "\\#"); -defineSymbol(text, textord, "\u0023", "\\#"); -defineSymbol(math, textord, "\u0026", "\\&"); -defineSymbol(text, textord, "\u0026", "\\&"); -defineSymbol(math, textord, "\u2135", "\\aleph", true); -defineSymbol(math, textord, "\u2200", "\\forall", true); -defineSymbol(math, textord, "\u210f", "\\hbar", true); -defineSymbol(math, textord, "\u2203", "\\exists", true); -defineSymbol(math, textord, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\AA", true); -defineSymbol(text, textord, "Å", "\\AA", true); -defineSymbol(math, textord, "\u2663", "\\clubsuit", true); -defineSymbol(math, textord, "\u2667", "\\varclubsuit", true); -defineSymbol(math, textord, "\u2118", "\\wp", true); -defineSymbol(math, textord, "\u266f", "\\sharp", true); -defineSymbol(math, textord, "\u2662", "\\diamondsuit", true); -defineSymbol(math, textord, "\u2666", "\\vardiamondsuit", true); -defineSymbol(math, textord, "\u211c", "\\Re", true); -defineSymbol(math, textord, "\u2661", "\\heartsuit", true); -defineSymbol(math, textord, "\u2665", "\\varheartsuit", true); -defineSymbol(math, textord, "\u2111", "\\Im", true); -defineSymbol(math, textord, "\u2660", "\\spadesuit", true); -defineSymbol(math, textord, "\u2664", "\\varspadesuit", true); -defineSymbol(math, textord, "\u2640", "\\female", true); -defineSymbol(math, textord, "\u2642", "\\male", true); -defineSymbol(math, textord, "\u00a7", "\\S", true); -defineSymbol(text, textord, "\u00a7", "\\S"); -defineSymbol(math, textord, "\u00b6", "\\P", true); -defineSymbol(text, textord, "\u00b6", "\\P"); -defineSymbol(text, textord, "\u263a", "\\smiley", true); -defineSymbol(math, textord, "\u263a", "\\smiley", true); - -// Math and Text -defineSymbol(math, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\textdagger"); -defineSymbol(math, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\textdaggerdbl"); - -// Large Delimiters -defineSymbol(math, close, "\u23b1", "\\rmoustache", true); -defineSymbol(math, open, "\u23b0", "\\lmoustache", true); -defineSymbol(math, close, "\u27ef", "\\rgroup", true); -defineSymbol(math, open, "\u27ee", "\\lgroup", true); - -// Binary Operators -defineSymbol(math, bin, "\u2213", "\\mp", true); -defineSymbol(math, bin, "\u2296", "\\ominus", true); -defineSymbol(math, bin, "\u228e", "\\uplus", true); -defineSymbol(math, bin, "\u2293", "\\sqcap", true); -defineSymbol(math, bin, "\u2217", "\\ast"); -defineSymbol(math, bin, "\u2294", "\\sqcup", true); -defineSymbol(math, bin, "\u25ef", "\\bigcirc", true); -defineSymbol(math, bin, "\u2219", "\\bullet", true); -defineSymbol(math, bin, "\u2021", "\\ddagger"); -defineSymbol(math, bin, "\u2240", "\\wr", true); -defineSymbol(math, bin, "\u2a3f", "\\amalg"); -defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath - -// Arrow Symbols -defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true); -defineSymbol(math, rel, "\u21d0", "\\Leftarrow", true); -defineSymbol(math, rel, "\u27f8", "\\Longleftarrow", true); -defineSymbol(math, rel, "\u27f6", "\\longrightarrow", true); -defineSymbol(math, rel, "\u21d2", "\\Rightarrow", true); -defineSymbol(math, rel, "\u27f9", "\\Longrightarrow", true); -defineSymbol(math, rel, "\u2194", "\\leftrightarrow", true); -defineSymbol(math, rel, "\u27f7", "\\longleftrightarrow", true); -defineSymbol(math, rel, "\u21d4", "\\Leftrightarrow", true); -defineSymbol(math, rel, "\u27fa", "\\Longleftrightarrow", true); -defineSymbol(math, rel, "\u21a6", "\\mapsto", true); -defineSymbol(math, rel, "\u27fc", "\\longmapsto", true); -defineSymbol(math, rel, "\u2197", "\\nearrow", true); -defineSymbol(math, rel, "\u21a9", "\\hookleftarrow", true); -defineSymbol(math, rel, "\u21aa", "\\hookrightarrow", true); -defineSymbol(math, rel, "\u2198", "\\searrow", true); -defineSymbol(math, rel, "\u21bc", "\\leftharpoonup", true); -defineSymbol(math, rel, "\u21c0", "\\rightharpoonup", true); -defineSymbol(math, rel, "\u2199", "\\swarrow", true); -defineSymbol(math, rel, "\u21bd", "\\leftharpoondown", true); -defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true); -defineSymbol(math, rel, "\u2196", "\\nwarrow", true); -defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true); -defineSymbol(math, mathord, "\u21af", "\\lightning", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); - -// AMS Negated Binary Relations -defineSymbol(math, rel, "\u226e", "\\nless", true); -// Symbol names preceeded by "@" each have a corresponding macro. -defineSymbol(math, rel, "\u2a87", "\\lneq", true); -defineSymbol(math, rel, "\u2268", "\\lneqq", true); -defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq"); -defineSymbol(math, rel, "\u22e6", "\\lnsim", true); -defineSymbol(math, rel, "\u2a89", "\\lnapprox", true); -defineSymbol(math, rel, "\u2280", "\\nprec", true); -// unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e0", "\\npreceq", true); -defineSymbol(math, rel, "\u22e8", "\\precnsim", true); -defineSymbol(math, rel, "\u2ab9", "\\precnapprox", true); -defineSymbol(math, rel, "\u2241", "\\nsim", true); -defineSymbol(math, rel, "\u2224", "\\nmid", true); -defineSymbol(math, rel, "\u2224", "\\nshortmid"); -defineSymbol(math, rel, "\u22ac", "\\nvdash", true); -defineSymbol(math, rel, "\u22ad", "\\nvDash", true); -defineSymbol(math, rel, "\u22ea", "\\ntriangleleft"); -defineSymbol(math, rel, "\u22ec", "\\ntrianglelefteq", true); -defineSymbol(math, rel, "\u2284", "\\nsubset", true); -defineSymbol(math, rel, "\u2285", "\\nsupset", true); -defineSymbol(math, rel, "\u228a", "\\subsetneq", true); -defineSymbol(math, rel, "\u228a\ufe00", "\\varsubsetneq"); -defineSymbol(math, rel, "\u2acb", "\\subsetneqq", true); -defineSymbol(math, rel, "\u2acb\ufe00", "\\varsubsetneqq"); -defineSymbol(math, rel, "\u226f", "\\ngtr", true); -defineSymbol(math, rel, "\u2a88", "\\gneq", true); -defineSymbol(math, rel, "\u2269", "\\gneqq", true); -defineSymbol(math, rel, "\u2269\ufe00", "\\gvertneqq"); -defineSymbol(math, rel, "\u22e7", "\\gnsim", true); -defineSymbol(math, rel, "\u2a8a", "\\gnapprox", true); -defineSymbol(math, rel, "\u2281", "\\nsucc", true); -// unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e1", "\\nsucceq", true); -defineSymbol(math, rel, "\u22e9", "\\succnsim", true); -defineSymbol(math, rel, "\u2aba", "\\succnapprox", true); -// unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u2246", "\\ncong", true); -defineSymbol(math, rel, "\u2226", "\\nparallel", true); -defineSymbol(math, rel, "\u2226", "\\nshortparallel"); -defineSymbol(math, rel, "\u22af", "\\nVDash", true); -defineSymbol(math, rel, "\u22eb", "\\ntriangleright"); -defineSymbol(math, rel, "\u22ed", "\\ntrianglerighteq", true); -defineSymbol(math, rel, "\u228b", "\\supsetneq", true); -defineSymbol(math, rel, "\u228b", "\\varsupsetneq"); -defineSymbol(math, rel, "\u2acc", "\\supsetneqq", true); -defineSymbol(math, rel, "\u2acc\ufe00", "\\varsupsetneqq"); -defineSymbol(math, rel, "\u22ae", "\\nVdash", true); -defineSymbol(math, rel, "\u2ab5", "\\precneqq", true); -defineSymbol(math, rel, "\u2ab6", "\\succneqq", true); -defineSymbol(math, bin, "\u22b4", "\\unlhd"); -defineSymbol(math, bin, "\u22b5", "\\unrhd"); - -// AMS Negated Arrows -defineSymbol(math, rel, "\u219a", "\\nleftarrow", true); -defineSymbol(math, rel, "\u219b", "\\nrightarrow", true); -defineSymbol(math, rel, "\u21cd", "\\nLeftarrow", true); -defineSymbol(math, rel, "\u21cf", "\\nRightarrow", true); -defineSymbol(math, rel, "\u21ae", "\\nleftrightarrow", true); -defineSymbol(math, rel, "\u21ce", "\\nLeftrightarrow", true); - -// AMS Misc -defineSymbol(math, rel, "\u25b3", "\\vartriangle"); -defineSymbol(math, textord, "\u210f", "\\hslash"); -defineSymbol(math, textord, "\u25bd", "\\triangledown"); -defineSymbol(math, textord, "\u25ca", "\\lozenge"); -defineSymbol(math, textord, "\u24c8", "\\circledS"); -defineSymbol(math, textord, "\u00ae", "\\circledR", true); -defineSymbol(text, textord, "\u00ae", "\\circledR"); -defineSymbol(text, textord, "\u00ae", "\\textregistered"); -defineSymbol(math, textord, "\u2221", "\\measuredangle", true); -defineSymbol(math, textord, "\u2204", "\\nexists"); -defineSymbol(math, textord, "\u2127", "\\mho"); -defineSymbol(math, textord, "\u2132", "\\Finv", true); -defineSymbol(math, textord, "\u2141", "\\Game", true); -defineSymbol(math, textord, "\u2035", "\\backprime"); -defineSymbol(math, textord, "\u25b2", "\\blacktriangle"); -defineSymbol(math, textord, "\u25bc", "\\blacktriangledown"); -defineSymbol(math, textord, "\u25a0", "\\blacksquare"); -defineSymbol(math, textord, "\u29eb", "\\blacklozenge"); -defineSymbol(math, textord, "\u2605", "\\bigstar"); -defineSymbol(math, textord, "\u2222", "\\sphericalangle", true); -defineSymbol(math, textord, "\u2201", "\\complement", true); -// unicode-math maps U+F0 to \matheth. We map to AMS function \eth -defineSymbol(math, textord, "\u00f0", "\\eth", true); -defineSymbol(text, textord, "\u00f0", "\u00f0"); -defineSymbol(math, textord, "\u2571", "\\diagup"); -defineSymbol(math, textord, "\u2572", "\\diagdown"); -defineSymbol(math, textord, "\u25a1", "\\square"); -defineSymbol(math, textord, "\u25a1", "\\Box"); -defineSymbol(math, textord, "\u25ca", "\\Diamond"); -// unicode-math maps U+A5 to \mathyen. We map to AMS function \yen -defineSymbol(math, textord, "\u00a5", "\\yen", true); -defineSymbol(text, textord, "\u00a5", "\\yen", true); -defineSymbol(math, textord, "\u2713", "\\checkmark", true); -defineSymbol(text, textord, "\u2713", "\\checkmark"); -defineSymbol(math, textord, "\u2717", "\\ballotx", true); -defineSymbol(text, textord, "\u2717", "\\ballotx"); -defineSymbol(text, textord, "\u2022", "\\textbullet"); - -// AMS Hebrew -defineSymbol(math, textord, "\u2136", "\\beth", true); -defineSymbol(math, textord, "\u2138", "\\daleth", true); -defineSymbol(math, textord, "\u2137", "\\gimel", true); - -// AMS Greek -defineSymbol(math, textord, "\u03dd", "\\digamma", true); -defineSymbol(math, textord, "\u03f0", "\\varkappa"); - -// AMS Delimiters -defineSymbol(math, open, "\u231C", "\\ulcorner", true); -defineSymbol(math, close, "\u231D", "\\urcorner", true); -defineSymbol(math, open, "\u231E", "\\llcorner", true); -defineSymbol(math, close, "\u231F", "\\lrcorner", true); - -// AMS Binary Relations -defineSymbol(math, rel, "\u2266", "\\leqq", true); -defineSymbol(math, rel, "\u2a7d", "\\leqslant", true); -defineSymbol(math, rel, "\u2a95", "\\eqslantless", true); -defineSymbol(math, rel, "\u2272", "\\lesssim", true); -defineSymbol(math, rel, "\u2a85", "\\lessapprox", true); -defineSymbol(math, rel, "\u224a", "\\approxeq", true); -defineSymbol(math, bin, "\u22d6", "\\lessdot"); -defineSymbol(math, rel, "\u22d8", "\\lll", true); -defineSymbol(math, rel, "\u2276", "\\lessgtr", true); -defineSymbol(math, rel, "\u22da", "\\lesseqgtr", true); -defineSymbol(math, rel, "\u2a8b", "\\lesseqqgtr", true); -defineSymbol(math, rel, "\u2251", "\\doteqdot"); -defineSymbol(math, rel, "\u2253", "\\risingdotseq", true); -defineSymbol(math, rel, "\u2252", "\\fallingdotseq", true); -defineSymbol(math, rel, "\u223d", "\\backsim", true); -defineSymbol(math, rel, "\u22cd", "\\backsimeq", true); -defineSymbol(math, rel, "\u2ac5", "\\subseteqq", true); -defineSymbol(math, rel, "\u22d0", "\\Subset", true); -defineSymbol(math, rel, "\u228f", "\\sqsubset", true); -defineSymbol(math, rel, "\u227c", "\\preccurlyeq", true); -defineSymbol(math, rel, "\u22de", "\\curlyeqprec", true); -defineSymbol(math, rel, "\u227e", "\\precsim", true); -defineSymbol(math, rel, "\u2ab7", "\\precapprox", true); -defineSymbol(math, rel, "\u22b2", "\\vartriangleleft"); -defineSymbol(math, rel, "\u22b4", "\\trianglelefteq"); -defineSymbol(math, rel, "\u22a8", "\\vDash", true); -defineSymbol(math, rel, "\u22aa", "\\Vvdash", true); -defineSymbol(math, rel, "\u2323", "\\smallsmile"); -defineSymbol(math, rel, "\u2322", "\\smallfrown"); -defineSymbol(math, rel, "\u224f", "\\bumpeq", true); -defineSymbol(math, rel, "\u224e", "\\Bumpeq", true); -defineSymbol(math, rel, "\u2267", "\\geqq", true); -defineSymbol(math, rel, "\u2a7e", "\\geqslant", true); -defineSymbol(math, rel, "\u2a96", "\\eqslantgtr", true); -defineSymbol(math, rel, "\u2273", "\\gtrsim", true); -defineSymbol(math, rel, "\u2a86", "\\gtrapprox", true); -defineSymbol(math, bin, "\u22d7", "\\gtrdot"); -defineSymbol(math, rel, "\u22d9", "\\ggg", true); -defineSymbol(math, rel, "\u2277", "\\gtrless", true); -defineSymbol(math, rel, "\u22db", "\\gtreqless", true); -defineSymbol(math, rel, "\u2a8c", "\\gtreqqless", true); -defineSymbol(math, rel, "\u2256", "\\eqcirc", true); -defineSymbol(math, rel, "\u2257", "\\circeq", true); -defineSymbol(math, rel, "\u225c", "\\triangleq", true); -defineSymbol(math, rel, "\u223c", "\\thicksim"); -defineSymbol(math, rel, "\u2248", "\\thickapprox"); -defineSymbol(math, rel, "\u2ac6", "\\supseteqq", true); -defineSymbol(math, rel, "\u22d1", "\\Supset", true); -defineSymbol(math, rel, "\u2290", "\\sqsupset", true); -defineSymbol(math, rel, "\u227d", "\\succcurlyeq", true); -defineSymbol(math, rel, "\u22df", "\\curlyeqsucc", true); -defineSymbol(math, rel, "\u227f", "\\succsim", true); -defineSymbol(math, rel, "\u2ab8", "\\succapprox", true); -defineSymbol(math, rel, "\u22b3", "\\vartriangleright"); -defineSymbol(math, rel, "\u22b5", "\\trianglerighteq"); -defineSymbol(math, rel, "\u22a9", "\\Vdash", true); -defineSymbol(math, rel, "\u2223", "\\shortmid"); -defineSymbol(math, rel, "\u2225", "\\shortparallel"); -defineSymbol(math, rel, "\u226c", "\\between", true); -defineSymbol(math, rel, "\u22d4", "\\pitchfork", true); -defineSymbol(math, rel, "\u221d", "\\varpropto"); -defineSymbol(math, rel, "\u25c0", "\\blacktriangleleft"); -// unicode-math says that \therefore is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2234", "\\therefore", true); -defineSymbol(math, rel, "\u220d", "\\backepsilon"); -defineSymbol(math, rel, "\u25b6", "\\blacktriangleright"); -// unicode-math says that \because is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2235", "\\because", true); -defineSymbol(math, rel, "\u22d8", "\\llless"); -defineSymbol(math, rel, "\u22d9", "\\gggtr"); -defineSymbol(math, bin, "\u22b2", "\\lhd"); -defineSymbol(math, bin, "\u22b3", "\\rhd"); -defineSymbol(math, rel, "\u2242", "\\eqsim", true); -defineSymbol(math, rel, "\u22c8", "\\Join"); -defineSymbol(math, rel, "\u2251", "\\Doteq", true); -defineSymbol(math, rel, "\u297d", "\\strictif", true); -defineSymbol(math, rel, "\u297c", "\\strictfi", true); - -// AMS Binary Operators -defineSymbol(math, bin, "\u2214", "\\dotplus", true); -defineSymbol(math, bin, "\u2216", "\\smallsetminus"); -defineSymbol(math, bin, "\u22d2", "\\Cap", true); -defineSymbol(math, bin, "\u22d3", "\\Cup", true); -defineSymbol(math, bin, "\u2a5e", "\\doublebarwedge", true); -defineSymbol(math, bin, "\u229f", "\\boxminus", true); -defineSymbol(math, bin, "\u229e", "\\boxplus", true); -defineSymbol(math, bin, "\u22c7", "\\divideontimes", true); -defineSymbol(math, bin, "\u22c9", "\\ltimes", true); -defineSymbol(math, bin, "\u22ca", "\\rtimes", true); -defineSymbol(math, bin, "\u22cb", "\\leftthreetimes", true); -defineSymbol(math, bin, "\u22cc", "\\rightthreetimes", true); -defineSymbol(math, bin, "\u22cf", "\\curlywedge", true); -defineSymbol(math, bin, "\u22ce", "\\curlyvee", true); -defineSymbol(math, bin, "\u229d", "\\circleddash", true); -defineSymbol(math, bin, "\u229b", "\\circledast", true); -defineSymbol(math, bin, "\u22ba", "\\intercal", true); -defineSymbol(math, bin, "\u22d2", "\\doublecap"); -defineSymbol(math, bin, "\u22d3", "\\doublecup"); -defineSymbol(math, bin, "\u22a0", "\\boxtimes", true); - -// AMS Arrows -// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. -// We'll map it to AMS function \dashrightarrow. It produces the same atom. -defineSymbol(math, rel, "\u21e2", "\\dashrightarrow", true); -// unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21e0", "\\dashleftarrow", true); -defineSymbol(math, rel, "\u21c7", "\\leftleftarrows", true); -defineSymbol(math, rel, "\u21c6", "\\leftrightarrows", true); -defineSymbol(math, rel, "\u21da", "\\Lleftarrow", true); -defineSymbol(math, rel, "\u219e", "\\twoheadleftarrow", true); -defineSymbol(math, rel, "\u21a2", "\\leftarrowtail", true); -defineSymbol(math, rel, "\u21ab", "\\looparrowleft", true); -defineSymbol(math, rel, "\u21cb", "\\leftrightharpoons", true); -defineSymbol(math, rel, "\u21b6", "\\curvearrowleft", true); -// unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21ba", "\\circlearrowleft", true); -defineSymbol(math, rel, "\u21b0", "\\Lsh", true); -defineSymbol(math, rel, "\u21c8", "\\upuparrows", true); -defineSymbol(math, rel, "\u21bf", "\\upharpoonleft", true); -defineSymbol(math, rel, "\u21c3", "\\downharpoonleft", true); -defineSymbol(math, rel, "\u22b6", "\\origof", true); -defineSymbol(math, rel, "\u22b7", "\\imageof", true); -defineSymbol(math, rel, "\u22b8", "\\multimap", true); -defineSymbol(math, rel, "\u21ad", "\\leftrightsquigarrow", true); -defineSymbol(math, rel, "\u21c9", "\\rightrightarrows", true); -defineSymbol(math, rel, "\u21c4", "\\rightleftarrows", true); -defineSymbol(math, rel, "\u21a0", "\\twoheadrightarrow", true); -defineSymbol(math, rel, "\u21a3", "\\rightarrowtail", true); -defineSymbol(math, rel, "\u21ac", "\\looparrowright", true); -defineSymbol(math, rel, "\u21b7", "\\curvearrowright", true); -// unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21bb", "\\circlearrowright", true); -defineSymbol(math, rel, "\u21b1", "\\Rsh", true); -defineSymbol(math, rel, "\u21ca", "\\downdownarrows", true); -defineSymbol(math, rel, "\u21be", "\\upharpoonright", true); -defineSymbol(math, rel, "\u21c2", "\\downharpoonright", true); -defineSymbol(math, rel, "\u21dd", "\\rightsquigarrow", true); -defineSymbol(math, rel, "\u21dd", "\\leadsto"); -defineSymbol(math, rel, "\u21db", "\\Rrightarrow", true); -defineSymbol(math, rel, "\u21be", "\\restriction"); - -defineSymbol(math, textord, "\u2018", "`"); -defineSymbol(math, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\textdollar"); -defineSymbol(math, textord, "%", "\\%"); -defineSymbol(text, textord, "%", "\\%"); -defineSymbol(math, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\textunderscore"); -defineSymbol(text, textord, "\u2423", "\\textvisiblespace", true); -defineSymbol(math, textord, "\u2220", "\\angle", true); -defineSymbol(math, textord, "\u221e", "\\infty", true); -defineSymbol(math, textord, "\u2032", "\\prime"); -defineSymbol(math, textord, "\u25b3", "\\triangle"); -defineSymbol(text, textord, "\u0391", "\\Alpha", true); -defineSymbol(text, textord, "\u0392", "\\Beta", true); -defineSymbol(text, textord, "\u0393", "\\Gamma", true); -defineSymbol(text, textord, "\u0394", "\\Delta", true); -defineSymbol(text, textord, "\u0395", "\\Epsilon", true); -defineSymbol(text, textord, "\u0396", "\\Zeta", true); -defineSymbol(text, textord, "\u0397", "\\Eta", true); -defineSymbol(text, textord, "\u0398", "\\Theta", true); -defineSymbol(text, textord, "\u0399", "\\Iota", true); -defineSymbol(text, textord, "\u039a", "\\Kappa", true); -defineSymbol(text, textord, "\u039b", "\\Lambda", true); -defineSymbol(text, textord, "\u039c", "\\Mu", true); -defineSymbol(text, textord, "\u039d", "\\Nu", true); -defineSymbol(text, textord, "\u039e", "\\Xi", true); -defineSymbol(text, textord, "\u039f", "\\Omicron", true); -defineSymbol(text, textord, "\u03a0", "\\Pi", true); -defineSymbol(text, textord, "\u03a1", "\\Rho", true); -defineSymbol(text, textord, "\u03a3", "\\Sigma", true); -defineSymbol(text, textord, "\u03a4", "\\Tau", true); -defineSymbol(text, textord, "\u03a5", "\\Upsilon", true); -defineSymbol(text, textord, "\u03a6", "\\Phi", true); -defineSymbol(text, textord, "\u03a7", "\\Chi", true); -defineSymbol(text, textord, "\u03a8", "\\Psi", true); -defineSymbol(text, textord, "\u03a9", "\\Omega", true); -defineSymbol(math, mathord, "\u0391", "\\Alpha", true); -defineSymbol(math, mathord, "\u0392", "\\Beta", true); -defineSymbol(math, mathord, "\u0393", "\\Gamma", true); -defineSymbol(math, mathord, "\u0394", "\\Delta", true); -defineSymbol(math, mathord, "\u0395", "\\Epsilon", true); -defineSymbol(math, mathord, "\u0396", "\\Zeta", true); -defineSymbol(math, mathord, "\u0397", "\\Eta", true); -defineSymbol(math, mathord, "\u0398", "\\Theta", true); -defineSymbol(math, mathord, "\u0399", "\\Iota", true); -defineSymbol(math, mathord, "\u039a", "\\Kappa", true); -defineSymbol(math, mathord, "\u039b", "\\Lambda", true); -defineSymbol(math, mathord, "\u039c", "\\Mu", true); -defineSymbol(math, mathord, "\u039d", "\\Nu", true); -defineSymbol(math, mathord, "\u039e", "\\Xi", true); -defineSymbol(math, mathord, "\u039f", "\\Omicron", true); -defineSymbol(math, mathord, "\u03a0", "\\Pi", true); -defineSymbol(math, mathord, "\u03a1", "\\Rho", true); -defineSymbol(math, mathord, "\u03a3", "\\Sigma", true); -defineSymbol(math, mathord, "\u03a4", "\\Tau", true); -defineSymbol(math, mathord, "\u03a5", "\\Upsilon", true); -defineSymbol(math, mathord, "\u03a6", "\\Phi", true); -defineSymbol(math, mathord, "\u03a7", "\\Chi", true); -defineSymbol(math, mathord, "\u03a8", "\\Psi", true); -defineSymbol(math, mathord, "\u03a9", "\\Omega", true); -defineSymbol(math, open, "\u00ac", "\\neg", true); -defineSymbol(math, open, "\u00ac", "\\lnot"); -defineSymbol(math, textord, "\u22a4", "\\top"); -defineSymbol(math, textord, "\u22a5", "\\bot"); -defineSymbol(math, textord, "\u2205", "\\emptyset"); -defineSymbol(math, textord, "\u00f8", "\\varnothing"); -defineSymbol(math, mathord, "\u03b1", "\\alpha", true); -defineSymbol(math, mathord, "\u03b2", "\\beta", true); -defineSymbol(math, mathord, "\u03b3", "\\gamma", true); -defineSymbol(math, mathord, "\u03b4", "\\delta", true); -defineSymbol(math, mathord, "\u03f5", "\\epsilon", true); -defineSymbol(math, mathord, "\u03b6", "\\zeta", true); -defineSymbol(math, mathord, "\u03b7", "\\eta", true); -defineSymbol(math, mathord, "\u03b8", "\\theta", true); -defineSymbol(math, mathord, "\u03b9", "\\iota", true); -defineSymbol(math, mathord, "\u03ba", "\\kappa", true); -defineSymbol(math, mathord, "\u03bb", "\\lambda", true); -defineSymbol(math, mathord, "\u03bc", "\\mu", true); -defineSymbol(math, mathord, "\u03bd", "\\nu", true); -defineSymbol(math, mathord, "\u03be", "\\xi", true); -defineSymbol(math, mathord, "\u03bf", "\\omicron", true); -defineSymbol(math, mathord, "\u03c0", "\\pi", true); -defineSymbol(math, mathord, "\u03c1", "\\rho", true); -defineSymbol(math, mathord, "\u03c3", "\\sigma", true); -defineSymbol(math, mathord, "\u03c4", "\\tau", true); -defineSymbol(math, mathord, "\u03c5", "\\upsilon", true); -defineSymbol(math, mathord, "\u03d5", "\\phi", true); -defineSymbol(math, mathord, "\u03c7", "\\chi", true); -defineSymbol(math, mathord, "\u03c8", "\\psi", true); -defineSymbol(math, mathord, "\u03c9", "\\omega", true); -defineSymbol(math, mathord, "\u03b5", "\\varepsilon", true); -defineSymbol(math, mathord, "\u03d1", "\\vartheta", true); -defineSymbol(math, mathord, "\u03d6", "\\varpi", true); -defineSymbol(math, mathord, "\u03f1", "\\varrho", true); -defineSymbol(math, mathord, "\u03c2", "\\varsigma", true); -defineSymbol(math, mathord, "\u03c6", "\\varphi", true); -defineSymbol(math, mathord, "\u03d8", "\\Coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\varcoppa", true); -defineSymbol(math, mathord, "\u03de", "\\Koppa", true); -defineSymbol(math, mathord, "\u03df", "\\koppa", true); -defineSymbol(math, mathord, "\u03e0", "\\Sampi", true); -defineSymbol(math, mathord, "\u03e1", "\\sampi", true); -defineSymbol(math, mathord, "\u03da", "\\Stigma", true); -defineSymbol(math, mathord, "\u03db", "\\stigma", true); -defineSymbol(math, mathord, "\u2aeb", "\\Bot"); -defineSymbol(math, bin, "\u2217", "\u2217", true); -defineSymbol(math, bin, "+", "+"); -defineSymbol(math, bin, "*", "*"); -defineSymbol(math, bin, "\u2044", "\u2044"); -defineSymbol(math, bin, "\u2212", "-", true); -defineSymbol(math, bin, "\u22c5", "\\cdot", true); -defineSymbol(math, bin, "\u2218", "\\circ", true); -defineSymbol(math, bin, "\u00f7", "\\div", true); -defineSymbol(math, bin, "\u00b1", "\\pm", true); -defineSymbol(math, bin, "\u00d7", "\\times", true); -defineSymbol(math, bin, "\u2229", "\\cap", true); -defineSymbol(math, bin, "\u222a", "\\cup", true); -defineSymbol(math, bin, "\u2216", "\\setminus", true); -defineSymbol(math, bin, "\u2227", "\\land"); -defineSymbol(math, bin, "\u2228", "\\lor"); -defineSymbol(math, bin, "\u2227", "\\wedge", true); -defineSymbol(math, bin, "\u2228", "\\vee", true); -defineSymbol(math, open, "\u27e6", "\\llbracket", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u27e7", "\\rrbracket", true); -defineSymbol(math, open, "\u27e8", "\\langle", true); -defineSymbol(math, open, "|", "\\lvert"); -defineSymbol(math, open, "\u2016", "\\lVert"); -defineSymbol(math, textord, "!", "\\oc"); // cmll package -defineSymbol(math, textord, "?", "\\wn"); -defineSymbol(math, textord, "\u2193", "\\shpos"); -defineSymbol(math, textord, "\u2195", "\\shift"); -defineSymbol(math, textord, "\u2191", "\\shneg"); -defineSymbol(math, close, "?", "?"); -defineSymbol(math, close, "!", "!"); -defineSymbol(math, close, "‼", "‼"); -defineSymbol(math, close, "\u27e9", "\\rangle", true); -defineSymbol(math, close, "|", "\\rvert"); -defineSymbol(math, close, "\u2016", "\\rVert"); -defineSymbol(math, open, "\u2983", "\\lBrace", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u2984", "\\rBrace", true); -defineSymbol(math, rel, "=", "\\equal", true); -defineSymbol(math, rel, ":", ":"); -defineSymbol(math, rel, "\u2248", "\\approx", true); -defineSymbol(math, rel, "\u2245", "\\cong", true); -defineSymbol(math, rel, "\u2265", "\\ge"); -defineSymbol(math, rel, "\u2265", "\\geq", true); -defineSymbol(math, rel, "\u2190", "\\gets"); -defineSymbol(math, rel, ">", "\\gt", true); -defineSymbol(math, rel, "\u2208", "\\in", true); -defineSymbol(math, rel, "\u2209", "\\notin", true); -defineSymbol(math, rel, "\ue020", "\\@not"); -defineSymbol(math, rel, "\u2282", "\\subset", true); -defineSymbol(math, rel, "\u2283", "\\supset", true); -defineSymbol(math, rel, "\u2286", "\\subseteq", true); -defineSymbol(math, rel, "\u2287", "\\supseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteqq"); -defineSymbol(math, rel, "\u2289", "\\nsupseteq", true); -defineSymbol(math, rel, "\u2289", "\\nsupseteqq"); -defineSymbol(math, rel, "\u22a8", "\\models"); -defineSymbol(math, rel, "\u2190", "\\leftarrow", true); -defineSymbol(math, rel, "\u2264", "\\le"); -defineSymbol(math, rel, "\u2264", "\\leq", true); -defineSymbol(math, rel, "<", "\\lt", true); -defineSymbol(math, rel, "\u2192", "\\rightarrow", true); -defineSymbol(math, rel, "\u2192", "\\to"); -defineSymbol(math, rel, "\u2271", "\\ngeq", true); -defineSymbol(math, rel, "\u2271", "\\ngeqq"); -defineSymbol(math, rel, "\u2271", "\\ngeqslant"); -defineSymbol(math, rel, "\u2270", "\\nleq", true); -defineSymbol(math, rel, "\u2270", "\\nleqq"); -defineSymbol(math, rel, "\u2270", "\\nleqslant"); -defineSymbol(math, rel, "\u2aeb", "\\Perp", true); //cmll package -defineSymbol(math, spacing, "\u00a0", "\\ "); -defineSymbol(math, spacing, "\u00a0", "\\space"); -// Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% -defineSymbol(math, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(text, spacing, "\u00a0", "\\ "); -defineSymbol(text, spacing, "\u00a0", " "); -defineSymbol(text, spacing, "\u00a0", "\\space"); -defineSymbol(text, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(math, spacing, null, "\\nobreak"); -defineSymbol(math, spacing, null, "\\allowbreak"); -defineSymbol(math, punct, ",", ","); -defineSymbol(text, punct, ":", ":"); -defineSymbol(math, punct, ";", ";"); -defineSymbol(math, bin, "\u22bc", "\\barwedge", true); -defineSymbol(math, bin, "\u22bb", "\\veebar", true); -defineSymbol(math, bin, "\u2299", "\\odot", true); -defineSymbol(math, bin, "\u2295", "\\oplus", true); -defineSymbol(math, bin, "\u2297", "\\otimes", true); -defineSymbol(math, textord, "\u2202", "\\partial", true); -defineSymbol(math, bin, "\u2298", "\\oslash", true); -defineSymbol(math, bin, "\u229a", "\\circledcirc", true); -defineSymbol(math, bin, "\u22a1", "\\boxdot", true); -defineSymbol(math, bin, "\u25b3", "\\bigtriangleup"); -defineSymbol(math, bin, "\u25bd", "\\bigtriangledown"); -defineSymbol(math, bin, "\u2020", "\\dagger"); -defineSymbol(math, bin, "\u22c4", "\\diamond"); -defineSymbol(math, bin, "\u22c6", "\\star"); -defineSymbol(math, bin, "\u25c3", "\\triangleleft"); -defineSymbol(math, bin, "\u25b9", "\\triangleright"); -defineSymbol(math, open, "{", "\\{"); -defineSymbol(text, textord, "{", "\\{"); -defineSymbol(text, textord, "{", "\\textbraceleft"); -defineSymbol(math, close, "}", "\\}"); -defineSymbol(text, textord, "}", "\\}"); -defineSymbol(text, textord, "}", "\\textbraceright"); -defineSymbol(math, open, "{", "\\lbrace"); -defineSymbol(math, close, "}", "\\rbrace"); -defineSymbol(math, open, "[", "\\lbrack", true); -defineSymbol(text, textord, "[", "\\lbrack", true); -defineSymbol(math, close, "]", "\\rbrack", true); -defineSymbol(text, textord, "]", "\\rbrack", true); -defineSymbol(math, open, "(", "\\lparen", true); -defineSymbol(math, close, ")", "\\rparen", true); -defineSymbol(text, textord, "<", "\\textless", true); // in T1 fontenc -defineSymbol(text, textord, ">", "\\textgreater", true); // in T1 fontenc -defineSymbol(math, open, "\u230a", "\\lfloor", true); -defineSymbol(math, close, "\u230b", "\\rfloor", true); -defineSymbol(math, open, "\u2308", "\\lceil", true); -defineSymbol(math, close, "\u2309", "\\rceil", true); -defineSymbol(math, textord, "\\", "\\backslash"); -defineSymbol(math, textord, "|", "|"); -defineSymbol(math, textord, "|", "\\vert"); -defineSymbol(text, textord, "|", "\\textbar", true); // in T1 fontenc -defineSymbol(math, textord, "\u2016", "\\|"); -defineSymbol(math, textord, "\u2016", "\\Vert"); -defineSymbol(text, textord, "\u2016", "\\textbardbl"); -defineSymbol(text, textord, "~", "\\textasciitilde"); -defineSymbol(text, textord, "\\", "\\textbackslash"); -defineSymbol(text, textord, "^", "\\textasciicircum"); -defineSymbol(math, rel, "\u2191", "\\uparrow", true); -defineSymbol(math, rel, "\u21d1", "\\Uparrow", true); -defineSymbol(math, rel, "\u2193", "\\downarrow", true); -defineSymbol(math, rel, "\u21d3", "\\Downarrow", true); -defineSymbol(math, rel, "\u2195", "\\updownarrow", true); -defineSymbol(math, rel, "\u21d5", "\\Updownarrow", true); -defineSymbol(math, op, "\u2210", "\\coprod"); -defineSymbol(math, op, "\u22c1", "\\bigvee"); -defineSymbol(math, op, "\u22c0", "\\bigwedge"); -defineSymbol(math, op, "\u2a04", "\\biguplus"); -defineSymbol(math, op, "\u22c2", "\\bigcap"); -defineSymbol(math, op, "\u22c3", "\\bigcup"); -defineSymbol(math, op, "\u222b", "\\int"); -defineSymbol(math, op, "\u222b", "\\intop"); -defineSymbol(math, op, "\u222c", "\\iint"); -defineSymbol(math, op, "\u222d", "\\iiint"); -defineSymbol(math, op, "\u220f", "\\prod"); -defineSymbol(math, op, "\u2211", "\\sum"); -defineSymbol(math, op, "\u2a02", "\\bigotimes"); -defineSymbol(math, op, "\u2a01", "\\bigoplus"); -defineSymbol(math, op, "\u2a00", "\\bigodot"); -defineSymbol(math, op, "\u222e", "\\oint"); -defineSymbol(math, op, "\u222f", "\\oiint"); -defineSymbol(math, op, "\u2230", "\\oiiint"); -defineSymbol(math, op, "\u2231", "\\intclockwise"); -defineSymbol(math, op, "\u2232", "\\varointclockwise"); -defineSymbol(math, op, "\u2a0c", "\\iiiint"); -defineSymbol(math, op, "\u2a0d", "\\intbar"); -defineSymbol(math, op, "\u2a0e", "\\intBar"); -defineSymbol(math, op, "\u2a0f", "\\fint"); -defineSymbol(math, op, "\u2a12", "\\rppolint"); -defineSymbol(math, op, "\u2a13", "\\scpolint"); -defineSymbol(math, op, "\u2a15", "\\pointint"); -defineSymbol(math, op, "\u2a16", "\\sqint"); -defineSymbol(math, op, "\u2a17", "\\intlarhk"); -defineSymbol(math, op, "\u2a18", "\\intx"); -defineSymbol(math, op, "\u2a19", "\\intcap"); -defineSymbol(math, op, "\u2a1a", "\\intcup"); -defineSymbol(math, op, "\u2a05", "\\bigsqcap"); -defineSymbol(math, op, "\u2a06", "\\bigsqcup"); -defineSymbol(math, op, "\u222b", "\\smallint"); -defineSymbol(text, inner, "\u2026", "\\textellipsis"); -defineSymbol(math, inner, "\u2026", "\\mathellipsis"); -defineSymbol(text, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u22f0", "\\iddots", true); -defineSymbol(math, inner, "\u22ef", "\\@cdots", true); -defineSymbol(math, inner, "\u22f1", "\\ddots", true); -defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro -defineSymbol(math, accent, "\u02ca", "\\acute"); -defineSymbol(math, accent, "\u0060", "\\grave"); -defineSymbol(math, accent, "\u00a8", "\\ddot"); -defineSymbol(math, accent, "\u20db", "\\dddot"); -defineSymbol(math, accent, "\u20dc", "\\ddddot"); -defineSymbol(math, accent, "\u007e", "\\tilde"); -defineSymbol(math, accent, "\u203e", "\\bar"); -defineSymbol(math, accent, "\u02d8", "\\breve"); -defineSymbol(math, accent, "\u02c7", "\\check"); -defineSymbol(math, accent, "\u005e", "\\hat"); -defineSymbol(math, accent, "\u20d7", "\\vec"); -defineSymbol(math, accent, "\u02d9", "\\dot"); -defineSymbol(math, accent, "\u02da", "\\mathring"); -defineSymbol(math, mathord, "\u0131", "\\imath", true); -defineSymbol(math, mathord, "\u0237", "\\jmath", true); -defineSymbol(math, textord, "\u0131", "\u0131"); -defineSymbol(math, textord, "\u0237", "\u0237"); -defineSymbol(text, textord, "\u0131", "\\i", true); -defineSymbol(text, textord, "\u0237", "\\j", true); -defineSymbol(text, textord, "\u00df", "\\ss", true); -defineSymbol(text, textord, "\u00e6", "\\ae", true); -defineSymbol(text, textord, "\u0153", "\\oe", true); -defineSymbol(text, textord, "\u00f8", "\\o", true); -defineSymbol(math, mathord, "\u00f8", "\\o", true); -defineSymbol(text, textord, "\u00c6", "\\AE", true); -defineSymbol(text, textord, "\u0152", "\\OE", true); -defineSymbol(text, textord, "\u00d8", "\\O", true); -defineSymbol(math, mathord, "\u00d8", "\\O", true); -defineSymbol(text, accent, "\u02ca", "\\'"); // acute -defineSymbol(text, accent, "\u02cb", "\\`"); // grave -defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(text, accent, "\u02dc", "\\~"); // tilde -defineSymbol(text, accent, "\u02c9", "\\="); // macron -defineSymbol(text, accent, "\u02d8", "\\u"); // breve -defineSymbol(text, accent, "\u02d9", "\\."); // dot above -defineSymbol(text, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(text, accent, "\u02da", "\\r"); // ring above -defineSymbol(text, accent, "\u02c7", "\\v"); // caron -defineSymbol(text, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(text, accent, "\u02dd", "\\H"); // double acute -defineSymbol(math, accent, "\u02ca", "\\'"); // acute -defineSymbol(math, accent, "\u02cb", "\\`"); // grave -defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(math, accent, "\u02dc", "\\~"); // tilde -defineSymbol(math, accent, "\u02c9", "\\="); // macron -defineSymbol(math, accent, "\u02d8", "\\u"); // breve -defineSymbol(math, accent, "\u02d9", "\\."); // dot above -defineSymbol(math, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(math, accent, "\u02da", "\\r"); // ring above -defineSymbol(math, accent, "\u02c7", "\\v"); // caron -defineSymbol(math, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(math, accent, "\u02dd", "\\H"); // double acute - -// These ligatures are detected and created in Parser.js's `formLigatures`. -const ligatures = { - "--": true, - "---": true, - "``": true, - "''": true -}; - -defineSymbol(text, textord, "\u2013", "--", true); -defineSymbol(text, textord, "\u2013", "\\textendash"); -defineSymbol(text, textord, "\u2014", "---", true); -defineSymbol(text, textord, "\u2014", "\\textemdash"); -defineSymbol(text, textord, "\u2018", "`", true); -defineSymbol(text, textord, "\u2018", "\\textquoteleft"); -defineSymbol(text, textord, "\u2019", "'", true); -defineSymbol(text, textord, "\u2019", "\\textquoteright"); -defineSymbol(text, textord, "\u201c", "``", true); -defineSymbol(text, textord, "\u201c", "\\textquotedblleft"); -defineSymbol(text, textord, "\u201d", "''", true); -defineSymbol(text, textord, "\u201d", "\\textquotedblright"); -// \degree from gensymb package -defineSymbol(math, textord, "\u00b0", "\\degree", true); -defineSymbol(text, textord, "\u00b0", "\\degree"); -// \textdegree from inputenc package -defineSymbol(text, textord, "\u00b0", "\\textdegree", true); -// TODO: In LaTeX, \pounds can generate a different character in text and math -// mode, but among our fonts, only Main-Regular defines this character "163". -defineSymbol(math, textord, "\u00a3", "\\pounds"); -defineSymbol(math, textord, "\u00a3", "\\mathsterling", true); -defineSymbol(text, textord, "\u00a3", "\\pounds"); -defineSymbol(text, textord, "\u00a3", "\\textsterling", true); -defineSymbol(math, textord, "\u2720", "\\maltese"); -defineSymbol(text, textord, "\u2720", "\\maltese"); -defineSymbol(math, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\texteuro"); -defineSymbol(math, textord, "\u00a9", "\\copyright", true); -defineSymbol(text, textord, "\u00a9", "\\textcopyright"); - -// Italic Greek -defineSymbol(math, textord, "𝛤", "\\varGamma"); -defineSymbol(math, textord, "𝛥", "\\varDelta"); -defineSymbol(math, textord, "𝛩", "\\varTheta"); -defineSymbol(math, textord, "𝛬", "\\varLambda"); -defineSymbol(math, textord, "𝛯", "\\varXi"); -defineSymbol(math, textord, "𝛱", "\\varPi"); -defineSymbol(math, textord, "𝛴", "\\varSigma"); -defineSymbol(math, textord, "𝛶", "\\varUpsilon"); -defineSymbol(math, textord, "𝛷", "\\varPhi"); -defineSymbol(math, textord, "𝛹", "\\varPsi"); -defineSymbol(math, textord, "𝛺", "\\varOmega"); -defineSymbol(text, textord, "𝛤", "\\varGamma"); -defineSymbol(text, textord, "𝛥", "\\varDelta"); -defineSymbol(text, textord, "𝛩", "\\varTheta"); -defineSymbol(text, textord, "𝛬", "\\varLambda"); -defineSymbol(text, textord, "𝛯", "\\varXi"); -defineSymbol(text, textord, "𝛱", "\\varPi"); -defineSymbol(text, textord, "𝛴", "\\varSigma"); -defineSymbol(text, textord, "𝛶", "\\varUpsilon"); -defineSymbol(text, textord, "𝛷", "\\varPhi"); -defineSymbol(text, textord, "𝛹", "\\varPsi"); -defineSymbol(text, textord, "𝛺", "\\varOmega"); - - -// There are lots of symbols which are the same, so we add them in afterwards. -// All of these are textords in math mode -const mathTextSymbols = '0123456789/@."'; -for (let i = 0; i < mathTextSymbols.length; i++) { - const ch = mathTextSymbols.charAt(i); - defineSymbol(math, textord, ch, ch); -} - -// All of these are textords in text mode -const textSymbols = '0123456789!@*()-=+";:?/.,'; -for (let i = 0; i < textSymbols.length; i++) { - const ch = textSymbols.charAt(i); - defineSymbol(text, textord, ch, ch); -} - -// All of these are textords in text mode, and mathords in math mode -const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -for (let i = 0; i < letters.length; i++) { - const ch = letters.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// Some more letters in Unicode Basic Multilingual Plane. -const narrow = "ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ"; -for (let i = 0; i < narrow.length; i++) { - const ch = narrow.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// The next loop loads wide (surrogate pair) characters. -// We support some letters in the Unicode range U+1D400 to U+1D7FF, -// Mathematical Alphanumeric Symbols. -let wideChar = ""; -for (let i = 0; i < letters.length; i++) { - // The hex numbers in the next line are a surrogate pair. - // 0xD835 is the high surrogate for all letters in the range we support. - // 0xDC00 is the low surrogate for bold A. - wideChar = String.fromCharCode(0xd835, 0xdc00 + i); // A-Z a-z bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc34 + i); // A-Z a-z italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc68 + i); // A-Z a-z bold italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd04 + i); // A-Z a-z Fractur - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdda0 + i); // A-Z a-z sans-serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xddd4 + i); // A-Z a-z sans bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde08 + i); // A-Z a-z sans italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde70 + i); // A-Z a-z monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd38 + i); // A-Z a-z double struck - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - const ch = letters.charAt(i); - wideChar = String.fromCharCode(0xd835, 0xdc9c + i); // A-Z a-z calligraphic - defineSymbol(math, mathord, ch, wideChar); - defineSymbol(text, textord, ch, wideChar); -} - -// Next, some wide character numerals -for (let i = 0; i < 10; i++) { - wideChar = String.fromCharCode(0xd835, 0xdfce + i); // 0-9 bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfe2 + i); // 0-9 sans serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfec + i); // 0-9 bold sans - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdff6 + i); // 0-9 monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); -} - -/* - * Neither Firefox nor Chrome support hard line breaks or soft line breaks. - * (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs) - * So Temml has work-arounds for both hard and soft breaks. - * The work-arounds sadly do not work simultaneously. Any top-level hard - * break makes soft line breaks impossible. - * - * Hard breaks are simulated by creating a and putting each line in its own . - * - * To create soft line breaks, Temml avoids using the and tags. - * Then the top level of a element can be occupied by elements, and the browser - * will break after a if the expression extends beyond the container limit. - * - * We want the expression to render with soft line breaks after each top-level binary or - * relational operator, per TeXbook p. 173. So we gather the expression into s so that - * each ends in a binary or relational operator. - * - * Soft line breaks will not work in Chromium and Safari, only Firefox. - * - * Hopefully browsers will someday do their own linebreaking and we will be able to delete - * much of this module. - */ - -function setLineBreaks(expression, isDisplayMode, isAnnotated, color = undefined) { - if (color === undefined) { - // First, make one pass through the expression and split any color nodes. - const upperLimit = expression.length - 1; - for (let i = upperLimit; i >= 0; i--) { - const node = expression[i]; - if (node.type === "mstyle" && node.attributes.mathcolor) { - const color = node.attributes.mathcolor; - const fragment = setLineBreaks(node.children, isDisplayMode, isAnnotated, color); - if (!(fragment.type && fragment.type !== "mtable")) { - expression.splice(i, 1, ...fragment.children); - - } - } - } - } - - const tagName = color ? "mstyle" : "mrow"; - - const mtrs = []; - let mrows = []; - let block = []; - let canBeBIN = false; // The first node cannot be an infix binary operator. - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type && node.type === "mstyle" && node.attributes.mathcolor) { - // Start a new block. (Insert a soft linebreak.) - mrows.push(new mathMLTree.MathNode(tagName, block)); - // Insert the mstyle - mrows.push(node); - block = []; - continue - } - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(new mathMLTree.MathNode(tagName, block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - continue - } - block.push(node); - if (node.type && node.type === "mo" && !isDisplayMode && !isAnnotated) { - // This may be a place for a soft line break. - if (canBeBIN && !node.attributes.form) { - // Check if the following node is a \nobreak text node, e.g. "~"" - const next = i < expression.length - 1 ? expression[i + 1] : null; - let glueIsFreeOfNobreak = true; - if ( - !( - next && - next.type === "mtext" && - next.attributes.linebreak && - next.attributes.linebreak === "nobreak" - ) - ) { - // We may need to start a new block. - // First, put any post-operator glue on same line as operator. - for (let j = i + 1; j < expression.length; j++) { - const nd = expression[j]; - if ( - nd.type && - nd.type === "mspace" && - !(nd.attributes.linebreak && nd.attributes.linebreak === "newline") - ) { - block.push(nd); - i += 1; - if ( - nd.attributes && - nd.attributes.linebreak && - nd.attributes.linebreak === "nobreak" - ) { - glueIsFreeOfNobreak = false; - } - } else { - break; - } - } - } - if (glueIsFreeOfNobreak) { - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - block = []; - } - canBeBIN = false; - } - const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"; - // Any operator that follows an open delimiter is unary. - canBeBIN = !(node.attributes.separator || isOpenDelimiter); - } else { - canBeBIN = true; - } - } - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - const mtr = new mathMLTree.MathNode("mtr", [mtd]); - mtrs.push(mtr); - const mtable = new mathMLTree.MathNode("mtable", mtrs); - if (!isDisplayMode) { - mtable.setAttribute("columnalign", "left"); - mtable.setAttribute("rowspacing", "0em"); - } - return mtable - } - return mathMLTree.newDocumentFragment(mrows); -} - -/** - * This file converts a parse tree into a cooresponding MathML tree. The main - * entry point is the `buildMathML` function, which takes a parse tree from the - * parser. - */ - -/** - * Takes a symbol and converts it into a MathML text node after performing - * optional replacement from symbols.js. - */ -const makeText = function(text, mode, style) { - if ( - symbols[mode][text] && - symbols[mode][text].replace && - text.charCodeAt(0) !== 0xd835 && - !( - Object.prototype.hasOwnProperty.call(ligatures, text) && - style && - ((style.fontFamily && style.fontFamily.slice(4, 6) === "tt") || - (style.font && style.font.slice(4, 6) === "tt")) - ) - ) { - text = symbols[mode][text].replace; - } - - return new mathMLTree.TextNode(text); -}; - -/** - * Wrap the given array of nodes in an node if needed, i.e., - * unless the array has length 1. Always returns a single node. - */ -const makeRow = function(body) { - if (body.length === 1) { - return body[0]; - } else { - return new mathMLTree.MathNode("mrow", body); - } -}; - -const isRel = item => { - return (item.type === "atom" && item.family === "rel") || - (item.type === "mclass" && item.mclass === "mrel") -}; - -/** - * Takes a list of nodes, builds them, and returns a list of the generated - * MathML nodes. Also do a couple chores along the way: - * (1) Suppress spacing when an author wraps an operator w/braces, as in {=}. - * (2) Suppress spacing between two adjacent relations. - */ -const buildExpression = function(expression, style, isOrdgroup) { - if (expression.length === 1) { - const group = buildGroup$1(expression[0], style); - if (isOrdgroup && group instanceof MathNode && group.type === "mo") { - // When TeX writers want to suppress spacing on an operator, - // they often put the operator by itself inside braces. - group.setAttribute("lspace", "0em"); - group.setAttribute("rspace", "0em"); - } - return [group]; - } - - const groups = []; - for (let i = 0; i < expression.length; i++) { - const group = buildGroup$1(expression[i], style); - // Suppress spacing between adjacent relations - if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) { - group.setAttribute("rspace", "0em"); - } - if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) { - group.setAttribute("lspace", "0em"); - } - groups.push(group); - } - return groups; -}; - -/** - * Equivalent to buildExpression, but wraps the elements in an - * if there's more than one. Returns a single node instead of an array. - */ -const buildExpressionRow = function(expression, style, isOrdgroup) { - return makeRow(buildExpression(expression, style, isOrdgroup)); -}; - -/** - * Takes a group from the parser and calls the appropriate groupBuilders function - * on it to produce a MathML node. - */ -const buildGroup$1 = function(group, style) { - if (!group) { - return new mathMLTree.MathNode("mrow"); - } - - if (_mathmlGroupBuilders[group.type]) { - // Call the groupBuilders function - const result = _mathmlGroupBuilders[group.type](group, style); - return result; - } else { - throw new ParseError("Got group of unknown type: '" + group.type + "'"); - } -}; - -const glue = _ => { - const glueNode = new mathMLTree.MathNode("mtd", []); - glueNode.setAttribute("style", "padding: 0;width: 50%;"); - return glueNode -}; - -const taggedExpression = (expression, tag, style, leqno, preventTagLap) => { - tag = buildExpressionRow(tag[0].body, style); - tag = utils.consolidateText(tag); - tag.classes = ["tml-tag"]; - if (!preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - tag.setAttribute((leqno ? "rspace" : "lspace"), "-1width"); - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = leqno - ? [tag, glue(), expression, glue()] - : [glue(), expression, glue(), tag]; - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.setAttribute("width", "100%"); - table.setAttribute("displaystyle", "true"); - return table -}; - -/** - * Takes a full parse tree and settings and builds a MathML representation of - * it. - */ -function buildMathML(tree, texExpression, style, settings) { - // Strip off outer tag wrapper for processing below. - let tag = null; - if (tree.length === 1 && tree[0].type === "tag") { - tag = tree[0].tag; - tree = tree[0].body; - } - - const expression = buildExpression(tree, style); - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - && !(n1.type === "mstyle" && n1.attributes.mathcolor) - ? expression[0] - : setLineBreaks(expression, settings.displayMode, settings.annotate); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno, settings.preventTagLap); - } - - let semantics; - if (settings.annotate) { - // Build a TeX annotation of the source - const annotation = new mathMLTree.MathNode( - "annotation", [new mathMLTree.TextNode(texExpression)]); - annotation.setAttribute("encoding", "application/x-tex"); - semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = settings.annotate - ? new mathMLTree.MathNode("math", [semantics]) - : new mathMLTree.MathNode("math", [wrapper]); - - if (settings.xml) { - math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); - } - if (settings.displayMode) { - math.setAttribute("display", "block"); - } - return math; -} - -const mathmlBuilder$a = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.mathMLnode(group.label) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup$1(group.base, style), accentNode] - ); - - node.setAttribute("accent", "true"); - return node; -}; - -const NON_STRETCHY_ACCENT_REGEX = new RegExp( - [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" - ] - .map((accent) => `\\${accent}`) - .join("|") -); - -// Accents -defineFunction({ - type: "accent", - names: [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring", - "\\overparen", - "\\widecheck", - "\\widehat", - "\\wideparen", - "\\widetilde", - "\\overrightarrow", - "\\overleftarrow", - "\\Overrightarrow", - "\\overleftrightarrow", - "\\overgroup", - "\\overleftharpoon", - "\\overrightharpoon" - ], - props: { - numArgs: 1 - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - - const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); - const isShifty = - !isStretchy || - context.funcName === "\\widehat" || - context.funcName === "\\widetilde" || - context.funcName === "\\widecheck"; - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - isShifty: isShifty, - base: base - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - -// Text-mode accents -defineFunction({ - type: "accent", - names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\c", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"], - props: { - numArgs: 1, - allowedInText: true, - allowedInMath: true, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - const mode = context.parser.mode; - - if (mode === "math" && context.parser.settings.strict) { - // LaTeX only writes a warning. It doesn't stop. We'll issue the same warning. - // eslint-disable-next-line no-console - console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`); - } - - return { - type: "accent", - mode: mode, - label: context.funcName, - isStretchy: false, - isShifty: true, - base: base - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - -defineFunction({ - type: "accentUnder", - names: [ - "\\underleftarrow", - "\\underrightarrow", - "\\underleftrightarrow", - "\\undergroup", - "\\underparen", - "\\utilde" - ], - props: { - numArgs: 1 - }, - handler: ({ parser, funcName }, args) => { - const base = args[0]; - return { - type: "accentUnder", - mode: parser.mode, - label: funcName, - base: base - }; - }, - mathmlBuilder: (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - const node = new mathMLTree.MathNode("munder", [ - buildGroup$1(group.base, style), - accentNode - ]); - node.setAttribute("accentunder", "true"); - return node; - } -}); - -/** - * This file does conversion between units. In particular, it provides - * calculateSize to convert other units into CSS units. - */ - -const ptPerUnit = { - // Convert to CSS (Postscipt) points, not TeX points - // https://en.wikibooks.org/wiki/LaTeX/Lengths and - // https://tex.stackexchange.com/a/8263 - pt: 800 / 803, // convert TeX point to CSS (Postscript) point - pc: (12 * 800) / 803, // pica - dd: ((1238 / 1157) * 800) / 803, // didot - cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot) - nd: ((685 / 642) * 800) / 803, // new didot - nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot) - sp: ((1 / 65536) * 800) / 803, // scaled point (TeX's internal smallest unit) - mm: (25.4 / 72), - cm: (2.54 / 72), - in: (1 / 72), - px: (96 / 72) -}; - -/** - * Determine whether the specified unit (either a string defining the unit - * or a "size" parse node containing a unit field) is valid. - */ -const validUnits = [ - "em", - "ex", - "mu", - "pt", - "mm", - "cm", - "in", - "px", - "bp", - "pc", - "dd", - "cc", - "nd", - "nc", - "sp" -]; - -const validUnit = function(unit) { - if (typeof unit !== "string") { - unit = unit.unit; - } - return validUnits.indexOf(unit) > -1 -}; - -const emScale = styleLevel => { - const scriptLevel = Math.max(styleLevel - 1, 0); - return [1, 0.7, 0.5][scriptLevel] -}; - -/* - * Convert a "size" parse node (with numeric "number" and string "unit" fields, - * as parsed by functions.js argType "size") into a CSS value. - */ -const calculateSize = function(sizeValue, style) { - let number = sizeValue.number; - if (style.maxSize[0] < 0 && number > 0) { - return { number: 0, unit: "em" } - } - const unit = sizeValue.unit; - switch (unit) { - case "mm": - case "cm": - case "in": - case "px": { - const numInCssPts = number * ptPerUnit[unit]; - if (numInCssPts > style.maxSize[1]) { - return { number: style.maxSize[1], unit: "pt" } - } - return { number, unit }; // absolute CSS units. - } - case "em": - case "ex": { - // In TeX, em and ex do not change size in \scriptstyle. - if (unit === "ex") { number *= 0.431; } - number = Math.min(number / emScale(style.level), style.maxSize[0]); - return { number: utils.round(number), unit: "em" }; - } - case "bp": { - if (number > style.maxSize[1]) { number = style.maxSize[1]; } - return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch). - } - case "pt": - case "pc": - case "dd": - case "cc": - case "nd": - case "nc": - case "sp": { - number = Math.min(number * ptPerUnit[unit], style.maxSize[1]); - return { number: utils.round(number), unit: "pt" } - } - case "mu": { - number = Math.min(number / 18, style.maxSize[0]); - return { number: utils.round(number), unit: "em" } - } - default: - throw new ParseError("Invalid unit: '" + unit + "'") - } -}; - -// Helper functions -const paddedNode = (group, width, lspace = "0.3em") => { - const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); - node.setAttribute("width", width); - node.setAttribute("lspace", lspace); - return node; -}; - -const labelSize = (size, scriptLevel) => (size / emScale(scriptLevel)).toFixed(4) + "em"; - -const munderoverNode = (name, body, below, style) => { - const arrowNode = stretchy.mathMLnode(name); - // Is this the short part of a mhchem equilibrium arrow? - const isEq = name.slice(1, 3) === "eq"; - const minWidth = name.charAt(1) === "x" - ? "1.75" // mathtools extensible arrows are 1.75em long - : name.slice(2, 4) === "cd" - ? "3.0" // cd package arrows - : isEq - ? "1.0" // The shorter harpoon of a mhchem equilibrium arrow - : "2.0"; // other mhchem arrows - arrowNode.setAttribute("minsize", String(minWidth) + "em"); - arrowNode.setAttribute("lspace", "0"); - arrowNode.setAttribute("rspace", (isEq ? "0.5em" : "0")); - - // upper and lower labels are set to scriptlevel by MathML - // So we have to adjust our dimensions accordingly. - const labelStyle = style.withLevel(style.level < 2 ? 2 : 3); - const emptyLabelWidth = labelSize(minWidth, labelStyle.level); - const lspace = labelSize((isEq ? 0 : 0.3), labelStyle.level); - let widthAdder = labelSize((isEq ? -0.4 : 0.6), labelStyle.level); - if (widthAdder.charAt(0) !== "-") { widthAdder = "+" + widthAdder; } - - const upperNode = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)) - ? paddedNode(buildGroup$1(body, labelStyle), widthAdder, lspace) - // Since Firefox does not recognize minsize set on the arrow, - // create an upper node w/correct width. - : paddedNode(null, emptyLabelWidth, "0"); - const lowerNode = (below && below.body && - (below.body.body || below.body.length > 0)) - ? paddedNode(buildGroup$1(below, labelStyle), widthAdder, lspace) - : paddedNode(null, emptyLabelWidth, "0"); - const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - return node -}; - -// Stretchy arrows with an optional argument -defineFunction({ - type: "xArrow", - names: [ - "\\xleftarrow", - "\\xrightarrow", - "\\xLeftarrow", - "\\xRightarrow", - "\\xleftrightarrow", - "\\xLeftrightarrow", - "\\xhookleftarrow", - "\\xhookrightarrow", - "\\xmapsto", - "\\xrightharpoondown", - "\\xrightharpoonup", - "\\xleftharpoondown", - "\\xleftharpoonup", - "\\xlongequal", - "\\xtwoheadrightarrow", - "\\xtwoheadleftarrow", - // The next 7 functions are here only to support mhchem - "\\yields", - "\\yieldsLeft", - "\\mesomerism", - "\\longrightharpoonup", - "\\longleftharpoondown", - // The next 3 functions are here only to support the {CD} environment. - "\\\\cdrightarrow", - "\\\\cdleftarrow", - "\\\\cdlongequal" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - return { - type: "xArrow", - mode: parser.mode, - name: funcName, - body: args[0], - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - // Build the arrow and its labels. - const node = munderoverNode(group.name, group.body, group.below, style); - // Create operator spacing for a relation. - const wrapper = new mathMLTree.MathNode("mpadded", [node]); - wrapper.setAttribute("lspace", "0.2778em"); - wrapper.setAttribute("width", "+0.5556em"); - return wrapper - } -}); - -const arrowComponent = { - "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"], - "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"], - "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"], - "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"], - // The next three all get the same harpoon glyphs. Only the lengths and paddings differ. - "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"], - "\\equilibriumRight": ["\\longrightharpoonup", "\\eqleftharpoondown"], - "\\equilibriumLeft": ["\\eqrightharpoonup", "\\longleftharpoondown"] -}; - -// Browsers are not good at stretching a glyph that contains a pair of stacked arrows such as ⇄. -// So we stack a pair of single arrows. -defineFunction({ - type: "stackedArrow", - names: [ - "\\xtofrom", // expfeil - "\\xleftrightharpoons", // mathtools - "\\xrightleftharpoons", // mathtools - "\\yieldsLeftRight", // mhchem - "\\equilibrium", // mhchem - "\\equilibriumRight", - "\\equilibriumLeft" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - const lowerArrowBody = args[0] - ? { - type: "hphantom", - mode: parser.mode, - body: args[0] - } - : null; - const upperArrowBelow = optArgs[0] - ? { - type: "hphantom", - mode: parser.mode, - body: optArgs[0] - } - : null; - return { - type: "stackedArrow", - mode: parser.mode, - name: funcName, - body: args[0], - upperArrowBelow, - lowerArrowBody, - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - const topLabel = arrowComponent[group.name][0]; - const botLabel = arrowComponent[group.name][1]; - const topArrow = munderoverNode(topLabel, group.body, group.upperArrowBelow, style); - const botArrow = munderoverNode(botLabel, group.lowerArrowBody, group.below, style); - let wrapper; - - const raiseNode = new mathMLTree.MathNode("mpadded", [topArrow]); - raiseNode.setAttribute("voffset", "0.3em"); - raiseNode.setAttribute("height", "+0.3em"); - raiseNode.setAttribute("depth", "-0.3em"); - // One of the arrows is given ~zero width. so the other has the same horzontal alignment. - if (group.name === "\\equilibriumLeft") { - const botNode = new mathMLTree.MathNode("mpadded", [botArrow]); - botNode.setAttribute("width", "0.5em"); - wrapper = new mathMLTree.MathNode("mpadded", [botNode, raiseNode]); - } else { - raiseNode.setAttribute("width", (group.name === "\\equilibriumRight" ? "0.5em" : "0")); - wrapper = new mathMLTree.MathNode("mpadded", [raiseNode, botArrow]); - } - - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("width", "+0.5556em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - wrapper.setAttribute("lspace", "0.2778em"); - return wrapper - } -}); - -defineFunction({ - type: "cancelto", - names: ["\\cancelto"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "cancelto", - mode: parser.mode, - value: args[0], - expression: args[1] - }; - }, - mathmlBuilder(group, style) { - const value = new mathMLTree.MathNode( - "mpadded", - [buildGroup$1(group.value, style)] - ); - value.setAttribute("depth", `-0.1em`); - value.setAttribute("height", `+0.1em`); - value.setAttribute("voffset", `0.1em`); - - const expression = new mathMLTree.MathNode( - "menclose", - [buildGroup$1(group.expression, style)] - ); - expression.setAttribute("notation", `updiagonalarrow`); - - return new mathMLTree.MathNode("msup", [expression, value]) - } -}); - -/** - * Asserts that the node is of the given type and returns it with stricter - * typing. Throws if the node's type does not match. - */ -function assertNodeType(node, type) { - if (!node || node.type !== type) { - throw new Error( - `Expected node of type ${type}, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return node; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function assertSymbolNodeType(node) { - const typedNode = checkSymbolNodeType(node); - if (!typedNode) { - throw new Error( - `Expected node of symbol group type, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return typedNode; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function checkSymbolNodeType(node) { - if (node && (node.type === "atom" || - Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) { - return node; - } - return null; -} - -const cdArrowFunctionName = { - ">": "\\\\cdrightarrow", - "<": "\\\\cdleftarrow", - "=": "\\\\cdlongequal", - A: "\\uparrow", - V: "\\downarrow", - "|": "\\Vert", - ".": "no arrow" -}; - -const newCell = () => { - // Create an empty cell, to be filled below with parse nodes. - return { type: "styling", body: [], mode: "math", scriptLevel: "display" }; -}; - -const isStartOfArrow = (node) => { - return node.type === "textord" && node.text === "@"; -}; - -const isLabelEnd = (node, endChar) => { - return (node.type === "mathord" || node.type === "atom") && node.text === endChar; -}; - -function cdArrow(arrowChar, labels, parser) { - // Return a parse tree of an arrow and its labels. - // This acts in a way similar to a macro expansion. - const funcName = cdArrowFunctionName[arrowChar]; - switch (funcName) { - case "\\\\cdrightarrow": - case "\\\\cdleftarrow": - return parser.callFunction(funcName, [labels[0]], [labels[1]]); - case "\\uparrow": - case "\\downarrow": { - const leftLabel = parser.callFunction("\\\\cdleft", [labels[0]], []); - const bareArrow = { - type: "atom", - text: funcName, - mode: "math", - family: "rel" - }; - const sizedArrow = parser.callFunction("\\Big", [bareArrow], []); - const rightLabel = parser.callFunction("\\\\cdright", [labels[1]], []); - const arrowGroup = { - type: "ordgroup", - mode: "math", - body: [leftLabel, sizedArrow, rightLabel] - }; - return parser.callFunction("\\\\cdparent", [arrowGroup], []); - } - case "\\\\cdlongequal": - return parser.callFunction("\\\\cdlongequal", [], []); - case "\\Vert": { - const arrow = { type: "textord", text: "\\Vert", mode: "math" }; - return parser.callFunction("\\Big", [arrow], []); - } - default: - return { type: "textord", text: " ", mode: "math" }; - } -} - -function parseCD(parser) { - // Get the array's parse nodes with \\ temporarily mapped to \cr. - const parsedRows = []; - parser.gullet.beginGroup(); - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - parser.gullet.beginGroup(); - while (true) { // eslint-disable-line no-constant-condition - // Get the parse nodes for the next row. - parsedRows.push(parser.parseExpression(false, "\\\\")); - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - const next = parser.fetch().text; - if (next === "&" || next === "\\\\") { - parser.consume(); - } else if (next === "\\end") { - if (parsedRows[parsedRows.length - 1].length === 0) { - parsedRows.pop(); // final row ended in \\ - } - break; - } else { - throw new ParseError("Expected \\\\ or \\cr or \\end", parser.nextToken); - } - } - - let row = []; - const body = [row]; - - // Loop thru the parse nodes. Collect them into cells and arrows. - for (let i = 0; i < parsedRows.length; i++) { - // Start a new row. - const rowNodes = parsedRows[i]; - // Create the first cell. - let cell = newCell(); - - for (let j = 0; j < rowNodes.length; j++) { - if (!isStartOfArrow(rowNodes[j])) { - // If a parseNode is not an arrow, it goes into a cell. - cell.body.push(rowNodes[j]); - } else { - // Parse node j is an "@", the start of an arrow. - // Before starting on the arrow, push the cell into `row`. - row.push(cell); - - // Now collect parseNodes into an arrow. - // The character after "@" defines the arrow type. - j += 1; - const arrowChar = assertSymbolNodeType(rowNodes[j]).text; - - // Create two empty label nodes. We may or may not use them. - const labels = new Array(2); - labels[0] = { type: "ordgroup", mode: "math", body: [] }; - labels[1] = { type: "ordgroup", mode: "math", body: [] }; - - // Process the arrow. - if ("=|.".indexOf(arrowChar) > -1) ; else if ("<>AV".indexOf(arrowChar) > -1) { - // Four arrows, `@>>>`, `@<<<`, `@AAA`, and `@VVV`, each take - // two optional labels. E.g. the right-point arrow syntax is - // really: @>{optional label}>{optional label}> - // Collect parseNodes into labels. - for (let labelNum = 0; labelNum < 2; labelNum++) { - let inLabel = true; - for (let k = j + 1; k < rowNodes.length; k++) { - if (isLabelEnd(rowNodes[k], arrowChar)) { - inLabel = false; - j = k; - break; - } - if (isStartOfArrow(rowNodes[k])) { - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[k] - ); - } - - labels[labelNum].body.push(rowNodes[k]); - } - if (inLabel) { - // isLabelEnd never returned a true. - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[j] - ); - } - } - } else { - throw new ParseError(`Expected one of "<>AV=|." after @.`); - } - - // Now join the arrow to its labels. - const arrow = cdArrow(arrowChar, labels, parser); - - // Wrap the arrow in a styling node - row.push(arrow); - // In CD's syntax, cells are implicit. That is, everything that - // is not an arrow gets collected into a cell. So create an empty - // cell now. It will collect upcoming parseNodes. - cell = newCell(); - } - } - if (i % 2 === 0) { - // Even-numbered rows consist of: cell, arrow, cell, arrow, ... cell - // The last cell is not yet pushed into `row`, so: - row.push(cell); - } else { - // Odd-numbered rows consist of: vert arrow, empty cell, ... vert arrow - // Remove the empty cell that was placed at the beginning of `row`. - row.shift(); - } - row = []; - body.push(row); - } - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - // define column separation. - const cols = new Array(body[0].length).fill({ - type: "align", - align: "c" - }); - - return { - type: "array", - mode: "math", - body, - arraystretch: 1, - addJot: true, - rowGaps: [null], - cols, - colSeparationType: "CD", - hLinesBeforeRow: new Array(body.length + 1).fill([]) - }; -} - -// The functions below are not available for general use. -// They are here only for internal use by the {CD} environment in placing labels -// next to vertical arrows. - -// We don't need any such functions for horizontal arrows because we can reuse -// the functionality that already exists for extensible arrows. - -defineFunction({ - type: "cdlabel", - names: ["\\\\cdleft", "\\\\cdright"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "cdlabel", - mode: parser.mode, - side: funcName.slice(4), - label: args[0] - }; - }, - mathmlBuilder(group, style) { - let label = new mathMLTree.MathNode("mrow", [buildGroup$1(group.label, style)]); - label = new mathMLTree.MathNode("mpadded", [label]); - label.setAttribute("width", "0"); - if (group.side === "left") { - label.setAttribute("lspace", "-1width"); - } - // We have to guess at vertical alignment. We know the arrow is 1.8em tall, - // But we don't know the height or depth of the label. - label.setAttribute("voffset", "0.7em"); - label = new mathMLTree.MathNode("mstyle", [label]); - label.setAttribute("displaystyle", "false"); - label.setAttribute("scriptlevel", "1"); - return label; - } -}); - -defineFunction({ - type: "cdlabelparent", - names: ["\\\\cdparent"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - return { - type: "cdlabelparent", - mode: parser.mode, - fragment: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow", [buildGroup$1(group.fragment, style)]); - } -}); - -// \@char is an internal function that takes a grouped decimal argument like -// {123} and converts into symbol with code 123. It is used by the *macro* -// \char defined in macros.js. -defineFunction({ - type: "textord", - names: ["\\@char"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser, token }, args) { - const arg = assertNodeType(args[0], "ordgroup"); - const group = arg.body; - let number = ""; - for (let i = 0; i < group.length; i++) { - const node = assertNodeType(group[i], "textord"); - number += node.text; - } - const code = parseInt(number); - if (isNaN(code)) { - throw new ParseError(`\\@char has non-numeric argument ${number}`, token) - } - return { - type: "textord", - mode: parser.mode, - text: String.fromCodePoint(code) - } - } -}); - -// Helpers -const htmlRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6})$/i; -const htmlOrNameRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i; -const RGBregEx = /^ *\d{1,3} *(?:, *\d{1,3} *){2}$/; -const rgbRegEx = /^ *[10](?:\.\d*)? *(?:, *[10](?:\.\d*)? *){2}$/; -const xcolorHtmlRegEx = /^[a-f0-9]{6}$/i; -const toHex = num => { - let str = num.toString(16); - if (str.length === 1) { str = "0" + str; } - return str -}; - -// Colors from Tables 4.1 and 4.2 of the xcolor package. -// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx. -// Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable -// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274. -const xcolors = JSON.parse(`{ - "Apricot": "#ffb484", - "Aquamarine": "#08b4bc", - "Bittersweet": "#c84c14", - "blue": "#0000FF", - "Blue": "#303494", - "BlueGreen": "#08b4bc", - "BlueViolet": "#503c94", - "BrickRed": "#b8341c", - "brown": "#BF8040", - "Brown": "#802404", - "BurntOrange": "#f8941c", - "CadetBlue": "#78749c", - "CarnationPink": "#f884b4", - "Cerulean": "#08a4e4", - "CornflowerBlue": "#40ace4", - "cyan": "#00FFFF", - "Cyan": "#08acec", - "Dandelion": "#ffbc44", - "darkgray": "#404040", - "DarkOrchid": "#a8548c", - "Emerald": "#08ac9c", - "ForestGreen": "#089c54", - "Fuchsia": "#90348c", - "Goldenrod": "#ffdc44", - "gray": "#808080", - "Gray": "#98949c", - "green": "#00FF00", - "Green": "#08a44c", - "GreenYellow": "#e0e474", - "JungleGreen": "#08ac9c", - "Lavender": "#f89cc4", - "lightgray": "#c0c0c0", - "lime": "#BFFF00", - "LimeGreen": "#90c43c", - "magenta": "#FF00FF", - "Magenta": "#f0048c", - "Mahogany": "#b0341c", - "Maroon": "#b03434", - "Melon": "#f89c7c", - "MidnightBlue": "#086494", - "Mulberry": "#b03c94", - "NavyBlue": "#086cbc", - "olive": "#7F7F00", - "OliveGreen": "#407c34", - "orange": "#FF8000", - "Orange": "#f8843c", - "OrangeRed": "#f0145c", - "Orchid": "#b074ac", - "Peach": "#f8945c", - "Periwinkle": "#8074bc", - "PineGreen": "#088c74", - "pink": "#ff7f7f", - "Plum": "#98248c", - "ProcessBlue": "#08b4ec", - "purple": "#BF0040", - "Purple": "#a0449c", - "RawSienna": "#983c04", - "red": "#ff0000", - "Red": "#f01c24", - "RedOrange": "#f86434", - "RedViolet": "#a0246c", - "Rhodamine": "#f0549c", - "Royallue": "#0874bc", - "RoyalPurple": "#683c9c", - "RubineRed": "#f0047c", - "Salmon": "#f8948c", - "SeaGreen": "#30bc9c", - "Sepia": "#701404", - "SkyBlue": "#48c4dc", - "SpringGreen": "#c8dc64", - "Tan": "#e09c74", - "teal": "#007F7F", - "TealBlue": "#08acb4", - "Thistle": "#d884b4", - "Turquoise": "#08b4cc", - "violet": "#800080", - "Violet": "#60449c", - "VioletRed": "#f054a4", - "WildStrawberry": "#f0246c", - "yellow": "#FFFF00", - "Yellow": "#fff404", - "YellowGreen": "#98cc6c", - "YellowOrange": "#ffa41c" -}`); - -const colorFromSpec = (model, spec) => { - let color = ""; - if (model === "HTML") { - if (!htmlRegEx.test(spec)) { - throw new ParseError("Invalid HTML input.") - } - color = spec; - } else if (model === "RGB") { - if (!RGBregEx.test(spec)) { - throw new ParseError("Invalid RGB input.") - } - spec.split(",").map(e => { color += toHex(Number(e.trim())); }); - } else { - if (!rgbRegEx.test(spec)) { - throw new ParseError("Invalid rbg input.") - } - spec.split(",").map(e => { - const num = Number(e.trim()); - if (num > 1) { throw new ParseError("Color rgb input must be < 1.") } - color += toHex((num * 255)); - }); - } - if (color.charAt(0) !== "#") { color = "#" + color; } - return color -}; - -const validateColor = (color, macros, token) => { - const macroName = `\\\\color@${color}`; // from \defineColor. - const match = htmlOrNameRegEx.exec(color); - if (!match) { throw new ParseError("Invalid color: '" + color + "'", token) } - // We allow a 6-digit HTML color spec without a leading "#". - // This follows the xcolor package's HTML color model. - // Predefined color names are all missed by this RegEx pattern. - if (xcolorHtmlRegEx.test(color)) { - return "#" + color - } else if (color.charAt(0) === "#") { - return color - } else if (macros.has(macroName)) { - color = macros.get(macroName).tokens[0].text; - } else if (xcolors[color]) { - color = xcolors[color]; - } - return color -}; - -const mathmlBuilder$9 = (group, style) => { - const inner = buildExpression(group.body, style.withColor(group.color)); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("mathcolor", group.color); - // Wrap w/. We get better operator spacing that way. - return new mathMLTree.MathNode("mrow", [node]) -}; - -defineFunction({ - type: "color", - names: ["\\textcolor"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "original"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token); - } - const body = args[1]; - return { - type: "color", - mode: parser.mode, - color, - body: ordargument(body) - } - }, - mathmlBuilder: mathmlBuilder$9 -}); - -defineFunction({ - type: "color", - names: ["\\color"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw"] - }, - handler({ parser, token }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros, token); - } - - // Set macro \current@color in current namespace to store the current - // color, mimicking the behavior of color.sty. - // This is currently used just to correctly color a \right - // that follows a \color command. - parser.gullet.macros.set("\\current@color", color); - - // Parse out the implicit body that should be colored. - // Since \color nodes should not be nested, break on \color. - const body = parser.parseExpression(true, "\\color"); - - return { - type: "color", - mode: parser.mode, - color, - body - } - }, - mathmlBuilder: mathmlBuilder$9 -}); - -defineFunction({ - type: "color", - names: ["\\definecolor"], - props: { - numArgs: 3, - allowedInText: true, - argTypes: ["raw", "raw", "raw"] - }, - handler({ parser, funcName, token }, args) { - const name = assertNodeType(args[0], "raw").string; - if (!/^[A-Za-z]+$/.test(name)) { - throw new ParseError("Color name must be latin letters.", token) - } - const model = assertNodeType(args[1], "raw").string; - if (!["HTML", "RGB", "rgb"].includes(model)) { - throw new ParseError("Color model must be HTML, RGB, or rgb.", token) - } - const spec = assertNodeType(args[2], "raw").string; - const color = colorFromSpec(model, spec); - parser.gullet.macros.set(`\\\\color@${name}`, { tokens: [{ text: color }], numArgs: 0 }); - return { type: "internal", mode: parser.mode } - } - // No mathmlBuilder. The point of \definecolor is to set a macro. -}); - -// Row breaks within tabular environments, and line breaks at top level - -// \DeclareRobustCommand\\{...\@xnewline} -defineFunction({ - type: "cr", - names: ["\\\\"], - props: { - numArgs: 0, - numOptionalArgs: 1, - argTypes: ["size"], - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = optArgs[0]; - const newLine = !parser.settings.displayMode; - return { - type: "cr", - mode: parser.mode, - newLine, - size: size && assertNodeType(size, "size").value - } - }, - - // The following builder is called only at the top level, - // not within tabular/array environments. - - mathmlBuilder(group, style) { - // MathML 3.0 calls for newline to occur in an or an . - // Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.linebreaking - const node = new mathMLTree.MathNode("mo"); - if (group.newLine) { - node.setAttribute("linebreak", "newline"); - if (group.size) { - const size = calculateSize(group.size, style); - node.setAttribute("height", size.number + size.unit); - } - } - return node - } -}); - -const checkControlSequence = (tok) => { - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - return name; -}; - -const getRHS = (parser) => { - let tok = parser.gullet.popToken(); - if (tok.text === "=") { - // consume optional equals - tok = parser.gullet.popToken(); - if (tok.text === " ") { - // consume one optional space - tok = parser.gullet.popToken(); - } - } - return tok; -}; - -const letCommand = (parser, name, tok) => { - let macro = parser.gullet.macros.get(tok.text); - if (macro == null) { - // don't expand it later even if a macro with the same name is defined - // e.g., \let\foo=\frac \def\frac{\relax} \frac12 - tok.noexpand = true; - macro = { - tokens: [tok], - numArgs: 0, - // reproduce the same behavior in expansion - unexpandable: !parser.gullet.isExpandable(tok.text) - }; - } - parser.gullet.macros.set(name, macro); -}; - -// Basic support for macro definitions: \def -// -> -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\edef"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let tok = parser.gullet.popToken(); - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - - let numArgs = 0; - let insert; - const delimiters = [[]]; - // contains no braces - while (parser.gullet.future().text !== "{") { - tok = parser.gullet.popToken(); - if (tok.text === "#") { - // If the very last character of the is #, so that - // this # is immediately followed by {, TeX will behave as if the { - // had been inserted at the right end of both the parameter text - // and the replacement text. - if (parser.gullet.future().text === "{") { - insert = parser.gullet.future(); - delimiters[numArgs].push("{"); - break; - } - - // A parameter, the first appearance of # must be followed by 1, - // the next by 2, and so on; up to nine #’s are allowed - tok = parser.gullet.popToken(); - if (!/^[1-9]$/.test(tok.text)) { - throw new ParseError(`Invalid argument number "${tok.text}"`); - } - if (parseInt(tok.text) !== numArgs + 1) { - throw new ParseError(`Argument number "${tok.text}" out of order`); - } - numArgs++; - delimiters.push([]); - } else if (tok.text === "EOF") { - throw new ParseError("Expected a macro definition"); - } else { - delimiters[numArgs].push(tok.text); - } - } - // replacement text, enclosed in '{' and '}' and properly nested - let { tokens } = parser.gullet.consumeArg(); - if (insert) { - tokens.unshift(insert); - } - - if (funcName === "\\edef") { - tokens = parser.gullet.expandTokens(tokens); - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set(name, { tokens, numArgs, delimiters } - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: ["\\let"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.consumeSpaces(); - const tok = getRHS(parser); - letCommand(parser, name, tok); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: ["\\futurelet"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - const middle = parser.gullet.popToken(); - const tok = parser.gullet.popToken(); - letCommand(parser, name, tok); - parser.gullet.pushToken(tok); - parser.gullet.pushToken(middle); - return { type: "internal", mode: parser.mode }; - } -}); - -defineFunction({ - type: "internal", - names: ["\\newcommand", "\\renewcommand", "\\providecommand"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let name = ""; - const tok = parser.gullet.popToken(); - if (tok.text === "{") { - name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.popToken(); - } else { - name = checkControlSequence(tok); - } - - const exists = parser.gullet.isDefined(name); - if (exists && funcName === "\\newcommand") { - throw new ParseError( - `\\newcommand{${name}} attempting to redefine ${name}; use \\renewcommand` - ); - } - if (!exists && funcName === "\\renewcommand") { - throw new ParseError( - `\\renewcommand{${name}} when command ${name} does not yet exist; use \\newcommand` - ); - } - - let numArgs = 0; - if (parser.gullet.future().text === "[") { - let tok = parser.gullet.popToken(); - tok = parser.gullet.popToken(); - if (!/^[0-9]$/.test(tok.text)) { - throw new ParseError(`Invalid number of arguments: "${tok.text}"`); - } - numArgs = parseInt(tok.text); - tok = parser.gullet.popToken(); - if (tok.text !== "]") { - throw new ParseError(`Invalid argument "${tok.text}"`); - } - } - - // replacement text, enclosed in '{' and '}' and properly nested - const { tokens } = parser.gullet.consumeArg(); - - parser.gullet.macros.set(name, { tokens, numArgs }); - - return { type: "internal", mode: parser.mode }; - - } -}); - -// Extra data needed for the delimiter handler down below -const delimiterSizes = { - "\\bigl": { mclass: "mopen", size: 1 }, - "\\Bigl": { mclass: "mopen", size: 2 }, - "\\biggl": { mclass: "mopen", size: 3 }, - "\\Biggl": { mclass: "mopen", size: 4 }, - "\\bigr": { mclass: "mclose", size: 1 }, - "\\Bigr": { mclass: "mclose", size: 2 }, - "\\biggr": { mclass: "mclose", size: 3 }, - "\\Biggr": { mclass: "mclose", size: 4 }, - "\\bigm": { mclass: "mrel", size: 1 }, - "\\Bigm": { mclass: "mrel", size: 2 }, - "\\biggm": { mclass: "mrel", size: 3 }, - "\\Biggm": { mclass: "mrel", size: 4 }, - "\\big": { mclass: "mord", size: 1 }, - "\\Big": { mclass: "mord", size: 2 }, - "\\bigg": { mclass: "mord", size: 3 }, - "\\Bigg": { mclass: "mord", size: 4 } -}; - -const delimiters = [ - "(", - "\\lparen", - ")", - "\\rparen", - "[", - "\\lbrack", - "]", - "\\rbrack", - "\\{", - "\\lbrace", - "\\}", - "\\rbrace", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lt", - "\\gt", - "\\lvert", - "\\rvert", - "\\lVert", - "\\rVert", - "\\lgroup", - "\\rgroup", - "\u27ee", - "\u27ef", - "\\lmoustache", - "\\rmoustache", - "\u23b0", - "\u23b1", - "\\llbracket", - "\\rrbracket", - "\u27e6", - "\u27e6", - "\\lBrace", - "\\rBrace", - "\u2983", - "\u2984", - "/", - "\\backslash", - "|", - "\\vert", - "\\|", - "\\Vert", - "\\uparrow", - "\\Uparrow", - "\\downarrow", - "\\Downarrow", - "\\updownarrow", - "\\Updownarrow", - "." -]; - -// Metrics of the different sizes. Found by looking at TeX's output of -// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ -// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. -const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; - -// Delimiter functions -function checkDelimiter(delim, context) { - if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") { - // Recover "/" from the zero spacing group. (See macros.js) - delim = { type: "textord", text: "/", mode: "math" }; - } - const symDelim = checkSymbolNodeType(delim); - if (symDelim && utils.contains(delimiters, symDelim.text)) { - // If a character is not in the MathML operator dictionary, it will not stretch. - // Replace such characters w/characters that will stretch. - if (utils.contains(["<", "\\lt"], symDelim.text)) { symDelim.text = "⟨"; } - if (utils.contains([">", "\\gt"], symDelim.text)) { symDelim.text = "⟩"; } - if (symDelim.text === "/") { symDelim.text = "\u2215"; } - if (symDelim.text === "\\backslash") { symDelim.text = "\u2216"; } - return symDelim; - } else if (symDelim) { - throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim); - } else { - throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim); - } -} - -defineFunction({ - type: "delimsizing", - names: [ - "\\bigl", - "\\Bigl", - "\\biggl", - "\\Biggl", - "\\bigr", - "\\Bigr", - "\\biggr", - "\\Biggr", - "\\bigm", - "\\Bigm", - "\\biggm", - "\\Biggm", - "\\big", - "\\Big", - "\\bigg", - "\\Bigg" - ], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - return { - type: "delimsizing", - mode: context.parser.mode, - size: delimiterSizes[context.funcName].size, - mclass: delimiterSizes[context.funcName].mclass, - delim: delim.text - }; - }, - mathmlBuilder: (group) => { - const children = []; - - if (group.delim === ".") { group.delim = ""; } - children.push(makeText(group.delim, group.mode)); - - const node = new mathMLTree.MathNode("mo", children); - - if (group.mclass === "mopen" || group.mclass === "mclose") { - // Only some of the delimsizing functions act as fences, and they - // return "mopen" or "mclose" mclass. - node.setAttribute("fence", "true"); - } else { - // Explicitly disable fencing if it's not a fence, to override the - // defaults. - node.setAttribute("fence", "false"); - } - if (group.delim === "\u2216") { - // \backslash is not in the operator dictionary, - // so we have to explicitly set stretchy to true. - node.setAttribute("stretchy", "true"); - } - - node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox. - node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em"); - node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em"); - - return node; - } -}); - -function assertParsed(group) { - if (!group.body) { - throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); - } -} - -defineFunction({ - type: "leftright-right", - names: ["\\right"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - // \left case below triggers parsing of \right in - // `const right = parser.parseFunction();` - // uses this return value. - const color = context.parser.gullet.macros.get("\\current@color"); - if (color && typeof color !== "string") { - throw new ParseError("\\current@color set to non-string in \\right"); - } - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text, - color // undefined if not set via \color - }; - } -}); - -defineFunction({ - type: "leftright", - names: ["\\left"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - const parser = context.parser; - // Parse out the implicit body - ++parser.leftrightDepth; - // parseExpression stops before '\\right' - const body = parser.parseExpression(false); - --parser.leftrightDepth; - // Check the next token - parser.expect("\\right", false); - const right = assertNodeType(parser.parseFunction(), "leftright-right"); - return { - type: "leftright", - mode: parser.mode, - body, - left: delim.text, - right: right.delim, - rightColor: right.color - }; - }, - mathmlBuilder: (group, style) => { - assertParsed(group); - const inner = buildExpression(group.body, style); - - if (group.left === ".") { group.left = ""; } - const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]); - leftNode.setAttribute("fence", "true"); - leftNode.setAttribute("form", "prefix"); - if (group.left === "\u2216") { leftNode.setAttribute("stretchy", "true"); } - inner.unshift(leftNode); - - if (group.right === ".") { group.right = ""; } - const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]); - rightNode.setAttribute("fence", "true"); - rightNode.setAttribute("form", "postfix"); - if (group.right === "\u2216") { rightNode.setAttribute("stretchy", "true"); } - if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor); } - inner.push(rightNode); - - return makeRow(inner); - } -}); - -defineFunction({ - type: "middle", - names: ["\\middle"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - if (!context.parser.leftrightDepth) { - throw new ParseError("\\middle without preceding \\left", delim); - } - - return { - type: "middle", - mode: context.parser.mode, - delim: delim.text - }; - }, - mathmlBuilder: (group, style) => { - const textNode = makeText(group.delim, group.mode); - const middleNode = new mathMLTree.MathNode("mo", [textNode]); - middleNode.setAttribute("fence", "true"); - // MathML gives 5/18em spacing to each element. - // \middle should get delimiter spacing instead. - middleNode.setAttribute("lspace", "0.05em"); - middleNode.setAttribute("rspace", "0.05em"); - return middleNode; - } -}); - -const mathmlBuilder$8 = (group, style) => { - const node = new mathMLTree.MathNode( - group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", - [buildGroup$1(group.body, style)] - ); - switch (group.label) { - case "\\cancel": - node.setAttribute("notation", "updiagonalstrike"); - break; - case "\\bcancel": - node.setAttribute("notation", "downdiagonalstrike"); - break; - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break; - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break; - case "\\sout": - node.setAttribute("notation", "horizontalstrike"); - break; - case "\\fbox": - node.setAttribute("notation", "box"); - break; - case "\\angl": - node.setAttribute("notation", "actuarial"); - break; - case "\\fcolorbox": - case "\\colorbox": { - // doesn't have a good notation option for \colorbox. - // So use instead. Set some attributes that come - // included with . - const fboxsep = 3; // 3 pt from LaTeX source2e - node.setAttribute("width", `+${2 * fboxsep}pt`); - node.setAttribute("height", `+${2 * fboxsep}pt`); - node.setAttribute("lspace", `${fboxsep}pt`); // - node.setAttribute("voffset", `${fboxsep}pt`); - if (group.label === "\\fcolorbox") { - node.setAttribute("style", "border: 0.06em solid " + String(group.borderColor)); - } - break; - } - case "\\xcancel": - node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); - break; - } - if (group.backgroundColor) { - node.setAttribute("mathbackground", group.backgroundColor); - } - return node; -}; - -defineFunction({ - type: "enclose", - names: ["\\colorbox"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - const body = args[1]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor: color, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -defineFunction({ - type: "enclose", - names: ["\\fcolorbox"], - props: { - numArgs: 3, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let borderColor = ""; - let backgroundColor; - if (model) { - const borderSpec = assertNodeType(args[0], "raw").string; - const backgroundSpec = assertNodeType(args[0], "raw").string; - borderColor = colorFromSpec(model, borderSpec); - backgroundColor = colorFromSpec(model, backgroundSpec); - } else { - borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros); - } - const body = args[2]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor, - borderColor, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -defineFunction({ - type: "enclose", - names: ["\\fbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "enclose", - mode: parser.mode, - label: "\\fbox", - body: args[0] - }; - } -}); - -defineFunction({ - type: "enclose", - names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\angl", "\\phase", "\\longdiv"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - body - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -/** - * All registered environments. - * `environments.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `environments.js`. - */ -const _environments = {}; - -function defineEnvironment({ type, names, props, handler, mathmlBuilder }) { - // Set default values of environments. - const data = { - type, - numArgs: props.numArgs || 0, - allowedInText: false, - numOptionalArgs: 0, - handler - }; - for (let i = 0; i < names.length; ++i) { - _environments[names[i]] = data; - } - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } -} - -// In TeX, there are actually three sets of dimensions, one for each of - -// Math style is not quite the same thing as script level. -const StyleLevel = { - DISPLAY: 0, - TEXT: 1, - SCRIPT: 2, - SCRIPTSCRIPT: 3 -}; - -// Helper functions -function getHLines(parser) { - // Return an array. The array length = number of hlines. - // Each element in the array tells if the line is dashed. - const hlineInfo = []; - parser.consumeSpaces(); - let nxt = parser.fetch().text; - while (nxt === "\\hline" || nxt === "\\hdashline") { - parser.consume(); - hlineInfo.push(nxt === "\\hdashline"); - parser.consumeSpaces(); - nxt = parser.fetch().text; - } - return hlineInfo; -} - -const validateAmsEnvironmentContext = context => { - const settings = context.parser.settings; - if (!settings.displayMode) { - throw new ParseError(`{${context.envName}} can be used only in display mode.`); - } -}; - -const getTag = (group, style, rowNum) => { - let tag; - const tagContents = group.tags.shift(); - if (tagContents) { - // The author has written a \tag or a \notag in this row. - if (tagContents.body) { - tag = buildExpressionRow(tagContents.body, style); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } - } else if (group.colSeparationType === "multline" && - ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) { - // A multiline that does not receive a tag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a post-processor. - tag = new mathMLTree.MathNode("mtext", [], ["tml-eqn"]); - } - if (!group.preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - if (!group.leqno) { tag.setAttribute("lspace", "-1width"); } - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!group.preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - return tag -}; - -/** - * Parse the body of the environment, with rows delimited by \\ and - * columns delimited by &, and create a nested list in row-major order - * with one group per cell. If given an optional argument scriptLevel - * ("text", "display", etc.), then each cell is cast into that scriptLevel. - */ -function parseArray( - parser, - { - hskipBeforeAndAfter, // boolean - addJot, // boolean - cols, // [{ type: string , align: l|c|r|null }] - arraystretch, // number - colSeparationType, // "align" | "alignat" | "gather" | "small" | "CD" | "multline" - addEqnNum, // boolean - singleRow, // boolean - emptySingleRow, // boolean - maxNumCols, // number - leqno // boolean - }, - scriptLevel -) { - parser.gullet.beginGroup(); - if (!singleRow) { - // \cr is equivalent to \\ without the optional size argument (see below) - // TODO: provide helpful error when \cr is used outside array environment - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - } - if (addEqnNum) { - parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // Get current arraystretch if it's not set by the environment - if (arraystretch === undefined || Number.isNaN(arraystretch)) { - const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); - if (stretch == null) { - // Default \arraystretch from lttab.dtx - arraystretch = 1; - } else { - arraystretch = parseFloat(stretch); - if (!arraystretch || arraystretch < 0) { - throw new ParseError(`Invalid \\arraystretch: ${stretch}`); - } - } - } - - // Start group for first cell - parser.gullet.beginGroup(); - - let row = []; - const body = [row]; - const rowGaps = []; - const tags = []; - let rowTag; - const hLinesBeforeRow = []; - - // Test for \hline at the top of the array. - hLinesBeforeRow.push(getHLines(parser)); - - // eslint-disable-next-line no-constant-condition - while (true) { - // Parse each cell in its own group (namespace) - let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\"); - - if (addEqnNum && !rowTag) { - // Check if the author wrote a \tag{} inside this cell. - for (let i = 0; i < cell.length; i++) { - if (cell[i].type === "envTag" || cell[i].type === "noTag") { - // Get the contents of the \text{} nested inside the \env@Tag{} - rowTag = cell[i].type === "envTag" - ? cell.splice(i, 1)[0].body.body[0] - : { body: null }; - break - } - } - } - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - - cell = { - type: "ordgroup", - mode: parser.mode, - body: cell - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (colSeparationType === "split") { - throw new ParseError("The split environment accepts no more than two columns", - parser.nextToken); - } else if (colSeparationType === "array") { - if (parser.settings.strict) { - throw new ParseError("Too few columns " + "specified in the {array} column argument.", - parser.nextToken) - } - } else { - throw new ParseError("The equation environment accepts only one column", - parser.nextToken) - } - } - parser.consume(); - } else if (next === "\\end") { - // Arrays terminate newlines with `\crcr` which consumes a `\cr` if - // the last line is empty. However, AMS environments keep the - // empty row if it's the only one. - // NOTE: Currently, `cell` is the last item added into `row`. - if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) { - body.pop(); - } - if (hLinesBeforeRow.length < body.length + 1) { - hLinesBeforeRow.push([]); - } - break; - } else if (next === "\\\\") { - parser.consume(); - let size; - // \def\Let@{\let\\\math@cr} - // \def\math@cr{...\math@cr@} - // \def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}} - // \def\math@cr@@[#1]{...\math@cr@@@...} - // \def\math@cr@@@{\cr} - if (parser.gullet.future().text !== " ") { - size = parser.parseSizeGroup(true); - } - rowGaps.push(size ? size.value : null); - - tags.push(rowTag); - - // check for \hline(s) following the row separator - hLinesBeforeRow.push(getHLines(parser)); - - row = []; - rowTag = null; - body.push(row); - } else { - throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); - } - } - - // End cell group - parser.gullet.endGroup(); - // End array group defining \cr - parser.gullet.endGroup(); - - tags.push(rowTag); - - return { - type: "array", - mode: parser.mode, - addJot, - arraystretch, - body, - cols, - rowGaps, - hskipBeforeAndAfter, - hLinesBeforeRow, - colSeparationType, - addEqnNum, - scriptLevel, - tags, - leqno, - preventTagLap: parser.settings.preventTagLap - }; -} - -// Decides on a scriptLevel for cells in an array according to whether the given -// environment name starts with the letter 'd'. -function dCellStyle(envName) { - return envName.slice(0, 1) === "d" ? "display" : "text" -} - -const alignMap = { - c: "center ", - l: "left ", - r: "right " -}; - -const mathmlBuilder$7 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - let glue; - if (group.addEqnNum) { - glue = new mathMLTree.MathNode("mtd", [], []); - const glueStyle = "padding: 0;width: " + - (group.colSeparationType === "multline" ? "7.5%" : "50%"); - glue.setAttribute("style", glueStyle); - } - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellStyle = group.scriptLevel === "text" - ? StyleLevel.TEXT - : group.scriptLevel === "script" - ? StyleLevel.SCRIPT - : StyleLevel.DISPLAY; - - for (let j = 0; j < rw.length; j++) { - const mtd = new mathMLTree.MathNode( - "mtd", - [buildGroup$1(rw[j], style.withLevel(cellStyle))] - ); - if (group.colSeparationType === "multline") { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue); - row.push(glue); - const tag = getTag(group, style.withLevel(cellStyle), i); - if (group.leqno) { - row.unshift(tag); - } else { - row.push(tag); - } - } - // If group.addEqnNum, insert a breadcrumb to be found by temmlPostProcess(). - tbl.push(new mathMLTree.MathNode("mtr", row, group.addEqnNum ? ["tml-tageqn"] : [] )); - } - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - // Set column alignment, row spacing, column spacing, and - // array lines by setting attributes on the table element. - - // Set the row spacing. In MathML, we specify a gap distance. - // We do not use rowGap[] because MathML automatically increases - // cell height with the height/depth of the element content. - - // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. - // We simulate this by adding (arraystretch - 1)em to the gap. This - // does a reasonable job of adjusting arrays containing 1 em tall content. - - // The 0.16 and 0.09 values are found emprically. They produce an array - // similar to LaTeX and in which content does not interfere with \hines. - const gap = - group.arraystretch === 0 - ? 0 // {subarray} - : group.arraystretch === 0.5 - ? 0.1 // {smallmatrix} - : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); - table.setAttribute("rowspacing", utils.round(gap) + "em"); - - if (group.addEqnNum || group.colSeparationType === "multline") { - table.setAttribute("width", "100%"); - } - - // MathML table lines go only between cells. - // To place a line on an edge we'll use , if necessary. - let menclose = ""; - let align = ""; - - if (group.cols && group.cols.length > 0) { - // Find column alignment, column spacing, and vertical lines. - const cols = group.cols; - let columnLines = ""; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - if (cols[0].type === "separator") { - menclose += "left "; - iStart = 1; - } - if (cols[cols.length - 1].type === "separator") { - menclose += "right "; - iEnd -= 1; - } - - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - align += alignMap[cols[i].align]; - - if (prevTypeWasAlign) { - columnLines += "none "; - } - prevTypeWasAlign = true; - } else if (cols[i].type === "separator") { - // MathML accepts only single lines between cells. - // So we read only the first of consecutive separators. - if (prevTypeWasAlign) { - columnLines += cols[i].separator === "|" ? "solid " : "dashed "; - prevTypeWasAlign = false; - } - } - } - if (group.addEqnNum) { - align = "left " + align + "right "; // allow for glue cells on each side - align = group.leqno ? "left " + align : align += "right"; // eqn num cell - } - - table.setAttribute("columnalign", align.trim()); - - if (/[sd]/.test(columnLines)) { - table.setAttribute("columnlines", columnLines.trim()); - } - } - - // Set column spacing. - switch (group.colSeparationType) { - case "gather": - case "gathered": - case "alignedat": - case "alignat": - case "alignat*": - table.setAttribute("columnspacing", "0em"); - break - case "small": - table.setAttribute("columnspacing", "0.2778em"); - break - case "CD": - table.setAttribute("columnspacing", "0.5em"); - break - case "align": - case "align*": { - const cols = group.cols || []; - let spacing = group.addEqnNum ? "0em " : ""; - for (let i = 1; i < cols.length; i++) { - spacing += i % 2 ? "0em " : "1em "; - } - if (group.addEqnNum) { spacing += "0em"; } - table.setAttribute("columnspacing", spacing.trim()); - break - } - default: - table.setAttribute("columnspacing", "1em"); - } - - // Address \hline and \hdashline - let rowLines = ""; - const hlines = group.hLinesBeforeRow; - - menclose += hlines[0].length > 0 ? "top " : ""; - menclose += hlines[hlines.length - 1].length > 0 ? "bottom " : ""; - - for (let i = 1; i < hlines.length - 1; i++) { - rowLines += - hlines[i].length === 0 - ? "none " - : // MathML accepts only a single line between rows. Read one element. - hlines[i][0] - ? "dashed " - : "solid "; - } - if (/[sd]/.test(rowLines)) { - table.setAttribute("rowlines", rowLines.trim()); - } - - if (menclose !== "") { - table = new mathMLTree.MathNode("menclose", [table]); - table.setAttribute("notation", menclose.trim()); - } - - if (!Number.isNaN(group.arraystretch) && group.arraystretch < 1) { - // A small array. Wrap in scriptstyle so row gap is not too large. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table; -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addJot: true, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - colSeparationType: context.envName, - maxNumCols: context.envName === "split" ? 2 : undefined, - leqno: context.parser.settings.leqno - }, - "display" - ); - - // Determining number of columns. - // 1. If the first argument is given, we use it as a number of columns, - // and makes sure that each row doesn't exceed that number. - // 2. Otherwise, just count number of columns = maximum number - // of cells in each row ("aligned" mode -- isAligned will be true). - // - // At the same time, prepend empty group {} at beginning of every second - // cell in each row (starting with second cell) so that operators become - // binary. This behavior is implemented in amsmath's \start@aligned. - let numMaths; - let numCols = 0; - if (args[0] && args[0].type === "ordgroup") { - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - const isAligned = !numCols; - res.body.forEach(function(row) { - if (!isAligned) { - // Case 1 - const curMaths = row.length / 2; - if (numMaths < curMaths) { - throw new ParseError( - "Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, - row[0] - ); - } - } else if (numCols < row.length) { - // Case 2 - numCols = row.length; - } - }); - - // Adjusting alignment. - // In aligned mode, we add one \qquad between columns; - // otherwise we add nothing. - for (let i = 0; i < numCols; ++i) { - let align = "r"; - if (i % 2 === 1) { - align = "l"; - } - cols[i] = { - type: "align", - align: align - }; - } - res.colSeparationType = isAligned ? "align" : "alignat"; - return res; -}; - -// Arrays are part of LaTeX, defined in lttab.dtx so its documentation -// is part of the source2e.pdf file of LaTeX2e source documentation. -// {darray} is an {array} environment where cells are set in \displaystyle, -// as defined in nccmath.sty. -defineEnvironment({ - type: "array", - names: ["array", "darray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Since no types are specified above, the two possibilities are - // - The argument is wrapped in {} or [], in which case Parser's - // parseGroup() returns an "ordgroup" wrapping some symbol node. - // - The argument is a bare symbol node. - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - if ("lcr".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } else if (ca === "|") { - return { - type: "separator", - separator: "|" - }; - } else if (ca === ":") { - return { - type: "separator", - separator: ":" - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - const res = { - cols, - colSeparationType: "array", - hskipBeforeAndAfter: true, // \@preamble in lttab.dtx - maxNumCols: cols.length - }; - return parseArray(context.parser, res, dCellStyle(context.envName)); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// The matrix environments of amsmath builds on the array environment -// of LaTeX, which is discussed above. -// The mathtools package adds starred versions of the same environments. -// These have an optional argument to choose left|center|right justification. -defineEnvironment({ - type: "array", - names: [ - "matrix", - "pmatrix", - "bmatrix", - "Bmatrix", - "vmatrix", - "Vmatrix", - "matrix*", - "pmatrix*", - "bmatrix*", - "Bmatrix*", - "vmatrix*", - "Vmatrix*" - ], - props: { - numArgs: 0 - }, - handler(context) { - const delimiters = { - matrix: null, - pmatrix: ["(", ")"], - bmatrix: ["[", "]"], - Bmatrix: ["\\{", "\\}"], - vmatrix: ["|", "|"], - Vmatrix: ["\\Vert", "\\Vert"] - }[context.envName.replace("*", "")]; - // \hskip -\arraycolsep in amsmath - let colAlign = "c"; - const payload = { - hskipBeforeAndAfter: false, - colSeparationType: "matrix", - cols: [{ type: "align", align: colAlign }] - }; - if (context.envName.charAt(context.envName.length - 1) === "*") { - // It's one of the mathtools starred functions. - // Parse the optional alignment argument. - const parser = context.parser; - parser.consumeSpaces(); - if (parser.fetch().text === "[") { - parser.consume(); - parser.consumeSpaces(); - colAlign = parser.fetch().text; - if ("lcr".indexOf(colAlign) === -1) { - throw new ParseError("Expected l or c or r", parser.nextToken); - } - parser.consume(); - parser.consumeSpaces(); - parser.expect("]"); - parser.consume(); - payload.cols = [{ type: "align", align: colAlign }]; - } - } - const res = parseArray(context.parser, payload, "text"); - // Populate cols with the correct number of column alignment specs. - const numCols = Math.max(0, ...res.body.map((row) => row.length)); - res.cols = new Array(numCols).fill({ type: "align", align: colAlign }); - return delimiters - ? { - type: "leftright", - mode: context.mode, - body: [res], - left: delimiters[0], - right: delimiters[1], - rightColor: undefined // \right uninfluenced by \color in array - } - : res; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["smallmatrix"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { arraystretch: 0.5 }; - const res = parseArray(context.parser, payload, "script"); - res.colSeparationType = "small"; - return res; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["subarray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Parsing of {subarray} is similar to {array} - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - // {subarray} only recognizes "l" & "c" - if ("lc".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - if (cols.length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - let res = { - cols, - hskipBeforeAndAfter: false, - colSeparationType: "array", - arraystretch: 0 - }; - res = parseArray(context.parser, res, "script"); - if (res.body.length > 0 && res.body[0].length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - return res; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// A cases environment (in amsmath.sty) is almost equivalent to -// \def -// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. -// {dcases} is a {cases} environment where cells are set in \displaystyle, -// as defined in mathtools.sty. -// {rcases} is another mathtools environment. It's brace is on the right side. -defineEnvironment({ - type: "array", - names: ["cases", "dcases", "rcases", "drcases"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { - cols: [ - { - type: "align", - align: "l" - }, - { - type: "align", - align: "l" - } - ], - colSeparationType: "cases" - }; - const res = parseArray(context.parser, payload, dCellStyle(context.envName)); - return { - type: "leftright", - mode: context.mode, - body: [res], - left: context.envName.indexOf("r") > -1 ? "." : "\\{", - right: context.envName.indexOf("r") > -1 ? "\\}" : ".", - rightColor: undefined - }; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// In the align environment, one uses ampersands, &, to specify number of -// columns in each row, and to locate spacing between each column. -// align gets automatic numbering. align* and aligned do not. -// The alignedat environment can be used in math mode. -// Note that we assume \nomallineskiplimit to be zero, -// so that \strut@ is the same as \strut. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$7 -}); - -// A gathered environment is like an array environment with one centered -// column, but where rows are considered lines so get \jot line spacing -// and contents are set in \displaystyle. -defineEnvironment({ - type: "array", - names: ["gathered", "gather", "gather*"], - props: { - numArgs: 0 - }, - handler(context) { - if (utils.contains(["gather", "gather*"], context.envName)) { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [ - { - type: "align", - align: "c" - } - ], - addJot: true, - colSeparationType: "gather", - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// alignat environment is like an align environment, but one must explicitly -// specify maximum number of columns in each row, and can adjust spacing between -// each columns. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["equation", "equation*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "equation", - emptySingleRow: true, - singleRow: true, - maxNumCols: 1, - colSeparationType: "gather", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["multline", "multline*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "multline", - maxNumCols: 1, - colSeparationType: "multline", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -defineEnvironment({ - type: "array", - names: ["CD"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - return parseCD(context.parser); - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// Catch \hline outside array environment -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\hline", "\\hdashline"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: true - }, - handler(context, args) { - throw new ParseError(`${context.funcName} valid only within array environment`); - } -}); - -const environments = _environments; - -// Environment delimiters. HTML/MathML rendering is defined in the corresponding -// defineEnvironment definitions. -defineFunction({ - type: "environment", - names: ["\\begin", "\\end"], - props: { - numArgs: 1, - argTypes: ["text"] - }, - handler({ parser, funcName }, args) { - const nameGroup = args[0]; - if (nameGroup.type !== "ordgroup") { - throw new ParseError("Invalid environment name", nameGroup); - } - let envName = ""; - for (let i = 0; i < nameGroup.body.length; ++i) { - envName += assertNodeType(nameGroup.body[i], "textord").text; - } - - if (funcName === "\\begin") { - // begin...end is similar to left...right - if (!Object.prototype.hasOwnProperty.call(environments, envName )) { - throw new ParseError("No such environment: " + envName, nameGroup); - } - // Build the environment object. Arguments and other information will - // be made available to the begin and end methods using properties. - const env = environments[envName]; - const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env); - const context = { - mode: parser.mode, - envName, - parser - }; - const result = env.handler(context, args, optArgs); - parser.expect("\\end", false); - const endNameToken = parser.nextToken; - const end = assertNodeType(parser.parseFunction(), "environment"); - if (end.name !== envName) { - throw new ParseError( - `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, - endNameToken - ); - } - return result; - } - - return { - type: "environment", - mode: parser.mode, - name: envName, - nameGroup - }; - } -}); - -defineFunction({ - type: "envTag", - names: ["\\env@tag"], - props: { - numArgs: 1, - argTypes: ["math"] - }, - handler({ parser }, args) { - return { - type: "envTag", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -defineFunction({ - type: "noTag", - names: ["\\env@notag"], - props: { - numArgs: 0 - }, - handler({ parser }) { - return { - type: "noTag", - mode: parser.mode - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -const mathmlBuilder$6 = (group, style) => { - const font = group.font; - const newStyle = style.withFont(font); - const mathGroup = buildGroup$1(group.body, newStyle); - - if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{} - if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - let canConsolidate = mathGroup.children[0].type === "mo"; - for (let i = 1; i < mathGroup.children.length; i++) { - if (mathGroup.children[i].type === "mo" && font === "boldsymbol") { - mathGroup.children[i].style.fontWeight = "bold"; - } - if (mathGroup.children[i].type !== "mi") { canConsolidate = false; } - const localVariant = mathGroup.children[i].attributes && - mathGroup.children[i].attributes.mathvariant || ""; - if (localVariant !== "normal") { canConsolidate = false; } - } - if (!canConsolidate) { return mathGroup } - // Consolidate the elements. - const mi = mathGroup.children[0]; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children.push(mathGroup.children[i].children[0]); - } - if (mathGroup.attributes.mathcolor) { mi.attributes.mathcolor = mathGroup.attributes.mathcolor; } - if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") { - // Workaround for a Firefox bug that renders spurious space around - // a - // Ref: https://bugs.webkit.org/show_bug.cgi?id=129097 - // We insert a text node that contains a zero-width space and wrap in an mrow. - // TODO: Get rid of this workaround when the Firefox bug is fixed. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - return mi -}; - -const fontAliases = { - "\\Bbb": "\\mathbb", - "\\bold": "\\mathbf", - "\\frak": "\\mathfrak", - "\\bm": "\\boldsymbol" -}; - -defineFunction({ - type: "font", - names: [ - // styles - "\\mathrm", - "\\mathit", - "\\mathbf", - "\\mathnormal", - "\\up@greek", - "\\boldsymbol", - - // families - "\\mathbb", - "\\mathcal", - "\\mathfrak", - "\\mathscr", - "\\mathsf", - "\\mathtt", - "\\oldstylenums", - - // aliases - "\\Bbb", - "\\bm", - "\\bold", - "\\frak" - ], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = normalizeArgument(args[0]); - let func = funcName; - if (func in fontAliases) { - func = fontAliases[func]; - } - return { - type: "font", - mode: parser.mode, - font: func.slice(1), - body - }; - }, - mathmlBuilder: mathmlBuilder$6 -}); - -// Old font changing functions -defineFunction({ - type: "font", - names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ parser, funcName, breakOnTokenText }, args) => { - const { mode } = parser; - const body = parser.parseExpression(true, breakOnTokenText); - const fontStyle = `math${funcName.slice(1)}`; - - return { - type: "font", - mode: mode, - font: fontStyle, - body: { - type: "ordgroup", - mode: parser.mode, - body - } - }; - }, - mathmlBuilder: mathmlBuilder$6 -}); - -const stylArray = ["display", "text", "script", "scriptscript"]; -const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 }; - -const mathmlBuilder$5 = (group, style) => { - // Track the scriptLevel of the numerator and denominator. - // We may need that info for \mathchoice or for adjusting em dimensions. - const childOptions = group.scriptLevel === "auto" - ? style.incrementLevel() - : group.scriptLevel === "display" - ? style.withLevel(StyleLevel.TEXT) - : group.scriptLevel === "text" - ? style.withLevel(StyleLevel.SCRIPT) - : style.withLevel(StyleLevel.SCRIPTSCRIPT); - - let node = new mathMLTree.MathNode("mfrac", [ - buildGroup$1(group.numer, childOptions), - buildGroup$1(group.denom, childOptions) - ]); - - if (!group.hasBarLine) { - node.setAttribute("linethickness", "0px"); - } else if (group.barSize) { - const ruleWidth = calculateSize(group.barSize, style); - node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit); - } - - if (group.leftDelim != null || group.rightDelim != null) { - const withDelims = []; - - if (group.leftDelim != null) { - const leftOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.leftDelim.replace("\\", "")) - ]); - leftOp.setAttribute("fence", "true"); - withDelims.push(leftOp); - } - - withDelims.push(node); - - if (group.rightDelim != null) { - const rightOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.rightDelim.replace("\\", "")) - ]); - rightOp.setAttribute("fence", "true"); - withDelims.push(rightOp); - } - - node = makeRow(withDelims); - } - - if (group.scriptLevel !== "auto") { - node = new mathMLTree.MathNode("mstyle", [node]); - node.setAttribute("displaystyle", String(group.scriptLevel === "display")); - node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]); - } - - return node; -}; - -defineFunction({ - type: "genfrac", - names: [ - "\\dfrac", - "\\frac", - "\\tfrac", - "\\dbinom", - "\\binom", - "\\tbinom", - "\\\\atopfrac", // can’t be entered directly - "\\\\bracefrac", - "\\\\brackfrac" // ditto - ], - props: { - numArgs: 2, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - let hasBarLine = false; - let leftDelim = null; - let rightDelim = null; - let scriptLevel = "auto"; - - switch (funcName) { - case "\\dfrac": - case "\\frac": - case "\\tfrac": - hasBarLine = true; - break; - case "\\\\atopfrac": - hasBarLine = false; - break; - case "\\dbinom": - case "\\binom": - case "\\tbinom": - leftDelim = "("; - rightDelim = ")"; - break; - case "\\\\bracefrac": - leftDelim = "\\{"; - rightDelim = "\\}"; - break; - case "\\\\brackfrac": - leftDelim = "["; - rightDelim = "]"; - break; - default: - throw new Error("Unrecognized genfrac command"); - } - - switch (funcName) { - case "\\dfrac": - case "\\dbinom": - scriptLevel = "display"; - break; - case "\\tfrac": - case "\\tbinom": - scriptLevel = "text"; - break; - } - - return { - type: "genfrac", - mode: parser.mode, - continued: false, - numer, - denom, - hasBarLine, - leftDelim, - rightDelim, - scriptLevel, - barSize: null - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -defineFunction({ - type: "genfrac", - names: ["\\cfrac"], - props: { - numArgs: 2 - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - - return { - type: "genfrac", - mode: parser.mode, - continued: true, - numer, - denom, - hasBarLine: true, - leftDelim: null, - rightDelim: null, - scriptLevel: "display", - barSize: null - }; - } -}); - -// Infix generalized fractions -- these are not rendered directly, but replaced -// immediately by one of the variants above. -defineFunction({ - type: "infix", - names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], - props: { - numArgs: 0, - infix: true - }, - handler({ parser, funcName, token }) { - let replaceWith; - switch (funcName) { - case "\\over": - replaceWith = "\\frac"; - break; - case "\\choose": - replaceWith = "\\binom"; - break; - case "\\atop": - replaceWith = "\\\\atopfrac"; - break; - case "\\brace": - replaceWith = "\\\\bracefrac"; - break; - case "\\brack": - replaceWith = "\\\\brackfrac"; - break; - default: - throw new Error("Unrecognized infix genfrac command"); - } - return { - type: "infix", - mode: parser.mode, - replaceWith, - token - }; - } -}); - -const delimFromValue = function(delimString) { - let delim = null; - if (delimString.length > 0) { - delim = delimString; - delim = delim === "." ? null : delim; - } - return delim; -}; - -defineFunction({ - type: "genfrac", - names: ["\\genfrac"], - props: { - numArgs: 6, - allowedInArgument: true, - argTypes: ["math", "math", "size", "text", "math", "math"] - }, - handler({ parser }, args) { - const numer = args[4]; - const denom = args[5]; - - // Look into the parse nodes to get the desired delimiters. - const leftNode = normalizeArgument(args[0]); - const leftDelim = leftNode.type === "atom" && leftNode.family === "open" - ? delimFromValue(leftNode.text) - : null; - const rightNode = normalizeArgument(args[1]); - const rightDelim = - rightNode.type === "atom" && rightNode.family === "close" - ? delimFromValue(rightNode.text) - : null; - - const barNode = assertNodeType(args[2], "size"); - let hasBarLine; - let barSize = null; - if (barNode.isBlank) { - // \genfrac acts differently than \above. - // \genfrac treats an empty size group as a signal to use a - // standard bar size. \above would see size = 0 and omit the bar. - hasBarLine = true; - } else { - barSize = barNode.value; - hasBarLine = barSize.number > 0; - } - - // Find out if we want displaystyle, textstyle, etc. - let scriptLevel = "auto"; - let styl = args[3]; - if (styl.type === "ordgroup") { - if (styl.body.length > 0) { - const textOrd = assertNodeType(styl.body[0], "textord"); - scriptLevel = stylArray[Number(textOrd.text)]; - } - } else { - styl = assertNodeType(styl, "textord"); - scriptLevel = stylArray[Number(styl.text)]; - } - - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim, - rightDelim, - scriptLevel - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -// \above is an infix fraction that also defines a fraction bar size. -defineFunction({ - type: "infix", - names: ["\\above"], - props: { - numArgs: 1, - argTypes: ["size"], - infix: true - }, - handler({ parser, funcName, token }, args) { - return { - type: "infix", - mode: parser.mode, - replaceWith: "\\\\abovefrac", - barSize: assertNodeType(args[0], "size").value, - token - }; - } -}); - -defineFunction({ - type: "genfrac", - names: ["\\\\abovefrac"], - props: { - numArgs: 3, - argTypes: ["math", "size", "math"] - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const barSize = assert(assertNodeType(args[1], "infix").barSize); - const denom = args[2]; - - const hasBarLine = barSize.number > 0; - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim: null, - rightDelim: null, - scriptLevel: "auto" - }; - }, - - mathmlBuilder: mathmlBuilder$5 -}); - -const mathmlBuilder$4 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [ - buildGroup$1(group.base, style), - accentNode - ]); -}; - -// Horizontal stretchy braces -defineFunction({ - type: "horizBrace", - names: ["\\overbrace", "\\underbrace"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "horizBrace", - mode: parser.mode, - label: funcName, - isOver: /^\\over/.test(funcName), - base: args[0] - }; - }, - mathmlBuilder: mathmlBuilder$4 -}); - -defineFunction({ - type: "href", - names: ["\\href"], - props: { - numArgs: 2, - argTypes: ["url", "original"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const body = args[1]; - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\href", - url: href - }) - ) { - throw new ParseError(`Function "\\href" is not trusted`, token) - } - - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - let math = buildExpressionRow(group.body, style); - if (!(math instanceof MathNode)) { - math = new MathNode("mrow", [math]); - } - math.setAttribute("href", group.href); - return math; - } -}); - -defineFunction({ - type: "href", - names: ["\\url"], - props: { - numArgs: 1, - argTypes: ["url"], - allowedInText: true - }, - handler: ({ parser, token }, args) => { - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\url", - url: href - }) - ) { - throw new ParseError(`Function "\\url" is not trusted`, token) - } - - const chars = []; - for (let i = 0; i < href.length; i++) { - let c = href[i]; - if (c === "~") { - c = "\\textasciitilde"; - } - chars.push({ - type: "textord", - mode: "text", - text: c - }); - } - const body = { - type: "text", - mode: parser.mode, - font: "\\texttt", - body: chars - }; - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - } -}); - -defineFunction({ - type: "html", - names: ["\\class", "\\id", "\\style", "\\data"], - props: { - numArgs: 2, - argTypes: ["raw", "original"], - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - const value = assertNodeType(args[0], "raw").string; - const body = args[1]; - - if (parser.settings.strict) { - throw new ParseError(`Function "${funcName}" is disabled in strict mode`, token) - } - - let trustContext; - const attributes = {}; - - switch (funcName) { - case "\\class": - attributes.class = value; - trustContext = { - command: "\\class", - class: value - }; - break; - case "\\id": - attributes.id = value; - trustContext = { - command: "\\id", - id: value - }; - break; - case "\\style": - attributes.style = value; - trustContext = { - command: "\\style", - style: value - }; - break; - case "\\data": { - const data = value.split(","); - for (let i = 0; i < data.length; i++) { - const keyVal = data[i].split("="); - if (keyVal.length !== 2) { - throw new ParseError("Error parsing key-value for \\data"); - } - attributes["data-" + keyVal[0].trim()] = keyVal[1].trim(); - } - - trustContext = { - command: "\\data", - attributes - }; - break; - } - default: - throw new Error("Unrecognized html command"); - } - - if (!parser.settings.isTrusted(trustContext)) { - throw new ParseError(`Function "${funcName}" is not trusted`, token) - } - return { - type: "html", - mode: parser.mode, - attributes, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const element = buildExpressionRow(group.body, style); - - const classes = []; - if (group.attributes.class) { - classes.push(...group.attributes.class.trim().split(/\s+/)); - } - element.classes = classes; - - for (const attr in group.attributes) { - if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) { - element.setAttribute(attr, group.attributes[attr]); - } - } - - return element; - } -}); - -const sizeData = function(str) { - if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { - // str is a number with no unit specified. - // default unit is bp, per graphix package. - return { number: +str, unit: "bp" } - } else { - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); - if (!match) { - throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); - } - return data - } -}; - -defineFunction({ - type: "includegraphics", - names: ["\\includegraphics"], - props: { - numArgs: 1, - numOptionalArgs: 1, - argTypes: ["raw", "url"], - allowedInText: false - }, - handler: ({ parser, token }, args, optArgs) => { - let width = { number: 0, unit: "em" }; - let height = { number: 0.9, unit: "em" }; // sorta character sized. - let totalheight = { number: 0, unit: "em" }; - let alt = ""; - - if (optArgs[0]) { - const attributeStr = assertNodeType(optArgs[0], "raw").string; - - // Parser.js does not parse key/value pairs. We get a string. - const attributes = attributeStr.split(","); - for (let i = 0; i < attributes.length; i++) { - const keyVal = attributes[i].split("="); - if (keyVal.length === 2) { - const str = keyVal[1].trim(); - switch (keyVal[0].trim()) { - case "alt": - alt = str; - break - case "width": - width = sizeData(str); - break - case "height": - height = sizeData(str); - break - case "totalheight": - totalheight = sizeData(str); - break - default: - throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics.") - } - } - } - } - - const src = assertNodeType(args[0], "url").url; - - if (alt === "") { - // No alt given. Use the file name. Strip away the path. - alt = src; - alt = alt.replace(/^.*[\\/]/, ""); - alt = alt.substring(0, alt.lastIndexOf(".")); - } - - if ( - !parser.settings.isTrusted({ - command: "\\includegraphics", - url: src - }) - ) { - throw new ParseError(`Function "\\includegraphics" is not trusted`, token) - } - - return { - type: "includegraphics", - mode: parser.mode, - alt: alt, - width: width, - height: height, - totalheight: totalheight, - src: src - } - }, - mathmlBuilder: (group, style) => { - const height = calculateSize(group.height, style); - const depth = { number: 0, unit: "em" }; - - if (group.totalheight.number > 0) { - if (group.totalheight.unit === height.unit && - group.totalheight.number > height.number) { - depth.number = group.totalheight.number - height.number; - depth.unit = height.unit; - } - } - - let width = 0; - if (group.width.number > 0) { - width = calculateSize(group.width, style); - } - - const graphicStyle = { height: height.number + depth.number + "em" }; - if (width.number > 0) { - graphicStyle.width = width.number + width.unit; - } - if (depth.number > 0) { - graphicStyle.verticalAlign = -depth.number + depth.unit; - } - - const node = new Img(group.src, group.alt, graphicStyle); - node.height = height; - node.depth = depth; - return new mathMLTree.MathNode("mtext", [node]) - } -}); - -// Horizontal spacing commands - -// TODO: \hskip and \mskip should support plus and minus in lengths - -defineFunction({ - type: "kern", - names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], - props: { - numArgs: 1, - argTypes: ["size"], - primitive: true, - allowedInText: true - }, - handler({ parser, funcName, token }, args) { - const size = assertNodeType(args[0], "size"); - if (parser.settings.strict) { - const mathFunction = funcName[1] === "m"; // \mkern, \mskip - const muUnit = size.value.unit === "mu"; - if (mathFunction) { - if (!muUnit) { - throw new ParseError(`LaTeX's ${funcName} supports only mu units, ` + - `not ${size.value.unit} units`, token) - } - if (parser.mode !== "math") { - throw new ParseError(`LaTeX's ${funcName} works only in math mode`, token) - } - } else { - // !mathFunction - if (muUnit) { - throw new ParseError(`LaTeX's ${funcName} doesn't support mu units`, token) - } - } - } - return { - type: "kern", - mode: parser.mode, - dimension: size.value - }; - }, - mathmlBuilder(group, style) { - const dimension = calculateSize(group.dimension, style); - const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : ""; - if (group.mode === "text" && ch.length > 0) { - const character = new mathMLTree.TextNode(ch); - return new mathMLTree.MathNode("mtext", [character]); - } else { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", dimension.number + dimension.unit); - return node; - } - } -}); - -const spaceCharacter = function(width) { - if (width >= 0.05555 && width <= 0.05556) { - return "\u200a"; //   - } else if (width >= 0.1666 && width <= 0.1667) { - return "\u2009"; //   - } else if (width >= 0.2222 && width <= 0.2223) { - return "\u2005"; //   - } else if (width >= 0.2777 && width <= 0.2778) { - return "\u2005\u200a"; //    - } else { - return ""; - } -}; - -// Limit valid characters to a small set, for safety. -const invalidIdRegEx = /[^A-Za-z_0-9-]/g; - -defineFunction({ - type: "label", - names: ["\\label"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser }, args) { - return { - type: "label", - mode: parser.mode, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Return a no-width, no-ink element with an HTML id. - const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]); - if (group.string.length > 0) { - node.setAttribute("id", group.string); - } - return node - } -}); - -// Horizontal overlap functions - -const textModeLap = ["\\clap", "\\llap", "\\rlap"]; - -defineFunction({ - type: "lap", - names: ["\\mathllap", "\\mathrlap", "\\mathclap", "\\clap", "\\llap", "\\rlap"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - if (textModeLap.includes(funcName)) { - if (parser.settings.strict && parser.mode !== "text") { - throw new ParseError(`{${funcName}} can be used only in text mode. - Try \\math${funcName.slice(1)}`, token) - } - funcName = funcName.slice(1); - } else { - funcName = funcName.slice(5); - } - const body = args[0]; - return { - type: "lap", - mode: parser.mode, - alignment: funcName, - body - } - }, - mathmlBuilder: (group, style) => { - // mathllap, mathrlap, mathclap - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, style)]); - - if (group.alignment === "rlap") { - if (group.body.body.length > 0 && group.body.body[0].type === "genfrac") { - // In Firefox, a squashes the 3/18em padding of a child \frac. Put it back. - node.setAttribute("lspace", "0.16667em"); - } - } else { - const offset = group.alignment === "llap" ? "-1" : "-0.5"; - node.setAttribute("lspace", offset + "width"); - } - node.setAttribute("width", "0px"); - return node - } -}); - -// Switching from text mode back to math mode -defineFunction({ - type: "ordgroup", - names: ["\\(", "$"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler({ funcName, parser }, args) { - const outerMode = parser.mode; - parser.switchMode("math"); - const close = funcName === "\\(" ? "\\)" : "$"; - const body = parser.parseExpression(false, close); - parser.expect(close); - parser.switchMode(outerMode); - return { - type: "ordgroup", - mode: parser.mode, - body - }; - } -}); - -// Check for extra closing math delimiters -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\)", "\\]"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler(context, token) { - throw new ParseError(`Mismatched ${context.funcName}`, token); - } -}); - -const chooseStyle = (group, style) => { - switch (style.level) { - case StyleLevel.DISPLAY: // 0 - return group.display; - case StyleLevel.TEXT: // 1 - return group.text; - case StyleLevel.SCRIPT: // 2 - return group.script; - case StyleLevel.SCRIPTSCRIPT: // 3 - return group.scriptscript; - default: - return group.text; - } -}; - -defineFunction({ - type: "mathchoice", - names: ["\\mathchoice"], - props: { - numArgs: 4, - primitive: true - }, - handler: ({ parser }, args) => { - return { - type: "mathchoice", - mode: parser.mode, - display: ordargument(args[0]), - text: ordargument(args[1]), - script: ordargument(args[2]), - scriptscript: ordargument(args[3]) - }; - }, - mathmlBuilder: (group, style) => { - const body = chooseStyle(group, style); - return buildExpressionRow(body, style); - } -}); - -const textAtomTypes = ["text", "textord", "mathord", "atom"]; - -function mathmlBuilder$3(group, style) { - let node; - const inner = buildExpression(group.body, style); - - if (group.mclass === "minner") { - node = new mathMLTree.MathNode("mpadded", inner); - } else if (group.mclass === "mord") { - if (group.isCharacterBox || inner[0].type === "mathord") { - node = inner[0]; - node.type = "mi"; - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - if (group.mustPromote) { - node = inner[0]; - node.type = "mo"; - if (group.isCharacterBox && group.body[0].text && /[A-Za-z]/.test(group.body[0].text)) { - node.setAttribute("mathvariant", "italic"); - } - } else { - node = new mathMLTree.MathNode("mo", inner); - } - - // Set spacing based on what is the most likely adjacent atom type. - // See TeXbook p170. - const doSpacing = style.level < 2; // Operator spacing is zero inside a (sub|super)script. - if (group.mclass === "mbin") { - // medium space - node.attributes.lspace = (doSpacing ? "0.2222em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2222em" : "0"); - } else if (group.mclass === "mrel") { - // thickspace - node.attributes.lspace = (doSpacing ? "0.2778em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2778em" : "0"); - } else if (group.mclass === "mpunct") { - node.attributes.lspace = "0em"; - node.attributes.rspace = (doSpacing ? "0.1667em" : "0"); - } else if (group.mclass === "mopen" || group.mclass === "mclose") { - node.attributes.lspace = "0em"; - node.attributes.rspace = "0em"; - } else if (group.mclass === "minner" && doSpacing) { - node.attributes.lspace = "0.0556em"; // 1 mu is the most likely option - node.attributes.width = "+0.1111em"; - } - if (!(group.mclass === "mopen" || group.mclass === "mclose")) { - delete node.attributes.stretchy; - delete node.attributes.form; - } - } - return node; -} - -// Math class commands except \mathop -defineFunction({ - type: "mclass", - names: [ - "\\mathord", - "\\mathbin", - "\\mathrel", - "\\mathopen", - "\\mathclose", - "\\mathpunct", - "\\mathinner" - ], - props: { - numArgs: 1, - primitive: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - const isCharacterBox = utils.isCharacterBox(body); - // We should not wrap a around a or . That would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - let mustPromote = true; - const mord = { type: "mathord", text: "", mode: parser.mode }; - const arr = (body.body) ? body.body : [body]; - for (const arg of arr) { - if (textAtomTypes.includes(arg.type)) { - if (arg.text) { - mord.text += arg.text; - } else if (arg.body) { - arg.body.map(e => { mord.text += e.text; }); - } - } else { - mustPromote = false; - break - } - } - return { - type: "mclass", - mode: parser.mode, - mclass: "m" + funcName.slice(5), - body: ordargument(mustPromote ? mord : body), - isCharacterBox, - mustPromote - }; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -const binrelClass = (arg) => { - // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. - // (by rendering separately and with {}s before and after, and measuring - // the change in spacing). We'll do roughly the same by detecting the - // atom type directly. - const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; - if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { - return "m" + atom.family; - } else { - return "mord"; - } -}; - -// \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. -// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. -defineFunction({ - type: "mclass", - names: ["\\@binrel"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "mclass", - mode: parser.mode, - mclass: binrelClass(args[0]), - body: ordargument(args[1]), - isCharacterBox: utils.isCharacterBox(args[1]) - }; - } -}); - -// Build a relation or stacked op by placing one symbol on top of another -defineFunction({ - type: "mclass", - names: ["\\stackrel", "\\overset", "\\underset"], - props: { - numArgs: 2 - }, - handler({ parser, funcName }, args) { - const baseArg = args[1]; - const shiftedArg = args[0]; - - const baseOp = { - type: "op", - mode: baseArg.mode, - limits: true, - alwaysHandleSupSub: true, - parentIsSupSub: false, - symbol: false, - stack: true, - suppressBaseShift: funcName !== "\\stackrel", - body: ordargument(baseArg) - }; - - return { - type: "supsub", - mode: shiftedArg.mode, - base: baseOp, - sup: funcName === "\\underset" ? null : shiftedArg, - sub: funcName === "\\underset" ? shiftedArg : null - }; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// Helper function -const buildGroup = (el, style, noneNode) => { - if (!el) { return noneNode } - const node = buildGroup$1(el, style); - if (node.type === "mrow" && node.children.length === 0) { return noneNode } - return node -}; - -defineFunction({ - type: "multiscript", - names: ["\\sideset", "\\pres@cript"], // See macros.js for \prescript - props: { - numArgs: 3 - }, - handler({ parser, funcName, token }, args) { - if (args[2].body.length === 0) { - throw new ParseError(funcName + `cannot parse an empty base.`) - } - const base = args[2].body[0]; - if (parser.settings.strict && funcName === "\\sideset" && !base.symbol) { - throw new ParseError(`The base of \\sideset must be a big operator. Try \\prescript.`) - } - - if ((args[0].body.length > 0 && args[0].body[0].type !== "supsub") || - (args[1].body.length > 0 && args[1].body[0].type !== "supsub")) { - throw new ParseError("\\sideset can parse only subscripts and " + - "superscripts in its first two arguments", token) - } - - // The prescripts and postscripts come wrapped in a supsub. - const prescripts = args[0].body.length > 0 ? args[0].body[0] : null; - const postscripts = args[1].body.length > 0 ? args[1].body[0] : null; - - if (!prescripts && !postscripts) { - return base - } else if (!prescripts) { - // It's not a multi-script. Get a \textstyle supsub. - return { - type: "styling", - mode: parser.mode, - scriptLevel: "text", - body: [{ - type: "supsub", - mode: parser.mode, - base, - sup: postscripts.sup, - sub: postscripts.sub - }] - } - } else { - return { - type: "multiscript", - mode: parser.mode, - isSideset: funcName === "\\sideset", - prescripts, - postscripts, - base - } - } - }, - mathmlBuilder(group, style) { - const base = buildGroup$1(group.base, style); - - const prescriptsNode = new mathMLTree.MathNode("mprescripts"); - const noneNode = new mathMLTree.MathNode("none"); - let children = []; - - const preSub = buildGroup(group.prescripts.sub, style, noneNode); - const preSup = buildGroup(group.prescripts.sup, style, noneNode); - if (group.isSideset) { - // This seems silly, but LaTeX does this. Firefox ignores it, which does not make me sad. - preSub.setAttribute("style", "text-align: left;"); - preSup.setAttribute("style", "text-align: left;"); - } - - if (group.postscripts) { - const postSub = buildGroup(group.postscripts.sub, style, noneNode); - const postSup = buildGroup(group.postscripts.sup, style, noneNode); - children = [base, postSub, postSup, prescriptsNode, preSub, preSup]; - } else { - children = [base, prescriptsNode, preSub, preSup]; - } - - return new mathMLTree.MathNode("mmultiscripts", children); - } -}); - -defineFunction({ - type: "not", - names: ["\\not"], - props: { - numArgs: 1, - primitive: true, - allowedInText: false - }, - handler({ parser }, args) { - const isCharacterBox = utils.isCharacterBox(args[0]); - let body; - if (isCharacterBox) { - body = ordargument(args[0]); - if (body[0].text.charAt(0) === "\\") { - body[0].text = symbols.math[body[0].text].replace; - } - // \u0338 is the Unicode Combining Long Solidus Overlay - body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1); - } else { - // When the argument is not a character box, TeX does an awkward, poorly placed overlay. - // We'll do the same. - const notNode = { type: "textord", mode: "math", text: "\u0338" }; - const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } }; - body = [notNode, kernNode, args[0]]; - } - return { - type: "not", - mode: parser.mode, - body, - isCharacterBox - }; - }, - mathmlBuilder(group, style) { - if (group.isCharacterBox) { - const inner = buildExpression(group.body, style); - return inner[0] - } else { - return buildExpressionRow(group.body, style, true) - } - } -}); - -// Limits, symbols - -// Some helpers - -const ordAtomTypes = ["textord", "mathord", "atom"]; - -// Most operators have a large successor symbol, but these don't. -const noSuccessor = ["\\smallint"]; - -// Math operators (e.g. \sin) need a space between these types and themselves: -const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"]; - -const dels = ["}", "\\left", "\\middle", "\\right"]; -const isDelimiter = str => str.length > 0 && - (delimiters.includes(str) || delimiterSizes[str] || dels.includes(str)); - -// NOTE: Unlike most `builders`s, this one handles not only "op", but also -// "supsub" since some of them (like \int) can affect super/subscripting. - -const mathmlBuilder$2 = (group, style) => { - let node; - - if (group.symbol) { - // This is a symbol. Just add the symbol. - node = new MathNode("mo", [makeText(group.name, group.mode)]); - if (utils.contains(noSuccessor, group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - } else { - // This is a text operator. Add all of the characters from the operator's name. - node = new MathNode("mi", [new TextNode(group.name.slice(1))]); - - if (!group.parentIsSupSub) { - // Append an invisible . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new MathNode("mo", [makeText("\u2061", "text")]); - node = new MathNode("mpadded", [node, operator]); - const lSpace = group.needsLeadingSpace ? 0.1667 : 0; - const rSpace = group.isFollowedByDelimiter ? 0 : 0.1666; - if (group.needsLeadingSpace) { - node.setAttribute("lspace", "0.1667em"); // thin space. - } - if ((lSpace + rSpace) > 0) { - node.setAttribute("width", `+${lSpace + rSpace}em`); - } - } - } - - return node; -}; - -const singleCharBigOps = { - "\u220F": "\\prod", - "\u2210": "\\coprod", - "\u2211": "\\sum", - "\u22c0": "\\bigwedge", - "\u22c1": "\\bigvee", - "\u22c2": "\\bigcap", - "\u22c3": "\\bigcup", - "\u2a00": "\\bigodot", - "\u2a01": "\\bigoplus", - "\u2a02": "\\bigotimes", - "\u2a04": "\\biguplus", - "\u2a05": "\\bigsqcap", - "\u2a06": "\\bigsqcup" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\smallint", - "\u220F", - "\u2210", - "\u2211", - "\u22c0", - "\u22c1", - "\u22c2", - "\u22c3", - "\u2a00", - "\u2a01", - "\u2a02", - "\u2a04", - "\u2a06" - ], - props: { - numArgs: 0 - }, - handler: ({ parser, funcName }, args) => { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharBigOps[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: true, - stack: false, // This is true for \stackrel{}, not here. - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// Note: calling defineFunction with a type that's already been defined only -// works because the same mathmlBuilder is being used. -defineFunction({ - type: "op", - names: ["\\mathop"], - props: { - numArgs: 1, - primitive: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - // It would be convienient to just wrap a around the argument. - // But if the argument is a or , that would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - const arr = (body.body) ? body.body : [body]; - const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type); - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: isSymbol, - stack: false, - name: isSymbol ? arr[0].text : null, - body: isSymbol ? null : ordargument(body) - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// There are 2 flags for operators; whether they produce limits in -// displaystyle, and whether they are symbols and should grow in -// displaystyle. These four groups cover the four possible choices. - -const singleCharIntegrals = { - "\u222b": "\\int", - "\u222c": "\\iint", - "\u222d": "\\iiint", - "\u222e": "\\oint", - "\u222f": "\\oiint", - "\u2230": "\\oiiint", - "\u2231": "\\intclockwise", - "\u2232": "\\varointclockwise", - "\u2a0c": "\\iiiint", - "\u2a0d": "\\intbar", - "\u2a0e": "\\intBar", - "\u2a0f": "\\fint", - "\u2a12": "\\rppolint", - "\u2a13": "\\scpolint", - "\u2a15": "\\pointint", - "\u2a16": "\\sqint", - "\u2a17": "\\intlarhk", - "\u2a18": "\\intx", - "\u2a19": "\\intcap", - "\u2a1a": "\\intcup" -}; - -// No limits, not symbols -defineFunction({ - type: "op", - names: [ - "\\arcsin", - "\\arccos", - "\\arctan", - "\\arctg", - "\\arcctg", - "\\arg", - "\\ch", - "\\cos", - "\\cosec", - "\\cosh", - "\\cot", - "\\cotg", - "\\coth", - "\\csc", - "\\ctg", - "\\cth", - "\\deg", - "\\dim", - "\\exp", - "\\hom", - "\\ker", - "\\lg", - "\\ln", - "\\log", - "\\sec", - "\\sin", - "\\sinh", - "\\sh", - "\\sgn", - "\\tan", - "\\tanh", - "\\tg", - "\\th" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - const next = parser.gullet.future().text; - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// Limits, not symbols -defineFunction({ - type: "op", - names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - const next = parser.gullet.future().text; - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: false, - stack: false, - isFollowedByDelimiter: isDelimiter(next), - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -// No limits, symbols -defineFunction({ - type: "op", - names: [ - "\\int", - "\\iint", - "\\iiint", - "\\iiiint", - "\\oint", - "\\oiint", - "\\oiiint", - "\\intclockwise", - "\\varointclockwise", - "\\intbar", - "\\intBar", - "\\fint", - "\\rppolint", - "\\scpolint", - "\\pointint", - "\\sqint", - "\\intlarhk", - "\\intx", - "\\intcap", - "\\intcup", - "\u222b", - "\u222c", - "\u222d", - "\u222e", - "\u222f", - "\u2230", - "\u2231", - "\u2232", - "\u2a0c", - "\u2a0d", - "\u2a0e", - "\u2a0f", - "\u2a12", - "\u2a13", - "\u2a15", - "\u2a16", - "\u2a17", - "\u2a18", - "\u2a19", - "\u2a1a" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharIntegrals[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: true, - stack: false, - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -/** - * All registered global/built-in macros. - * `macros.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `macros.js`. - */ -const _macros = {}; - -// This function might one day accept an additional argument and do more things. -function defineMacro(name, body) { - _macros[name] = body; -} - -// NOTE: Unlike most builders, this one handles not only -// "operatorname", but also "supsub" since \operatorname* can -// affect super/subscripting. - -const mathmlBuilder$1 = (group, style) => { - let expression = buildExpression(group.body, style.withFont("mathrm")); - - // Is expression a string or has it something like a fraction? - let isAllString = true; // default - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - switch (node.type) { - case "mi": - case "mn": - case "ms": - case "mtext": - break; // Do nothing yet. - case "mspace": - { - if (node.attributes.width) { - const width = node.attributes.width.replace("em", ""); - const ch = spaceCharacter(Number(width)); - if (ch === "") { - isAllString = false; - } else { - expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)]); - } - } - } - break - case "mo": { - const child = node.children[0]; - if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { - child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); - } else { - isAllString = false; - } - break - } - default: - isAllString = false; - } - } else { - isAllString = false; - } - } - - if (isAllString) { - // Write a single TextNode instead of multiple nested tags. - const word = expression.map((node) => node.toText()).join(""); - expression = [new mathMLTree.TextNode(word)]; - } else if ( - expression.length === 1 - && utils.contains(["mover", "munder"], expression[0].type) && - (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext") - ) { - expression[0].children[0].type = "mi"; - if (group.parentIsSupSub) { - return new mathMLTree.MathNode("mrow", expression) - } else { - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - return mathMLTree.newDocumentFragment([expression[0], operator]) - } - } - - let wrapper; - if (isAllString) { - wrapper = new mathMLTree.MathNode("mi", expression); - wrapper.setAttribute("mathvariant", "normal"); - } else { - wrapper = new mathMLTree.MathNode("mrow", expression); - } - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (group.needsLeadingSpace) { - // LaTeX gives operator spacing, but a gets ord spacing. - // So add a leading space. - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - return mathMLTree.newDocumentFragment([space, wrapper, operator]) - } else { - return mathMLTree.newDocumentFragment([wrapper, operator]) - } - } - - return wrapper -}; - -// \operatorname -// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ -defineFunction({ - type: "operatorname", - names: ["\\operatorname@", "\\operatornamewithlimits"], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = args[0]; - const prevAtomType = parser.prevAtomType; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, true); - } -}); - -defineFunction({ - type: "overline", - names: ["\\overline"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - const body = args[0]; - return { - type: "overline", - mode: parser.mode, - body - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005F")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode( - "mover", - [buildGroup$1(group.body, style), operator] - ); - node.setAttribute("accent", "true"); - - return node; - } -}); - -defineFunction({ - type: "phantom", - names: ["\\phantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "phantom", - mode: parser.mode, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(group.body, style); - return new mathMLTree.MathNode("mphantom", inner); - } -}); - -defineFunction({ - type: "hphantom", - names: ["\\hphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "hphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("height", "0px"); - node.setAttribute("depth", "0px"); - return node; - } -}); - -defineFunction({ - type: "vphantom", - names: ["\\vphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "vphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("width", "0px"); - return node; - } -}); - -// \pmb is a simulation of bold font. -// The version of \pmb in ambsy.sty works by typesetting three copies of the argument -// with small offsets. We use CSS text-shadow. -// It's a hack. Not as good as a real bold font. Better than nothing. - -defineFunction({ - type: "pmb", - names: ["\\pmb"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "pmb", - mode: parser.mode, - body: ordargument(args[0]) - } - }, - mathmlBuilder(group, style) { - const inner = buildExpression(group.body, style); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px"); - return node - } -}); - -const sign = num => num >= 0 ? "+" : "-"; - -// \raise, \lower, and \raisebox - -const mathmlBuilder = (group, style) => { - const newStyle = style.withLevel(StyleLevel.TEXT); - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, newStyle)]); - const dy = calculateSize(group.dy, style); - node.setAttribute("voffset", dy.number + dy.unit); - const dyAbs = Math.abs(dy.number); - node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit); - node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit); - return node -}; - -defineFunction({ - type: "raise", - names: ["\\raise", "\\lower"], - props: { - numArgs: 2, - argTypes: ["size", "primitive"], - primitive: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - if (funcName === "\\lower") { amount.number *= -1; } - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder -}); - - -defineFunction({ - type: "raise", - names: ["\\raisebox"], - props: { - numArgs: 2, - argTypes: ["size", "hbox"], - allowedInText: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "ref", - names: ["\\ref", "\\eqref"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser, funcName }, args) { - return { - type: "ref", - mode: parser.mode, - funcName, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Create an empty text node. Set a class and an href. - // The post-processor will populate with the target's tag or equation number. - const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"]; - const node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("")], classes); - node.setAttribute("href", "#" + group.string); - return node - } -}); - -defineFunction({ - type: "internal", - names: ["\\relax"], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser }) { - return { - type: "internal", - mode: parser.mode - }; - } -}); - -defineFunction({ - type: "rule", - names: ["\\rule"], - props: { - numArgs: 2, - numOptionalArgs: 1, - argTypes: ["size", "size", "size"] - }, - handler({ parser }, args, optArgs) { - const shift = optArgs[0]; - const width = assertNodeType(args[0], "size"); - const height = assertNodeType(args[1], "size"); - return { - type: "rule", - mode: parser.mode, - shift: shift && assertNodeType(shift, "size").value, - width: width.value, - height: height.value - }; - }, - mathmlBuilder(group, style) { - const width = calculateSize(group.width, style); - const height = calculateSize(group.height, style); - const shift = group.shift - ? calculateSize(group.shift, style) - : { number: 0, unit: "em" }; - const color = (style.color && style.getColor()) || "black"; - - const rule = new mathMLTree.MathNode("mspace"); - if (width.number > 0 && height.number > 0) { - rule.setAttribute("mathbackground", color); - } - rule.setAttribute("width", width.number + width.unit); - rule.setAttribute("height", height.number + height.unit); - if (shift.number === 0) { return rule } - - const wrapper = new mathMLTree.MathNode("mpadded", [rule]); - if (shift.number >= 0) { - wrapper.setAttribute("height", "+" + shift.number + shift.unit); - } else { - wrapper.setAttribute("height", shift.number + shift.unit); - wrapper.setAttribute("depth", "+" + -shift.number + shift.unit); - } - wrapper.setAttribute("voffset", shift.number + shift.unit); - return wrapper; - } -}); - -// The size mappings are taken from TeX with \normalsize=10pt. -// We don't have to track script level. MathML does that. -const sizeMap = { - "\\tiny": 0.5, - "\\sixptsize": 0.6, - "\\Tiny": 0.6, - "\\scriptsize": 0.7, - "\\footnotesize": 0.8, - "\\small": 0.9, - "\\normalsize": 1.0, - "\\large": 1.2, - "\\Large": 1.44, - "\\LARGE": 1.728, - "\\huge": 2.074, - "\\Huge": 2.488 -}; - -defineFunction({ - type: "sizing", - names: [ - "\\tiny", - "\\sixptsize", - "\\Tiny", - "\\scriptsize", - "\\footnotesize", - "\\small", - "\\normalsize", - "\\large", - "\\Large", - "\\LARGE", - "\\huge", - "\\Huge" - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ breakOnTokenText, funcName, parser }, args) => { - if (parser.settings.strict && parser.mode === "math") { - // eslint-disable-next-line no-console - console.log(`Temml strict-mode warning: Command ${funcName} is invalid in math mode.`); - } - const body = parser.parseExpression(false, breakOnTokenText); - return { - type: "sizing", - mode: parser.mode, - funcName, - body - }; - }, - mathmlBuilder: (group, style) => { - const newStyle = style.withFontSize(sizeMap[group.funcName]); - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - const factor = (sizeMap[group.funcName] / style.fontSize).toFixed(4); - node.setAttribute("mathsize", factor + "em"); - return node; - } -}); - -// smash, with optional [tb], as in AMS - -defineFunction({ - type: "smash", - names: ["\\smash"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args, optArgs) => { - let smashHeight = false; - let smashDepth = false; - const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); - if (tbArg) { - // Optional [tb] argument is engaged. - // ref: amsmath: \renewcommand{\smash}[1][tb]{% - // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% - let letter = ""; - for (let i = 0; i < tbArg.body.length; ++i) { - const node = tbArg.body[i]; - // TODO: Write an AssertSymbolNode - letter = node.text; - if (letter === "t") { - smashHeight = true; - } else if (letter === "b") { - smashDepth = true; - } else { - smashHeight = false; - smashDepth = false; - break; - } - } - } else { - smashHeight = true; - smashDepth = true; - } - - const body = args[0]; - return { - type: "smash", - mode: parser.mode, - body, - smashHeight, - smashDepth - }; - }, - mathmlBuilder: (group, style) => { - const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, style)]); - - if (group.smashHeight) { - node.setAttribute("height", "0px"); - } - - if (group.smashDepth) { - node.setAttribute("depth", "0px"); - } - - return node; - } -}); - -defineFunction({ - type: "sqrt", - names: ["\\sqrt"], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser }, args, optArgs) { - const index = optArgs[0]; - const body = args[0]; - return { - type: "sqrt", - mode: parser.mode, - body, - index - }; - }, - mathmlBuilder(group, style) { - const { body, index } = group; - return index - ? new mathMLTree.MathNode("mroot", [ - buildGroup$1(body, style), - buildGroup$1(index, style.incrementLevel()) - ]) - : new mathMLTree.MathNode("msqrt", [buildGroup$1(body, style)]); - } -}); - -const styleMap = { - display: 0, - text: 1, - script: 2, - scriptscript: 3 -}; - -const styleAttributes = { - display: ["0", "true"], - text: ["0", "false"], - script: ["1", "false"], - scriptscript: ["2", "false"] -}; - -defineFunction({ - type: "styling", - names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ breakOnTokenText, funcName, parser }, args) { - // parse out the implicit body - const body = parser.parseExpression(true, breakOnTokenText); - - const scriptLevel = funcName.slice(1, funcName.length - 5); - return { - type: "styling", - mode: parser.mode, - // Figure out what scriptLevel to use by pulling out the scriptLevel from - // the function name - scriptLevel, - body - }; - }, - mathmlBuilder(group, style) { - // Figure out what scriptLevel we're changing to. - const newStyle = style.withLevel(styleMap[group.scriptLevel]); - // The style argument in the next line does NOT directly set a MathML script level. - // It just tracks the style level, in case we need to know it for supsub or mathchoice. - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - - const attr = styleAttributes[group.scriptLevel]; - - // Here is where we set the MathML script level. - node.setAttribute("scriptlevel", attr[0]); - node.setAttribute("displaystyle", attr[1]); - - return node; - } -}); - -/** - * Sometimes, groups perform special rules when they have superscripts or - * subscripts attached to them. This function lets the `supsub` group know that - * Sometimes, groups perform special rules when they have superscripts or - * its inner element should handle the superscripts and subscripts instead of - * handling them itself. - */ - -// Helpers -const symbolRegEx = /^m(over|under|underover)$/; - -// Super scripts and subscripts, whose precise placement can depend on other -// functions that precede them. -defineFunctionBuilders({ - type: "supsub", - mathmlBuilder(group, style) { - // Is the inner group a relevant horizonal brace? - let isBrace = false; - let isOver; - let isSup; - let appendApplyFunction = false; - let needsLeadingSpace = false; - - if (group.base && group.base.type === "horizBrace") { - isSup = !!group.sup; - if (isSup === group.base.isOver) { - isBrace = true; - isOver = group.base.isOver; - } - } - - if (group.base && !group.base.stack && - (group.base.type === "op" || group.base.type === "operatorname")) { - group.base.parentIsSupSub = true; - appendApplyFunction = !group.base.symbol; - needsLeadingSpace = group.base.needsLeadingSpace; - } - - const children = group.base && group.base.stack - ? [buildGroup$1(group.base.body[0], style)] - : [buildGroup$1(group.base, style)]; - - const childStyle = style.inSubOrSup(); - if (group.sub) { - children.push(buildGroup$1(group.sub, childStyle)); - } - - if (group.sup) { - children.push(buildGroup$1(group.sup, childStyle)); - } - - let nodeType; - if (isBrace) { - nodeType = isOver ? "mover" : "munder"; - } else if (!group.sub) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "mover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "mover"; - } else { - nodeType = "msup"; - } - } else if (!group.sup) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munder"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "munder"; - } else { - nodeType = "msub"; - } - } else { - const base = group.base; - if (base && ((base.type === "op" && base.limits) || base.type === "multiscript") && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munderover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (style.level === StyleLevel.DISPLAY || base.limits) - ) { - nodeType = "munderover"; - } else { - nodeType = "msubsup"; - } - } - - let node = new mathMLTree.MathNode(nodeType, children); - if (appendApplyFunction) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (needsLeadingSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node = mathMLTree.newDocumentFragment([space, node, operator]); - } else { - node = mathMLTree.newDocumentFragment([node, operator]); - } - } else if (symbolRegEx.test(nodeType)) { - // Wrap in a . Otherwise Firefox stretchy parens will not stretch to include limits. - node = new mathMLTree.MathNode("mrow", [node]); - } - - return node - } -}); - -// Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js. - -const short = ["\\shortmid", "\\nshortmid", "\\shortparallel", - "\\nshortparallel", "\\smallsetminus"]; - -defineFunctionBuilders({ - type: "atom", - mathmlBuilder(group, style) { - const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]); - if (group.family === "punct") { - node.setAttribute("separator", "true"); - } else if (group.family === "open" || group.family === "close") { - // Delims built here should not stretch vertically. - // See delimsizing.js for stretchy delims. - if (group.family === "open") { - node.setAttribute("form", "prefix"); - // Set an explicit attribute for stretch. Otherwise Firefox may do it wrong. - node.setAttribute("stretchy", "false"); - } else if (group.family === "close") { - node.setAttribute("form", "postfix"); - node.setAttribute("stretchy", "false"); - } - } else if (group.text === "\\mid") { - // Firefox messes up this spacing if at the end of an . See it explicitly. - node.setAttribute("lspace", "0.22em"); // medium space - node.setAttribute("rspace", "0.22em"); - node.setAttribute("stretchy", "false"); - } else if (short.includes(group.text)) { - node.setAttribute("mathsize", "70%"); - } else if (group.text === ":") { - // ":" is not in the MathML operator dictionary. Give it BIN spacing. - node.attributes.lspace = "0.2222em"; - node.attributes.rspace = "0.2222em"; - } - return node; - } -}); - -/** - * Maps TeX font commands to "mathvariant" attribute in buildMathML.js - */ -const fontMap = { - // styles - mathbf: "bold", - mathrm: "normal", - textit: "italic", - mathit: "italic", - mathnormal: "italic", - - // families - mathbb: "double-struck", - mathcal: "script", - mathfrak: "fraktur", - mathscr: "script", - mathsf: "sans-serif", - mathtt: "monospace", - oldstylenums: "oldstylenums" -}; - -/** - * Returns the math variant as a string or null if none is required. - */ -const getVariant = function(group, style) { - // Handle font specifiers as best we can. - // Chromium does not support the MathML mathvariant attribute. - // So we'll use Unicode replacement characters instead. - // But first, determine the math variant. - - // Deal with the \textit, \textbf, etc., functions. - if (style.fontFamily === "texttt") { - return "monospace" - } else if (style.fontFamily === "textsc") { - return "normal"; // handled via character substitution in symbolsOrd.js. - } else if (style.fontFamily === "textsf") { - if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "sans-serif-bold-italic" - } else if (style.fontShape === "textit") { - return "sans-serif-italic" - } else if (style.fontWeight === "textbf") { - return "sans-serif-bold" - } else { - return "sans-serif" - } - } else if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "bold-italic" - } else if (style.fontShape === "textit") { - return "italic" - } else if (style.fontWeight === "textbf") { - return "bold" - } - - // Deal with the \mathit, mathbf, etc, functions. - const font = style.font; - if (!font || font === "mathnormal") { - return null - } - - const mode = group.mode; - switch (font) { - case "mathit": - return "italic" - case "mathrm": { - const codePoint = group.text.codePointAt(0); - // LaTeX \mathrm returns italic for Greek characters. - return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal" - } - case "greekItalic": - return "italic" - case "up@greek": - return "normal" - case "boldsymbol": - case "mathboldsymbol": - return "bold-italic" - case "mathbf": - return "bold" - case "mathbb": - return "double-struck" - case "mathfrak": - return "fraktur" - case "mathscr": - case "mathcal": - return "script" - case "mathsf": - return "sans-serif" - case "mathtt": - return "monospace" - case "oldstylenums": - return "oldstylenums" - } - - let text = group.text; - if (symbols[mode][text] && symbols[mode][text].replace) { - text = symbols[mode][text].replace; - } - - return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null -}; - -// Chromium does not support the MathML `mathvariant` attribute. -// Instead, we replace ASCII characters with Unicode characters that -// are defined in the font as bold, italic, double-struck, etc. -// This module identifies those Unicode code points. - -// First, a few helpers. -const script = Object.freeze({ - B: 0x20EA, // Offset from ASCII B to Unicode script B - E: 0x20EB, - F: 0x20EB, - H: 0x20C3, - I: 0x20C7, - L: 0x20C6, - M: 0x20E6, - R: 0x20C9, - e: 0x20CA, - g: 0x20A3, - o: 0x20C5 -}); - -const frak = Object.freeze({ - C: 0x20EA, - H: 0x20C4, - I: 0x20C8, - R: 0x20CA, - Z: 0x20CE -}); - -const bbb = Object.freeze({ - C: 0x20BF, // blackboard bold - H: 0x20C5, - N: 0x20C7, - P: 0x20C9, - Q: 0x20C9, - R: 0x20CB, - Z: 0x20CA -}); - -const bold = Object.freeze({ - "\u03f5": 0x1D2E7, // lunate epsilon - "\u03d1": 0x1D30C, // vartheta - "\u03f0": 0x1D2EE, // varkappa - "\u03c6": 0x1D319, // varphi - "\u03f1": 0x1D2EF, // varrho - "\u03d6": 0x1D30B // varpi -}); - -const boldItalic = Object.freeze({ - "\u03f5": 0x1D35B, // lunate epsilon - "\u03d1": 0x1D380, // vartheta - "\u03f0": 0x1D362, // varkappa - "\u03c6": 0x1D38D, // varphi - "\u03f1": 0x1D363, // varrho - "\u03d6": 0x1D37F // varpi -}); - -const boldsf = Object.freeze({ - "\u03f5": 0x1D395, // lunate epsilon - "\u03d1": 0x1D3BA, // vartheta - "\u03f0": 0x1D39C, // varkappa - "\u03c6": 0x1D3C7, // varphi - "\u03f1": 0x1D39D, // varrho - "\u03d6": 0x1D3B9 // varpi -}); - -const bisf = Object.freeze({ - "\u03f5": 0x1D3CF, // lunate epsilon - "\u03d1": 0x1D3F4, // vartheta - "\u03f0": 0x1D3D6, // varkappa - "\u03c6": 0x1D401, // varphi - "\u03f1": 0x1D3D7, // varrho - "\u03d6": 0x1D3F3 // varpi -}); - -// Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf -const offset = Object.freeze({ - upperCaseLatin: { // A-Z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3BF }, - "italic": ch => { return 0x1D3F3 }, - "bold-italic": ch => { return 0x1D427 }, - "script": ch => { return script[ch] || 0x1D45B }, - "script-bold": ch => { return 0x1D48F }, - "fraktur": ch => { return frak[ch] || 0x1D4C3 }, - "fraktur-bold": ch => { return 0x1D52B }, - "double-struck": ch => { return bbb[ch] || 0x1D4F7 }, - "sans-serif": ch => { return 0x1D55F }, - "sans-serif-bold": ch => { return 0x1D593 }, - "sans-serif-italic": ch => { return 0x1D5C7 }, - "sans-serif-bold-italic": ch => { return 0x1D63C }, - "monospace": ch => { return 0x1D62F } - }, - lowerCaseLatin: { // a-z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3B9 }, - "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED }, - "bold-italic": ch => { return 0x1D421 }, - "script": ch => { return script[ch] || 0x1D455 }, - "script-bold": ch => { return 0x1D489 }, - "fraktur": ch => { return 0x1D4BD }, - "fraktur-bold": ch => { return 0x1D525 }, - "double-struck": ch => { return 0x1D4F1 }, - "sans-serif": ch => { return 0x1D559 }, - "sans-serif-bold": ch => { return 0x1D58D }, - "sans-serif-italic": ch => { return 0x1D5C1 }, - "sans-serif-bold-italic": ch => { return 0x1D5F5 }, - "monospace": ch => { return 0x1D629 } - }, - upperCaseGreek: { // A-Ω ∇ - "normal": ch => { return 0 }, - "bold": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "italic": ch => { return ch === "∇" ? 0x1B4F4 : 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-bold": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return ch === "∇" ? 0x1B5A2 : 0x1D3FF }, - "monospace": ch => { return 0 } - }, - lowerCaseGreek: { // α-ω - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D311 }, - "italic": ch => { return 0x1D34B }, - "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return 0x1D3BF }, - "sans-serif-bold": ch => { return 0x1D3BF }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0x1D3F9 }, - "monospace": ch => { return 0 } - }, - varGreek: { // \varGamma, etc - "normal": ch => { return 0 }, - "bold": ch => { return bold[ch] || -51 }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return boldItalic[ch] || 0x3A }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - "sans-serif": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-bold": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE }, - "monospace": ch => { return 0 } - }, - numeral: { // 0-9 - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D79E }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return 0 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0x1D7A8 }, - "sans-serif": ch => { return 0x1D7B2 }, - "sans-serif-bold": ch => { return 0x1D7BC }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0 }, - "monospace": ch => { return 0x1D7C6 } - } -}); - -const variantChar = (ch, variant) => { - const codePoint = ch.codePointAt(0); - const block = 0x40 < codePoint && codePoint < 0x5b - ? "upperCaseLatin" - : 0x60 < codePoint && codePoint < 0x7b - ? "lowerCaseLatin" - : (0x390 < codePoint && codePoint < 0x3AA) || ch === "∇" - ? "upperCaseGreek" - : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5" - ? "lowerCaseGreek" - : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch] - ? "varGreek" - : (0x2F < codePoint && codePoint < 0x3A) - ? "numeral" - : "other"; - return block === "other" - ? ch - : String.fromCodePoint(codePoint + offset[block][variant](ch)) -}; - -const smallCaps = Object.freeze({ - a: "ᴀ", - b: "ʙ", - c: "ᴄ", - d: "ᴅ", - e: "ᴇ", - f: "ꜰ", - g: "ɢ", - h: "ʜ", - i: "ɪ", - j: "ᴊ", - k: "ᴋ", - l: "ʟ", - m: "ᴍ", - n: "ɴ", - o: "ᴏ", - p: "ᴘ", - q: "ǫ", - r: "ʀ", - s: "s", - t: "ᴛ", - u: "ᴜ", - v: "ᴠ", - w: "ᴡ", - x: "x", - y: "ʏ", - z: "ᴢ" -}); - -// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in -// src/symbols.js. - -const numberRegEx$1 = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in Parser.js - -const latinRegEx = /[A-Ba-z]/; - -const italicNumber = (text, variant) => { - const mn = new mathMLTree.MathNode("mn", [text]); - const wrapper = new mathMLTree.MathNode("mstyle", [mn]); - wrapper.style["font-style"] = "italic"; - wrapper.style["font-family"] = "Cambria, 'Times New Roman', serif"; - if (variant === "bold-italic") { wrapper.style["font-weight"] = "bold"; } - return wrapper -}; - -defineFunctionBuilders({ - type: "mathord", - mathmlBuilder(group, style) { - const text = makeText(group.text, group.mode, style); - const codePoint = text.text.codePointAt(0); - // Test for upper-case Greek - const defaultVariant = (0x0390 < codePoint && codePoint < 0x03aa) ? "normal" : "italic"; - const variant = getVariant(group, style) || defaultVariant; - if (variant === "script") { - text.text = variantChar(text.text, variant); - return new mathMLTree.MathNode("mi", [text], [style.font]) - } else if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - let node = new mathMLTree.MathNode("mi", [text]); - // TODO: Handle U+1D49C - U+1D4CF per https://www.unicode.org/charts/PDF/U1D400.pdf - if (variant === "normal") { - node.setAttribute("mathvariant", "normal"); - if (text.text.length === 1) { - // A Firefox bug will apply spacing here, but there should be none. Fix it. - node = new mathMLTree.MathNode("mpadded", [node]); - node.setAttribute("lspace", "0"); - node.setAttribute("width", "+0em"); - } - } - return node - } -}); - -defineFunctionBuilders({ - type: "textord", - mathmlBuilder(group, style) { - let ch = group.text; - const codePoint = ch.codePointAt(0); - if (style.fontFamily === "textsc") { - // Convert small latin letters to small caps. - if (96 < codePoint && codePoint < 123) { - ch = smallCaps[ch]; - } - } - const text = makeText(ch, group.mode, style); - const variant = getVariant(group, style) || "normal"; - - let node; - if (group.mode === "text") { - if (variant === "italic" || variant === "bold-italic") { - if (numberRegEx$1.test(group.text)) { - return italicNumber(text, variant) - } - } - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (numberRegEx$1.test(group.text)) { - if (variant === "oldstylenums") { - const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]); - node = new mathMLTree.MathNode("mn", [ms]); - } else if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode("mn", [text]); - } - } else if (group.text === "\\prime") { - node = new mathMLTree.MathNode("mo", [text]); - } else { - const origText = text.text; - if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mi", [text]); - if (text.text === origText && latinRegEx.test(origText)) { - node.setAttribute("mathvariant", "italic"); - } - } - return node - } -}); - -// A map of CSS-based spacing functions to their CSS class. -const cssSpace = { - "\\nobreak": "nobreak", - "\\allowbreak": "allowbreak" -}; - -// A lookup table to determine whether a spacing function/symbol should be -// treated like a regular space character. If a symbol or command is a key -// in this table, then it should be a regular space character. Furthermore, -// the associated value may have a `className` specifying an extra CSS class -// to add to the created `span`. -const regularSpace = { - " ": {}, - "\\ ": {}, - "~": { - className: "nobreak" - }, - "\\space": {}, - "\\nobreakspace": { - className: "nobreak" - } -}; - -// ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in -// src/symbols.js. -defineFunctionBuilders({ - type: "spacing", - mathmlBuilder(group, style) { - let node; - - if (Object.prototype.hasOwnProperty.call(regularSpace, group.text)) { - // Firefox does not render a space in a . So write a no-break space. - // TODO: If Firefox fixes that bug, uncomment the next line and write ch into the node. - //const ch = (regularSpace[group.text].className === "nobreak") ? "\u00a0" : " " - node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]); - } else if (Object.prototype.hasOwnProperty.call(cssSpace, group.text)) { - // MathML 3.0 calls for nobreak to occur in an , not an - // Ref: https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs - node = new mathMLTree.MathNode("mo"); - if (group.text === "\\nobreak") { - node.setAttribute("linebreak", "nobreak"); - } - } else { - throw new ParseError(`Unknown type of space "${group.text}"`) - } - - return node - } -}); - -defineFunctionBuilders({ - type: "tag" -}); - -// For a \tag, the work usually done in a mathmlBuilder is instead done in buildMathML.js. -// That way, a \tag can be pulled out of the parse tree and wrapped around the outer node. - -// Non-mathy text, possibly in a font -const textFontFamilies = { - "\\text": undefined, - "\\textrm": "textrm", - "\\textsf": "textsf", - "\\texttt": "texttt", - "\\textnormal": "textrm", - "\\textsc": "textsc" // small caps -}; - -const textFontWeights = { - "\\textbf": "textbf", - "\\textmd": "textmd" -}; - -const textFontShapes = { - "\\textit": "textit", - "\\textup": "textup" -}; - -const styleWithFont = (group, style) => { - const font = group.font; - // Checks if the argument is a font family or a font style. - if (!font) { - return style; - } else if (textFontFamilies[font]) { - return style.withTextFontFamily(textFontFamilies[font]); - } else if (textFontWeights[font]) { - return style.withTextFontWeight(textFontWeights[font]); - } else { - return style.withTextFontShape(textFontShapes[font]); - } -}; - -defineFunction({ - type: "text", - names: [ - // Font families - "\\text", - "\\textrm", - "\\textsf", - "\\texttt", - "\\textnormal", - "\\textsc", - // Font weights - "\\textbf", - "\\textmd", - // Font Shapes - "\\textit", - "\\textup" - ], - props: { - numArgs: 1, - argTypes: ["text"], - allowedInArgument: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "text", - mode: parser.mode, - body: ordargument(body), - font: funcName - }; - }, - mathmlBuilder(group, style) { - const newStyle = styleWithFont(group, style); - const mrow = buildExpressionRow(group.body, newStyle); - return utils.consolidateText(mrow) - } -}); - -// Two functions included to enable migration from Mathjax. - -defineFunction({ - type: "tip", - names: ["\\mathtip"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup$1(group.body, style); - const tip = buildGroup$1(group.tip, style); - // Browsers don't support the tooltip actiontype. - // TODO: Come back and fix \mathtip when it can be done via CSS w/o a JS event. - const node = new mathMLTree.MathNode("maction", [math, tip], ["tml-tip"]); - node.setAttribute("actiontype", "tooltip"); - return node - } -}); - -defineFunction({ - type: "tip", - names: ["\\texttip"], - props: { - numArgs: 2, - argTypes: ["math", "text"] - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup$1(group.body, style); - const tip = buildGroup$1(group.tip, style); - // args[1] only accepted text, so tip is a element or a of them. - let str = ""; - if (tip.type === "mtext") { - str = tip.children[0].text; - } else { - for (const child of tip.children) { - str += child.children[0].text; - } - } - // Implement \texttip via a title attribute. - math.setAttribute("title", str); - return math - } -}); - -defineFunctionBuilders({ - type: "toggle", - mathmlBuilder(group, style) { - const expression = buildExpression(group.body, style); - const node = new mathMLTree.MathNode("maction", expression, [], { cursor: "default" }); - node.setAttribute("actiontype", "toggle"); - return node - } -}); - -defineFunction({ - type: "underline", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "underline", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005f")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode("munder", - [buildGroup$1(group.body, style), operator] - ); - node.setAttribute("accentunder", "true"); - - return node; - } -}); - -defineFunction({ - type: "verb", - names: ["\\verb"], - props: { - numArgs: 0, - allowedInText: true - }, - handler(context, args, optArgs) { - // \verb and \verb* are dealt with directly in Parser.js. - // If we end up here, it's because of a failure to match the two delimiters - // in the regex in Lexer.js. LaTeX raises the following error when \verb is - // terminated by end of line (or file). - throw new ParseError("\\verb ended by end of line instead of matching delimiter"); - }, - mathmlBuilder(group, style) { - const text = new mathMLTree.TextNode(makeVerb(group)); - const node = new mathMLTree.MathNode("mtext", [text]); - node.setAttribute("mathvariant", "monospace"); - return node; - } -}); - -/** - * Converts verb group into body string. - * - * \verb* replaces each space with an open box \u2423 - * \verb replaces each space with a no-break space \xA0 - */ -const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0"); - -/** Include this to ensure that all functions are defined. */ - -const functions = _functions; - -/** - * Lexing or parsing positional information for error reporting. - * This object is immutable. - */ -class SourceLocation { - constructor(lexer, start, end) { - this.lexer = lexer; // Lexer holding the input string. - this.start = start; // Start offset, zero-based inclusive. - this.end = end; // End offset, zero-based exclusive. - } - - /** - * Merges two `SourceLocation`s from location providers, given they are - * provided in order of appearance. - * - Returns the first one's location if only the first is provided. - * - Returns a merged range of the first and the last if both are provided - * and their lexers match. - * - Otherwise, returns null. - */ - static range(first, second) { - if (!second) { - return first && first.loc; - } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { - return null; - } else { - return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); - } - } -} - -/** - * Interface required to break circular dependency between Token, Lexer, and - * ParseError. - */ - -/** - * The resulting token returned from `lex`. - * - * It consists of the token text plus some position information. - * The position information is essentially a range in an input string, - * but instead of referencing the bare input string, we refer to the lexer. - * That way it is possible to attach extra metadata to the input string, - * like for example a file name or similar. - * - * The position information is optional, so it is OK to construct synthetic - * tokens if appropriate. Not providing available position information may - * lead to degraded error reporting, though. - */ -class Token { - constructor( - text, // the text of this token - loc - ) { - this.text = text; - this.loc = loc; - } - - /** - * Given a pair of tokens (this and endToken), compute a `Token` encompassing - * the whole input range enclosed by these two. - */ - range( - endToken, // last token of the range, inclusive - text // the text of the newly constructed token - ) { - return new Token(text, SourceLocation.range(this, endToken)); - } -} - -/** - * The Lexer class handles tokenizing the input in various ways. Since our - * parser expects us to be able to backtrack, the lexer allows lexing from any - * given starting point. - * - * Its main exposed function is the `lex` function, which takes a position to - * lex from and a type of token to lex. It defers to the appropriate `_innerLex` - * function. - * - * The various `_innerLex` functions perform the actual lexing of different - * kinds. - */ - -/* The following tokenRegex - * - matches typical whitespace (but not NBSP etc.) using its first two groups - * - does not match any control character \x00-\x1f except whitespace - * - does not match a bare backslash - * - matches any ASCII character except those just mentioned - * - does not match the BMP private use area \uE000-\uF8FF - * - does not match bare surrogate code units - * - matches any BMP character except for those just described - * - matches any valid Unicode surrogate pair - * - mathches numerals - * - matches a backslash followed by one or more whitespace characters - * - matches a backslash followed by one or more letters then whitespace - * - matches a backslash followed by any BMP character - * Capturing groups: - * [1] regular whitespace - * [2] backslash followed by whitespace - * [3] anything else, which may include: - * [4] left character of \verb* - * [5] left character of \verb - * [6] backslash followed by word, excluding any trailing whitespace - * Just because the Lexer matches something doesn't mean it's valid input: - * If there is no matching function or symbol definition, the Parser will - * still reject the input. - */ -const spaceRegexString = "[ \r\n\t]"; -const controlWordRegexString = "\\\\[a-zA-Z@]+"; -const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; -const controlWordWhitespaceRegexString = `(${controlWordRegexString})${spaceRegexString}*`; -const controlSpaceRegexString = "\\\\(\n|[ \r\t]+\n?)[ \r\t]*"; -const combiningDiacriticalMarkString = "[\u0300-\u036f]"; -const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); -const tokenRegexString = - `(${spaceRegexString}+)|` + // whitespace - `${controlSpaceRegexString}|` + // whitespace - "(number" + // numbers (in non-strict mode) - "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|\\\\verb\\*([^]).*?\\4" + // \verb* - "|\\\\verb([^*a-zA-Z]).*?\\5" + // \verb unstarred - `|${controlWordWhitespaceRegexString}` + // \macroName + spaces - `|${controlSymbolRegexString})`; // \\, \', etc. - -/** Main Lexer class */ -class Lexer { - constructor(input, settings) { - // Separate accents from characters - this.input = input; - this.settings = settings; - this.tokenRegex = new RegExp( - // Strict Temml, like TeX, lexes one numeral at a time. - // Default Temml lexes contiguous numerals into a single element. - tokenRegexString.replace("number|", settings.strict ? "" : "\\d(?:[\\d,.]*\\d)?|"), - "g" - ); - // Category codes. The lexer only supports comment characters (14) for now. - // MacroExpander additionally distinguishes active (13). - this.catcodes = { - "%": 14, // comment character - "~": 13 // active character - }; - } - - setCatcode(char, code) { - this.catcodes[char] = code; - } - - /** - * This function lexes a single token. - */ - lex() { - const input = this.input; - const pos = this.tokenRegex.lastIndex; - if (pos === input.length) { - return new Token("EOF", new SourceLocation(this, pos, pos)); - } - const match = this.tokenRegex.exec(input); - if (match === null || match.index !== pos) { - throw new ParseError( - `Unexpected character: '${input[pos]}'`, - new Token(input[pos], new SourceLocation(this, pos, pos + 1)) - ); - } - const text = match[6] || match[3] || (match[2] ? "\\ " : " "); - - if (this.catcodes[text] === 14) { - // comment character - const nlIndex = input.indexOf("\n", this.tokenRegex.lastIndex); - if (nlIndex === -1) { - this.tokenRegex.lastIndex = input.length; // EOF - if (this.settings.strict) { - throw new ParseError("% comment has no terminating newline; LaTeX would " + - "fail because of commenting the end of math mode") - } - } else { - this.tokenRegex.lastIndex = nlIndex + 1; - } - return this.lex(); - } - - return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); - } -} - -/** - * A `Namespace` refers to a space of nameable things like macros or lengths, - * which can be `set` either globally or local to a nested group, using an - * undo stack similar to how TeX implements this functionality. - * Performance-wise, `get` and `set` take constant time. - */ - -class Namespace { - /** - * Both arguments are optional. The first argument is an object of - * built-in mappings which never change. The second argument is an object - * of initial (global-level) mappings, which will constantly change - * according to any global/top-level `set`s done. - */ - constructor(builtins = {}, globalMacros = {}) { - this.current = globalMacros; - this.builtins = builtins; - this.undefStack = []; - } - - /** - * Start a new nested group, affecting future local `set`s. - */ - beginGroup() { - this.undefStack.push({}); - } - - /** - * End current nested group, restoring values before the group began. - */ - endGroup() { - if (this.undefStack.length === 0) { - throw new ParseError( - "Unbalanced namespace destruction: attempt " + - "to pop global namespace; please report this as a bug" - ); - } - const undefs = this.undefStack.pop(); - for (const undef in undefs) { - if (Object.prototype.hasOwnProperty.call(undefs, undef )) { - if (undefs[undef] === undefined) { - delete this.current[undef]; - } else { - this.current[undef] = undefs[undef]; - } - } - } - } - - /** - * Detect whether `name` has a definition. Equivalent to - * `get(name) != null`. - */ - has(name) { - return Object.prototype.hasOwnProperty.call(this.current, name ) || - Object.prototype.hasOwnProperty.call(this.builtins, name ); - } - - /** - * Get the current value of a name, or `undefined` if there is no value. - * - * Note: Do not use `if (namespace.get(...))` to detect whether a macro - * is defined, as the definition may be the empty string which evaluates - * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or - * `if (namespace.has(...))`. - */ - get(name) { - if (Object.prototype.hasOwnProperty.call(this.current, name )) { - return this.current[name]; - } else { - return this.builtins[name]; - } - } - - /** - * Set the current value of a name, and adds an undo - * operation to the undo stack. - */ - set(name, value) { - // Undo this set at end of this group (possibly to `undefined`), - // unless an undo is already in place, in which case that older - // value is the correct one. - const top = this.undefStack[this.undefStack.length - 1]; - if (top && !Object.prototype.hasOwnProperty.call(top, name )) { - top[name] = this.current[name]; - } - this.current[name] = value; - } -} - -/** - * Predefined macros for Temml. - * This can be used to define some commands in terms of others. - */ -const macros = _macros; - -////////////////////////////////////////////////////////////////////// -// macro tools - -defineMacro("\\noexpand", function(context) { - // The expansion is the token itself; but that token is interpreted - // as if its meaning were ‘\relax’ if it is a control sequence that - // would ordinarily be expanded by TeX’s expansion rules. - const t = context.popToken(); - if (context.isExpandable(t.text)) { - t.noexpand = true; - t.treatAsRelax = true; - } - return { tokens: [t], numArgs: 0 }; -}); - -defineMacro("\\expandafter", function(context) { - // TeX first reads the token that comes immediately after \expandafter, - // without expanding it; let’s call this token t. Then TeX reads the - // token that comes after t (and possibly more tokens, if that token - // has an argument), replacing it by its expansion. Finally TeX puts - // t back in front of that expansion. - const t = context.popToken(); - context.expandOnce(true); // expand only an expandable token - return { tokens: [t], numArgs: 0 }; -}); - -// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 -// TeX source: \long\def\@firstoftwo#1#2{#1} -defineMacro("\\@firstoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[0], numArgs: 0 }; -}); - -// LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 -// TeX source: \long\def\@secondoftwo#1#2{#2} -defineMacro("\\@secondoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[1], numArgs: 0 }; -}); - -// LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) -// symbol that isn't a space, consuming any spaces but not consuming the -// first nonspace character. If that nonspace character matches #1, then -// the macro expands to #2; otherwise, it expands to #3. -defineMacro("\\@ifnextchar", function(context) { - const args = context.consumeArgs(3); // symbol, if, else - context.consumeSpaces(); - const nextToken = context.future(); - if (args[0].length === 1 && args[0][0].text === nextToken.text) { - return { tokens: args[1], numArgs: 0 }; - } else { - return { tokens: args[2], numArgs: 0 }; - } -}); - -// LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. -// If it is `*`, then it consumes the symbol, and the macro expands to #1; -// otherwise, the macro expands to #2 (without consuming the symbol). -// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} -defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); - -// LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode -defineMacro("\\TextOrMath", function(context) { - const args = context.consumeArgs(2); - if (context.mode === "text") { - return { tokens: args[0], numArgs: 0 }; - } else { - return { tokens: args[1], numArgs: 0 }; - } -}); - -const stringFromArg = arg => { - // Reverse the order of the arg and return a string. - let str = ""; - for (let i = arg.length - 1; i > -1; i--) { - str += arg[i].text; - } - return str -}; - -// Lookup table for parsing numbers in base 8 through 16 -const digitToNumber = { - 0: 0, - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - a: 10, - A: 10, - b: 11, - B: 11, - c: 12, - C: 12, - d: 13, - D: 13, - e: 14, - E: 14, - f: 15, - F: 15 -}; - -const nextCharNumber = context => { - const numStr = context.future().text; - if (numStr === "EOF") { return [null, ""] } - return [digitToNumber[numStr.charAt(0)], numStr] -}; - -const appendCharNumbers = (number, numStr, base) => { - for (let i = 1; i < numStr.length; i++) { - const digit = digitToNumber[numStr.charAt(i)]; - number *= base; - number += digit; - } - return number -}; - -// TeX \char makes a literal character (catcode 12) using the following forms: -// (see The TeXBook, p. 43) -// \char123 -- decimal -// \char'123 -- octal -// \char"123 -- hex -// \char`x -- character that can be written (i.e. isn't active) -// \char`\x -- character that cannot be written (e.g. %) -// These all refer to characters from the font, so we turn them into special -// calls to a function \@char dealt with in the Parser. -defineMacro("\\char", function(context) { - let token = context.popToken(); - let base; - let number = ""; - if (token.text === "'") { - base = 8; - token = context.popToken(); - } else if (token.text === '"') { - base = 16; - token = context.popToken(); - } else if (token.text === "`") { - token = context.popToken(); - if (token.text[0] === "\\") { - number = token.text.charCodeAt(1); - } else if (token.text === "EOF") { - throw new ParseError("\\char` missing argument"); - } else { - number = token.text.charCodeAt(0); - } - } else { - base = 10; - } - if (base) { - // Parse a number in the given base, starting with first `token`. - let numStr = token.text; - number = digitToNumber[numStr.charAt(0)]; - if (number == null || number >= base) { - throw new ParseError(`Invalid base-${base} digit ${token.text}`); - } - number = appendCharNumbers(number, numStr, base); - let digit; - [digit, numStr] = nextCharNumber(context); - while (digit != null && digit < base) { - number *= base; - number += digit; - number = appendCharNumbers(number, numStr, base); - context.popToken(); - [digit, numStr] = nextCharNumber(context); - } - } - return `\\@char{${number}}`; -}); - -// The Latin Modern font renders at the wrong vertical alignment. -// This macro provides a better rendering. -defineMacro("\\surd", "\\sqrt{}"); - -defineMacro("\\hbox", "\\text{#1}"); - -// Per TeXbook p.122, "/" gets zero operator spacing. -// And MDN recommends using U+2044 instead of / for inline -defineMacro("/", "{\u2044}"); - -// Since Temml has no \par, ignore \long. -defineMacro("\\long", ""); - -////////////////////////////////////////////////////////////////////// -// Grouping -// \let\bgroup={ \let\egroup=} -defineMacro("\\bgroup", "{"); -defineMacro("\\egroup", "}"); - -// Symbols from latex.ltx: -// \def~{\nobreakspace{}} -// \def\lq{`} -// \def\rq{'} -// \def \aa {\r a} -defineMacro("~", "\\nobreakspace"); -defineMacro("\\lq", "`"); -defineMacro("\\rq", "'"); -defineMacro("\\aa", "\\r a"); - -defineMacro("\\Bbbk", "\\Bbb{k}"); - -// \mathstrut from the TeXbook, p 360 -defineMacro("\\mathstrut", "\\vphantom{(}"); - -// \underbar from TeXbook p 353 -defineMacro("\\underbar", "\\underline{\\text{#1}}"); - -////////////////////////////////////////////////////////////////////// -// LaTeX_2ε - -// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ -// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} -// We'll call \varvdots, which gets a glyph from symbols.js. -// The zero-width rule gets us an equivalent to the vertical 6pt kern. -defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); -defineMacro("\u22ee", "\\vdots"); - -////////////////////////////////////////////////////////////////////// -// amsmath.sty -// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf - -//\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} -defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); - -// \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} -defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); - -// \def\iff{\DOTSB\;\Longleftrightarrow\;} -// \def\implies{\DOTSB\;\Longrightarrow\;} -// \def\impliedby{\DOTSB\;\Longleftarrow\;} -defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); -defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); -defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); - -// AMSMath's automatic \dots, based on \mdots@@ macro. -const dotsByToken = { - ",": "\\dotsc", - "\\not": "\\dotsb", - // \keybin@ checks for the following: - "+": "\\dotsb", - "=": "\\dotsb", - "<": "\\dotsb", - ">": "\\dotsb", - "-": "\\dotsb", - "*": "\\dotsb", - ":": "\\dotsb", - // Symbols whose definition starts with \DOTSB: - "\\DOTSB": "\\dotsb", - "\\coprod": "\\dotsb", - "\\bigvee": "\\dotsb", - "\\bigwedge": "\\dotsb", - "\\biguplus": "\\dotsb", - "\\bigcap": "\\dotsb", - "\\bigcup": "\\dotsb", - "\\prod": "\\dotsb", - "\\sum": "\\dotsb", - "\\bigotimes": "\\dotsb", - "\\bigoplus": "\\dotsb", - "\\bigodot": "\\dotsb", - "\\bigsqcap": "\\dotsb", - "\\bigsqcup": "\\dotsb", - "\\And": "\\dotsb", - "\\longrightarrow": "\\dotsb", - "\\Longrightarrow": "\\dotsb", - "\\longleftarrow": "\\dotsb", - "\\Longleftarrow": "\\dotsb", - "\\longleftrightarrow": "\\dotsb", - "\\Longleftrightarrow": "\\dotsb", - "\\mapsto": "\\dotsb", - "\\longmapsto": "\\dotsb", - "\\hookrightarrow": "\\dotsb", - "\\doteq": "\\dotsb", - // Symbols whose definition starts with \mathbin: - "\\mathbin": "\\dotsb", - // Symbols whose definition starts with \mathrel: - "\\mathrel": "\\dotsb", - "\\relbar": "\\dotsb", - "\\Relbar": "\\dotsb", - "\\xrightarrow": "\\dotsb", - "\\xleftarrow": "\\dotsb", - // Symbols whose definition starts with \DOTSI: - "\\DOTSI": "\\dotsi", - "\\int": "\\dotsi", - "\\oint": "\\dotsi", - "\\iint": "\\dotsi", - "\\iiint": "\\dotsi", - "\\iiiint": "\\dotsi", - "\\idotsint": "\\dotsi", - // Symbols whose definition starts with \DOTSX: - "\\DOTSX": "\\dotsx" -}; - -defineMacro("\\dots", function(context) { - // TODO: If used in text mode, should expand to \textellipsis. - // However, in Temml, \textellipsis and \ldots behave the same - // (in text mode), and it's unlikely we'd see any of the math commands - // that affect the behavior of \dots when in text mode. So fine for now - // (until we support \ifmmode ... \else ... \fi). - let thedots = "\\dotso"; - const next = context.expandAfterFuture().text; - if (next in dotsByToken) { - thedots = dotsByToken[next]; - } else if (next.slice(0, 4) === "\\not") { - thedots = "\\dotsb"; - } else if (next in symbols.math) { - if (utils.contains(["bin", "rel"], symbols.math[next].group)) { - thedots = "\\dotsb"; - } - } - return thedots; -}); - -const spaceAfterDots = { - // \rightdelim@ checks for the following: - ")": true, - "]": true, - "\\rbrack": true, - "\\}": true, - "\\rbrace": true, - "\\rangle": true, - "\\rceil": true, - "\\rfloor": true, - "\\rgroup": true, - "\\rmoustache": true, - "\\right": true, - "\\bigr": true, - "\\biggr": true, - "\\Bigr": true, - "\\Biggr": true, - // \extra@ also tests for the following: - $: true, - // \extrap@ checks for the following: - ";": true, - ".": true, - ",": true -}; - -defineMacro("\\dotso", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\dotsc", function(context) { - const next = context.future().text; - // \dotsc uses \extra@ but not \extrap@, instead specially checking for - // ';' and '.', but doesn't check for ','. - if (next in spaceAfterDots && next !== ",") { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\cdots", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\@cdots\\,"; - } else { - return "\\@cdots"; - } -}); - -defineMacro("\\dotsb", "\\cdots"); -defineMacro("\\dotsm", "\\cdots"); -defineMacro("\\dotsi", "\\!\\cdots"); -defineMacro("\\idotsint", "\\dotsi"); -// amsmath doesn't actually define \dotsx, but \dots followed by a macro -// starting with \DOTSX implies \dotso, and then \extra@ detects this case -// and forces the added `\,`. -defineMacro("\\dotsx", "\\ldots\\,"); - -// \let\DOTSI\relax -// \let\DOTSB\relax -// \let\DOTSX\relax -defineMacro("\\DOTSI", "\\relax"); -defineMacro("\\DOTSB", "\\relax"); -defineMacro("\\DOTSX", "\\relax"); - -// Spacing, based on amsmath.sty's override of LaTeX defaults -// \DeclareRobustCommand{\tmspace}[3]{% -// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} -defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); -// \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\,", "{\\tmspace+{3mu}{.1667em}}"); -// \let\thinspace\, -defineMacro("\\thinspace", "\\,"); -// \def\>{\mskip\medmuskip} -// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} -// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\>", "\\mskip{4mu}"); -defineMacro("\\:", "{\\tmspace+{4mu}{.2222em}}"); -// \let\medspace\: -defineMacro("\\medspace", "\\:"); -// \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip = 5mu plus 5mu -defineMacro("\\;", "{\\tmspace+{5mu}{.2777em}}"); -// \let\thickspace\; -defineMacro("\\thickspace", "\\;"); -// \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\!", "{\\tmspace-{3mu}{.1667em}}"); -// \let\negthinspace\! -defineMacro("\\negthinspace", "\\!"); -// \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} -// TODO: math mode should use \medmuskip -defineMacro("\\negmedspace", "{\\tmspace-{4mu}{.2222em}}"); -// \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip -defineMacro("\\negthickspace", "{\\tmspace-{5mu}{.277em}}"); -// \def\enspace{\kern.5em } -defineMacro("\\enspace", "\\kern.5em "); -// \def\enskip{\hskip.5em\relax} -defineMacro("\\enskip", "\\hskip.5em\\relax"); -// \def\quad{\hskip1em\relax} -defineMacro("\\quad", "\\hskip1em\\relax"); -// \def\qquad{\hskip2em\relax} -defineMacro("\\qquad", "\\hskip2em\\relax"); - -// \tag@in@display form of \tag -defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); -defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); -defineMacro("\\tag@literal", (context) => { - if (context.macros.get("\\df@tag")) { - throw new ParseError("Multiple \\tag"); - } - return "\\def\\df@tag{\\text{#1}}"; -}); - -// \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin -// {\operator@font mod}\penalty900 -// \mkern5mu\nonscript\mskip-\medmuskip} -// \newcommand{\pod}[1]{\allowbreak -// \if@display\mkern18mu\else\mkern8mu\fi(#1)} -// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} -// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu -// \else\mkern12mu\fi{\operator@font mod}\,\,#1} -// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\bmod", "\\mathbin{\\text{mod}}"); -defineMacro( - "\\pod", - "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)" -); -defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); -defineMacro( - "\\mod", - "\\allowbreak" + - "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + - "{\\rm mod}\\,\\,#1" -); - -////////////////////////////////////////////////////////////////////// -// LaTeX source2e - -// \expandafter\let\expandafter\@normalcr -// \csname\expandafter\@gobble\string\\ \endcsname -// \DeclareRobustCommand\newline{\@normalcr\relax} -defineMacro("\\newline", "\\\\\\relax"); - -// \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} -// TODO: Doesn't normally work in math mode because \@ fails. -defineMacro("\\TeX", "\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"); - -defineMacro( - "\\LaTeX", - "\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX" -); - -defineMacro( - "\\Temml", - // eslint-disable-next-line max-len - "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}" -); - -// \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} -// \def\@hspace#1{\hskip #1\relax} -// \def\@hspacer#1{\vrule \@width\z@\nobreak -// \hskip #1\hskip \z@skip} -defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); -defineMacro("\\@hspace", "\\hskip #1\\relax"); -defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); - -defineMacro("\\colon", `\\mathpunct{\\char"3a}`); - -////////////////////////////////////////////////////////////////////// -// mathtools.sty - -defineMacro("\\prescript", "\\pres@cript{_{#1}^{#2}}{}{#3}"); - -//\providecommand\ordinarycolon{:} -defineMacro("\\ordinarycolon", `\\char"3a`); -// Raise to center on the math axis, as closely as possible. -defineMacro("\\vcentcolon", "\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}}"); -// \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\coloneq", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2212}'); -// \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\Coloneq", '\\mathrel{\\char"2237\\char"2212}'); -// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqqcolon", '\\mathrel{\\char"3d\\char"2237}'); -// \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqcolon", '\\mathrel{\\char"2212\\char"2237}'); -// \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\colonapprox", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"2248}'); -// \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\Colonapprox", '\\mathrel{\\char"2237\\char"2248}'); -// \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); -// \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\Colonsim", '\\mathrel{\\raisebox{0.035em}{\\ordinarycolon}\\char"223c}'); - -////////////////////////////////////////////////////////////////////// -// colonequals.sty - -// Alternate names for mathtools's macros: -defineMacro("\\ratio", "\\vcentcolon"); -defineMacro("\\coloncolon", "\\dblcolon"); -defineMacro("\\colonequals", "\\coloneqq"); -defineMacro("\\coloncolonequals", "\\Coloneqq"); -defineMacro("\\equalscolon", "\\eqqcolon"); -defineMacro("\\equalscoloncolon", "\\Eqqcolon"); -defineMacro("\\colonminus", "\\coloneq"); -defineMacro("\\coloncolonminus", "\\Coloneq"); -defineMacro("\\minuscolon", "\\eqcolon"); -defineMacro("\\minuscoloncolon", "\\Eqcolon"); -// \colonapprox name is same in mathtools and colonequals. -defineMacro("\\coloncolonapprox", "\\Colonapprox"); -// \colonsim name is same in mathtools and colonequals. -defineMacro("\\coloncolonsim", "\\Colonsim"); - -// Present in newtxmath, pxfonts and txfonts -defineMacro("\\notni", "\\mathrel{\\char`\u220C}"); -defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); -defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); - -////////////////////////////////////////////////////////////////////// -// From amsopn.sty -defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}"); -defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}"); -defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"); -defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"); -defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"); -defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"); - -defineMacro("\\centerdot", "{\\medspace\\rule{0.167em}{0.189em}\\medspace}"); - -////////////////////////////////////////////////////////////////////// -// statmath.sty -// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf - -defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); -defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); -defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}"); - -////////////////////////////////////////////////////////////////////// -// braket.sty -// http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf - -defineMacro("\\bra", "\\mathinner{\\langle{#1}|}"); -defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}"); -defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}"); -defineMacro("\\Bra", "\\left\\langle#1\\right|"); -defineMacro("\\Ket", "\\left|#1\\right\\rangle"); -const braketHelper = (one) => (context) => { - const left = context.consumeArg().tokens; - const middle = context.consumeArg().tokens; - const middleDouble = context.consumeArg().tokens; - const right = context.consumeArg().tokens; - const oldMiddle = context.macros.get("|"); - const oldMiddleDouble = context.macros.get("\\|"); - context.macros.beginGroup(); - const midMacro = (double) => (context) => { - if (one) { - // Only modify the first instance of | or \| - context.macros.set("|", oldMiddle); - if (middleDouble.length) { - context.macros.set("\\|", oldMiddleDouble); - } - } - let doubled = double; - if (!double && middleDouble.length) { - // Mimic \@ifnextchar - const nextToken = context.future(); - if (nextToken.text === "|") { - context.popToken(); - doubled = true; - } - } - return { - tokens: doubled ? middleDouble : middle, - numArgs: 0 - }; - }; - context.macros.set("|", midMacro(false)); - if (middleDouble.length) { - context.macros.set("\\|", midMacro(true)); - } - const arg = context.consumeArg().tokens; - const expanded = context.expandTokens([...right, ...arg, ...left]); // reversed - context.macros.endGroup(); - return { - tokens: expanded.reverse(), - numArgs: 0 - }; -}; -defineMacro("\\bra@ket", braketHelper(false)); -defineMacro("\\bra@set", braketHelper(true)); -defineMacro("\\Braket", "\\bra@ket{\\left\\langle}" + - "{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"); -defineMacro("\\Set", "\\bra@set{\\left\\{\\:}" + - "{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"); -defineMacro("\\set", "\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"); - // has no support for special || or \| - -////////////////////////////////////////////////////////////////////// -// actuarialangle.dtx -defineMacro("\\angln", "{\\angl n}"); - -////////////////////////////////////////////////////////////////////// -// derivative.sty -defineMacro("\\odv", "\\@ifstar\\odv@next\\odv@numerator"); -defineMacro("\\odv@numerator", "\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}"); -defineMacro("\\odv@next", "\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1"); -defineMacro("\\pdv", "\\@ifstar\\pdv@next\\pdv@numerator"); - -const pdvHelper = args => { - const numerator = args[0][0].text; - const denoms = stringFromArg(args[1]).split(","); - const power = String(denoms.length); - const numOp = power === "1" ? "\\partial" : `\\partial^${power}`; - let denominator = ""; - denoms.map(e => { denominator += "\\partial " + e.trim() + "\\,";}); - return [numerator, numOp, denominator.replace(/\\,$/, "")] -}; -defineMacro("\\pdv@numerator", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp} ${numerator}}{${denominator}}` -}); -defineMacro("\\pdv@next", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp}}{${denominator}} ${numerator}` -}); - -////////////////////////////////////////////////////////////////////// -// upgreek.dtx -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\upbeta", "\\up@greek{\\beta}"); -defineMacro("\\upgamma", "\\up@greek{\\gamma}"); -defineMacro("\\updelta", "\\up@greek{\\delta}"); -defineMacro("\\upepsilon", "\\up@greek{\\epsilon}"); -defineMacro("\\upzeta", "\\up@greek{\\zeta}"); -defineMacro("\\upeta", "\\up@greek{\\eta}"); -defineMacro("\\uptheta", "\\up@greek{\\theta}"); -defineMacro("\\upiota", "\\up@greek{\\iota}"); -defineMacro("\\upkappa", "\\up@greek{\\kappa}"); -defineMacro("\\uplambda", "\\up@greek{\\lambda}"); -defineMacro("\\upmu", "\\up@greek{\\mu}"); -defineMacro("\\upnu", "\\up@greek{\\nu}"); -defineMacro("\\upxi", "\\up@greek{\\xi}"); -defineMacro("\\upomicron", "\\up@greek{\\omicron}"); -defineMacro("\\uppi", "\\up@greek{\\pi}"); -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\uprho", "\\up@greek{\\rho}"); -defineMacro("\\upsigma", "\\up@greek{\\sigma}"); -defineMacro("\\uptau", "\\up@greek{\\tau}"); -defineMacro("\\upupsilon", "\\up@greek{\\upsilon}"); -defineMacro("\\upphi", "\\up@greek{\\phi}"); -defineMacro("\\upchi", "\\up@greek{\\chi}"); -defineMacro("\\uppsi", "\\up@greek{\\psi}"); -defineMacro("\\upomega", "\\up@greek{\\omega}"); - -////////////////////////////////////////////////////////////////////// -// cmll package -defineMacro("\\invamp", '\\mathbin{\\char"214b}'); -defineMacro("\\parr", '\\mathbin{\\char"214b}'); -defineMacro("\\with", '\\mathbin{\\char"26}'); -defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}'); -defineMacro("\\multimapboth", '\\mathrel{\\char"29df}'); -defineMacro("\\scoh", '{\\mkern5mu\\char"2322\\mkern5mu}'); -defineMacro("\\sincoh", '{\\mkern5mu\\char"2323\\mkern5mu}'); -defineMacro("\\coh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2322}}} -{\\smash{\\lower4mu{\\char"2323}}}\\mkern5mu}`); -defineMacro("\\incoh", `{\\mkern5mu\\rule{}{0.7em}\\mathrlap{\\smash{\\raise2mu{\\char"2323}}} -{\\smash{\\lower4mu{\\char"2322}}}\\mkern5mu}`); - - -////////////////////////////////////////////////////////////////////// -// chemstyle package -defineMacro("\\standardstate", "\\text{\\tiny\\char`⦵}"); - -/* eslint-disable */ -/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ - -/************************************************************* - * - * Temml mhchem.js - * - * This file implements a Temml version of mhchem version 3.3.0. - * It is adapted from MathJax/extensions/TeX/mhchem.js - * It differs from the MathJax version as follows: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. - * 3. The reaction arrow code is simplified. All reaction arrows are rendered - * using Temml extensible arrows instead of building non-extensible arrows. - * 4. The ~bond forms are composed entirely of \rule elements. - * 5. Two dashes in _getBond are wrapped in braces to suppress spacing. i.e., {-} - * 6. The electron dot uses \textbullet instead of \bullet. - * - * This code, as other Temml code, is released under the MIT license. - * - * /************************************************************* - * - * MathJax/extensions/TeX/mhchem.js - * - * Implements the \ce command for handling chemical formulas - * from the mhchem LaTeX package. - * - * --------------------------------------------------------------------- - * - * Copyright (c) 2011-2015 The MathJax Consortium - * Copyright (c) 2015-2018 Martin Hensel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Coding Style -// - use '' for identifiers that can by minified/uglified -// - use "" for strings that need to stay untouched - -// version: "3.3.0" for MathJax and Temml - - -// Add \ce, \pu, and \tripleDash to the Temml macros. - -defineMacro("\\ce", function(context) { - return chemParse(context.consumeArgs(1)[0], "ce") -}); - -defineMacro("\\pu", function(context) { - return chemParse(context.consumeArgs(1)[0], "pu"); -}); - -// Math fonts do not include glyphs for the ~ form of bonds. So we'll send path geometry -// So we'll compose characters built from \rule elements. -defineMacro("\\uniDash", `{\\rule{0.672em}{0.06em}}`) -defineMacro("\\triDash", `{\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}\\kern2mu\\rule{0.15em}{0.06em}}`) -defineMacro("\\tripleDash", `\\kern0.075em\\raise0.25em{\\triDash}\\kern0.075em`) -defineMacro("\\tripleDashOverLine", `\\kern0.075em\\mathrlap{\\raise0.125em{\\uniDash}}\\raise0.34em{\\triDash}\\kern0.075em`) -defineMacro("\\tripleDashOverDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\triDash}}\\raise0.27em{\\uniDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`) -defineMacro("\\tripleDashBetweenDoubleLine", `\\kern0.075em\\mathrlap{\\mathrlap{\\raise0.48em{\\uniDash}}\\raise0.27em{\\triDash}}{\\raise0.05em{\\uniDash}}\\kern0.075em`) - - // - // This is the main function for handing the \ce and \pu commands. - // It takes the argument to \ce or \pu and returns the corresponding TeX string. - // - - var chemParse = function (tokens, stateMachine) { - // Recreate the argument string from Temml's array of tokens. - var str = ""; - var expectedLoc = tokens.length && tokens[tokens.length - 1].loc.start - for (var i = tokens.length - 1; i >= 0; i--) { - if(tokens[i].loc.start > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = tokens[i].loc.start; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - // Call the mhchem core parser. - var tex = texify.go(mhchemParser.go(str, stateMachine)); - return tex; - }; - - // - // Core parser for mhchem syntax (recursive) - // - /** @type {MhchemParser} */ - var mhchemParser = { - // - // Parses mchem \ce syntax - // - // Call like - // go("H2O"); - // - go: function (input, stateMachine) { - if (!input) { return []; } - if (stateMachine === undefined) { stateMachine = 'ce'; } - var state = '0'; - - // - // String buffers for parsing: - // - // buffer.a == amount - // buffer.o == element - // buffer.b == left-side superscript - // buffer.p == left-side subscript - // buffer.q == right-side subscript - // buffer.d == right-side superscript - // - // buffer.r == arrow - // buffer.rdt == arrow, script above, type - // buffer.rd == arrow, script above, content - // buffer.rqt == arrow, script below, type - // buffer.rq == arrow, script below, content - // - // buffer.text_ - // buffer.rm - // etc. - // - // buffer.parenthesisLevel == int, starting at 0 - // buffer.sb == bool, space before - // buffer.beginsWithBond == bool - // - // These letters are also used as state names. - // - // Other states: - // 0 == begin of main part (arrow/operator unlikely) - // 1 == next entity - // 2 == next entity (arrow/operator unlikely) - // 3 == next atom - // c == macro - // - /** @type {Buffer} */ - var buffer = {}; - buffer['parenthesisLevel'] = 0; - - input = input.replace(/\n/g, " "); - input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); - input = input.replace(/[\u2026]/g, "..."); - - // - // Looks through mhchemParser.transitions, to execute a matching action - // (recursive) - // - var lastInput; - var watchdog = 10; - /** @type {ParserOutput[]} */ - var output = []; - while (true) { - if (lastInput !== input) { - watchdog = 10; - lastInput = input; - } else { - watchdog--; - } - // - // Find actions in transition table - // - var machine = mhchemParser.stateMachines[stateMachine]; - var t = machine.transitions[state] || machine.transitions['*']; - iterateTransitions: - for (var i=0; i 0) { - if (!task.revisit) { - input = matches.remainder; - } - if (!task.toContinue) { - break iterateTransitions; - } - } else { - return output; - } - } - } - // - // Prevent infinite loop - // - if (watchdog <= 0) { - throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character - } - } - }, - concatArray: function (a, b) { - if (b) { - if (Array.isArray(b)) { - for (var iB=0; iB': /^[=<>]/, - '#': /^[#\u2261]/, - '+': /^\+/, - '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation - '-9': /^-(?=[0-9])/, - '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, - '-': /^-/, - 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, - 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, - 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, - '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, - '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, - 'CMT': /^[CMT](?=\[)/, - '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, - '1st-level escape': /^(&|\\\\|\\hline)\s*/, - '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before - '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, - '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, - '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, - '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, - 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway - 'others': /^[\/~|]/, - '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, - '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, - '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, - '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, - '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, - '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); }, - '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, - '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, - 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, - 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge - 'roman numeral': /^[IVX]+/, - '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, - 'amount': function (input) { - var match; - // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing - match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); - if (a) { // e.g. $2n-1$, $-$ - match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - } - return null; - }, - 'amount2': function (input) { return this['amount'](input); }, - '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, - 'formula$': function (input) { - if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula - var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - return null; - }, - 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, - '/': /^\s*(\/)\s*/, - '//': /^\s*(\/\/)\s*/, - '*': /^\s*[*.]\s*/ - }, - findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { - /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ - var _match = function (input, pattern) { - if (typeof pattern === "string") { - if (input.indexOf(pattern) !== 0) { return null; } - return pattern; - } else { - var match = input.match(pattern); - if (!match) { return null; } - return match[0]; - } - }; - /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ - var _findObserveGroups = function (input, i, endChars) { - var braces = 0; - while (i < input.length) { - var a = input.charAt(i); - var match = _match(input.substr(i), endChars); - if (match !== null && braces === 0) { - return { endMatchBegin: i, endMatchEnd: i + match.length }; - } else if (a === "{") { - braces++; - } else if (a === "}") { - if (braces === 0) { - throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; - } else { - braces--; - } - } - i++; - } - if (braces > 0) { - return null; - } - return null; - }; - var match = _match(input, begExcl); - if (match === null) { return null; } - input = input.substr(match.length); - match = _match(input, begIncl); - if (match === null) { return null; } - var e = _findObserveGroups(input, match.length, endIncl || endExcl); - if (e === null) { return null; } - var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); - if (!(beg2Excl || beg2Incl)) { - return { - match_: match1, - remainder: input.substr(e.endMatchEnd) - }; - } else { - var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); - if (group2 === null) { return null; } - /** @type {string[]} */ - var matchRet = [match1, group2.match_]; - return { - match_: (combine ? matchRet.join("") : matchRet), - remainder: group2.remainder - }; - } - }, - - // - // Matching function - // e.g. match("a", input) will look for the regexp called "a" and see if it matches - // returns null or {match_:"a", remainder:"bc"} - // - match_: function (m, input) { - var pattern = mhchemParser.patterns.patterns[m]; - if (pattern === undefined) { - throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern - } else if (typeof pattern === "function") { - return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser - } else { // RegExp - var match = input.match(pattern); - if (match) { - var mm; - if (match[2]) { - mm = [ match[1], match[2] ]; - } else if (match[1]) { - mm = match[1]; - } else { - mm = match[0]; - } - return { match_: mm, remainder: input.substr(match[0].length) }; - } - return null; - } - } - }, - - // - // Generic state machine actions - // - actions: { - 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; }, - 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; }, - 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; }, - 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; }, - 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; }, - 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; }, - 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; }, - 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; }, - 'insert': function (buffer, m, a) { return { type_: a }; }, - 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; }, - 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, - 'copy': function (buffer, m) { return m; }, - 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; }, - 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); }, - '{text}': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); - ret.push("}"); - return ret; - }, - 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); }, - 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); }, - 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, - 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; }, - 'ce': function (buffer, m) { return mhchemParser.go(m); }, - '1/2': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m.match(/^[+\-]/)) { - ret.push(m.substr(0, 1)); - m = m.substr(1); - } - var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); - n[1] = n[1].replace(/\$/g, ""); - ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); - if (n[3]) { - n[3] = n[3].replace(/\$/g, ""); - ret.push({ type_: 'tex-math', p1: n[3] }); - } - return ret; - }, - '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); } - }, - // - // createTransitions - // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } - // with expansion of 'a|b' to 'a' and 'b' (at 2 places) - // - createTransitions: function (o) { - var pattern, state; - /** @type {string[]} */ - var stateArray; - var i; - // - // 1. Collect all states - // - /** @type {Transitions} */ - var transitions = {}; - for (pattern in o) { - for (state in o[pattern]) { - stateArray = state.split("|"); - o[pattern][state].stateArray = stateArray; - for (i=0; i': { - '0|1|2|3': { action_: 'r=', nextState: 'r' }, - 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' }, - '*': { action_: [ 'output', 'r=' ], nextState: 'r' } }, - '+': { - 'o': { action_: 'd= kv', nextState: 'd' }, - 'd|D': { action_: 'd=', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd|qD': { action_: 'd=', nextState: 'qd' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' }, - '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - 'amount': { - '0|2': { action_: 'a=', nextState: 'a' } }, - 'pm-operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } }, - 'operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - '-$': { - 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' }, - 'd': { action_: 'd=', nextState: 'd' }, - 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd': { action_: 'd=', nextState: 'qd' }, - 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - '-9': { - '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } }, - '- orbital overlap': { - 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } }, - '-': { - '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' }, - '3': { action_: { type_: 'bond', option: "-" } }, - 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' }, - 'b': { action_: 'b=' }, - 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, - 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - 'amount2': { - '1|3': { action_: 'a=', nextState: 'a' } }, - 'letters': { - '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, - 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, - 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, - 'digits': { - 'o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q': { action_: [ 'output', 'o=' ], nextState: 'o' }, - 'a': { action_: 'o=', nextState: 'o' } }, - 'space A': { - 'b|p|bp': {} }, - 'space': { - 'a': { nextState: 'as' }, - '0': { action_: 'sb=false' }, - '1|2': { action_: 'sb=true' }, - 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, - '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} }, - '1st-level escape': { - '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] }, - '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } }, - '[(...)]': { - 'r|rt': { action_: 'rd=', nextState: 'rd' }, - 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, - '...': { - 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' }, - '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } }, - '. |* ': { - '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } }, - 'state of aggregation $': { - '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } }, - '{[(': { - 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } }, - ')]}': { - '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' }, - 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } }, - ', ': { - '*': { action_: [ 'output', 'comma' ], nextState: '0' } }, - '^_': { // ^ and _ without a sensible argument - '*': { } }, - '^{(...)}|^($...$)': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'D' }, - 'q': { action_: 'd=', nextState: 'qD' }, - 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } }, - '^a|^\\x{}{}|^\\x{}|^\\x|\'': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'd|qd|D|qD': { action_: 'd=' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } }, - '_{(state of aggregation)}$': { - 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { - '0|1|2|as': { action_: 'p=', nextState: 'p' }, - 'b': { action_: 'p=', nextState: 'bp' }, - '3|o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '=<>': { - '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } }, - '#': { - '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } }, - '{}': { - '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, - '{...}': { - '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, - 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '$...$': { - 'a': { action_: 'a=' }, // 2$n$ - '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount' - 'as|o': { action_: 'o=' }, - 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '\\bond{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } }, - '\\frac{(...)}': { - '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } }, - '\\overset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } }, - '\\underset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } }, - '\\underbrace{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } }, - '\\color{(...)}0': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } }, - '\\ce{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } }, - '\\,': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } }, - '\\x{}{}|\\x{}|\\x': { - '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' }, - '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } }, - 'others': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } }, - 'else2': { - 'a': { action_: 'a to o', nextState: 'o', revisit: true }, - 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true }, - 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true }, - '*': { action_: [ 'output', 'copy' ], nextState: '3' } } - }), - actions: { - 'o after d': function (buffer, m) { - var ret; - if ((buffer.d || "").match(/^[0-9]+$/)) { - var tmp = buffer.d; - buffer.d = undefined; - ret = this['output'](buffer); - buffer.b = tmp; - } else { - ret = this['output'](buffer); - } - mhchemParser.actions['o='](buffer, m); - return ret; - }, - 'd= kv': function (buffer, m) { - buffer.d = m; - buffer.dType = 'kv'; - }, - 'charge or bond': function (buffer, m) { - if (buffer['beginsWithBond']) { - /** @type {ParserOutput[]} */ - var ret = []; - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - return ret; - } else { - buffer.d = m; - } - }, - '- after o/d': function (buffer, m, isAfterD) { - var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); - var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); - var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); - var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); - var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 ); - if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { - buffer.o = '$' + buffer.o + '$'; - } - /** @type {ParserOutput[]} */ - var ret = []; - if (hyphenFollows) { - mhchemParser.concatArray(ret, this['output'](buffer)); - ret.push({ type_: 'hyphen' }); - } else { - c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); - if (isAfterD && c1 && c1.remainder==='') { - mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); - mhchemParser.concatArray(ret, this['output'](buffer)); - } else { - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - } - } - return ret; - }, - 'a to o': function (buffer) { - buffer.o = buffer.a; - buffer.a = undefined; - }, - 'sb=true': function (buffer) { buffer.sb = true; }, - 'sb=false': function (buffer) { buffer.sb = false; }, - 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; }, - 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; }, - 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; }, - 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; }, - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') }; - }, - 'comma': function (buffer, m) { - var a = m.replace(/\s*$/, ''); - var withSpace = (a !== m); - if (withSpace && buffer['parenthesisLevel'] === 0) { - return { type_: 'comma enumeration L', p1: a }; - } else { - return { type_: 'comma enumeration M', p1: a }; - } - }, - 'output': function (buffer, m, entityFollows) { - // entityFollows: - // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) - // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) - // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - if (!buffer.r) { - ret = []; - if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { - //ret = []; - } else { - if (buffer.sb) { - ret.push({ type_: 'entitySkip' }); - } - if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) { - buffer.o = buffer.a; - buffer.a = undefined; - } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { - buffer.o = buffer.a; - buffer.d = buffer.b; - buffer.q = buffer.p; - buffer.a = buffer.b = buffer.p = undefined; - } else { - if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { - buffer.dType = 'oxidation'; - } else if (buffer.o && buffer.dType==='kv' && !buffer.q) { - buffer.dType = undefined; - } - } - ret.push({ - type_: 'chemfive', - a: mhchemParser.go(buffer.a, 'a'), - b: mhchemParser.go(buffer.b, 'bd'), - p: mhchemParser.go(buffer.p, 'pq'), - o: mhchemParser.go(buffer.o, 'o'), - q: mhchemParser.go(buffer.q, 'pq'), - d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), - dType: buffer.dType - }); - } - } else { // r - /** @type {ParserOutput[]} */ - var rd; - if (buffer.rdt === 'M') { - rd = mhchemParser.go(buffer.rd, 'tex-math'); - } else if (buffer.rdt === 'T') { - rd = [ { type_: 'text', p1: buffer.rd || "" } ]; - } else { - rd = mhchemParser.go(buffer.rd); - } - /** @type {ParserOutput[]} */ - var rq; - if (buffer.rqt === 'M') { - rq = mhchemParser.go(buffer.rq, 'tex-math'); - } else if (buffer.rqt === 'T') { - rq = [ { type_: 'text', p1: buffer.rq || ""} ]; - } else { - rq = mhchemParser.go(buffer.rq); - } - ret = { - type_: 'arrow', - r: buffer.r, - rd: rd, - rq: rq - }; - } - for (var p in buffer) { - if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { - delete buffer[p]; - } - } - return ret; - }, - 'oxidation-output': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); - ret.push("}"); - return ret; - }, - 'frac-output': function (buffer, m) { - return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'overset-output': function (buffer, m) { - return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underset-output': function (buffer, m) { - return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underbrace-output': function (buffer, m) { - return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) }; - }, - 'r=': function (buffer, m) { buffer.r = m; }, - 'rdt=': function (buffer, m) { buffer.rdt = m; }, - 'rd=': function (buffer, m) { buffer.rd = m; }, - 'rqt=': function (buffer, m) { buffer.rqt = m; }, - 'rq=': function (buffer, m) { buffer.rq = m; }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } - } - }, - 'a': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - '$(...)$': { - '*': { action_: 'tex-math tight', nextState: '1' } }, - ',': { - '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'o': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - 'letters': { - '*': { action_: 'rm' } }, - '\\ca': { - '*': { action_: { type_: 'insert', option: 'circa' } } }, - '\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: '{text}' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'text': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '{...}': { - '*': { action_: 'text=' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '\\greek': { - '*': { action_: [ 'output', 'rm' ] } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: [ 'output', 'copy' ] } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.text_) { - /** @type {ParserOutput} */ - var ret = { type_: 'text', p1: buffer.text_ }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'pq': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'state of aggregation $': { - '*': { action_: 'state of aggregation' } }, - 'i$': { - '0': { nextState: '!f', revisit: true } }, - '(KV letters),': { - '0': { action_: 'rm', nextState: '0' } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'letters': { - '*': { action_: 'rm' } }, - '-9.,9': { - '*': { action_: '9,9' } }, - ',': { - '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') }; - } - } - }, - 'bd': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'x$': { - '0': { nextState: '!f', revisit: true } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '-9.,9 no missing 0': { - '*': { action_: '9,9' } }, - '.': { - '*': { action_: { type_: 'insert', option: 'electron dot' } } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'x': { - '*': { action_: { type_: 'insert', option: 'KV x' } } }, - 'letters': { - '*': { action_: 'rm' } }, - '\'': { - '*': { action_: { type_: 'insert', option: 'prime' } } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') }; - } - } - }, - 'oxidation': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'roman numeral': { - '*': { action_: 'roman-numeral' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; } - } - }, - 'tex-math': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'tex-math tight': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - '-|+': { - '*': { action_: 'tight operator' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; }, - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - '9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - ',': { - '*': { action_: 'comma' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; } - } - }, - //#endregion - // - // \pu state machines - // - //#region pu - 'pu': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - 'space$': { - '*': { action_: [ 'output', 'space' ] } }, - '{[(|)]}': { - '0|a': { action_: 'copy' } }, - '(-)(9)^(-9)': { - '0': { action_: 'number^', nextState: 'a' } }, - '(-)(9.,9)(e)(99)': { - '0': { action_: 'enumber', nextState: 'a' } }, - 'space': { - '0|a': {} }, - 'pm-operator': { - '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } }, - 'operator': { - '0|a': { action_: 'copy', nextState: '0' } }, - '//': { - 'd': { action_: 'o=', nextState: '/' } }, - '/': { - 'd': { action_: 'o=', nextState: '/' } }, - '{...}|else': { - '0|d': { action_: 'd=', nextState: 'd' }, - 'a': { action_: [ 'space', 'd=' ], nextState: 'd' }, - '/|q': { action_: 'q=', nextState: 'q' } } - }), - actions: { - 'enumber': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - if (m[1]) { - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - if (m[2]) { - if (m[2].match(/[,.]/)) { - mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); - } else { - ret.push(m[2]); - } - } - m[3] = m[4] || m[3]; - if (m[3]) { - m[3] = m[3].trim(); - if (m[3] === "e" || m[3].substr(0, 1) === "*") { - ret.push({ type_: 'cdot' }); - } else { - ret.push({ type_: 'times' }); - } - } - } - if (m[3]) { - ret.push("10^{"+m[5]+"}"); - } - return ret; - }, - 'number^': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - ret.push("^{"+m[2]+"}"); - return ret; - }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }, - 'space': function () { return { type_: 'pu-space-1' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); - if (md && md.remainder === '') { buffer.d = md.match_; } - var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); - if (mq && mq.remainder === '') { buffer.q = mq.match_; } - if (buffer.d) { - buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - } - if (buffer.q) { // fraction - buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - var b5 = { - d: mhchemParser.go(buffer.d, 'pu'), - q: mhchemParser.go(buffer.q, 'pu') - }; - if (buffer.o === '//') { - ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q }; - } else { - ret = b5.d; - if (b5.d.length > 1 || b5.q.length > 1) { - ret.push({ type_: ' / ' }); - } else { - ret.push({ type_: '/' }); - } - mhchemParser.concatArray(ret, b5.q); - } - } else { // no fraction - ret = mhchemParser.go(buffer.d, 'pu-2'); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-2': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '*': { - '*': { action_: [ 'output', 'cdot' ], nextState: '0' } }, - '\\x': { - '*': { action_: 'rm=' } }, - 'space': { - '*': { action_: [ 'output', 'space' ], nextState: '0' } }, - '^{(...)}|^(-1)': { - '1': { action_: '^(-1)' } }, - '-9.,9': { - '0': { action_: 'rm=', nextState: '0' }, - '1': { action_: '^(-1)', nextState: '0' } }, - '{...}|else': { - '*': { action_: 'rm=', nextState: '1' } } - }), - actions: { - 'cdot': function () { return { type_: 'tight cdot' }; }, - '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; }, - 'space': function () { return { type_: 'pu-space-2' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret = []; - if (buffer.rm) { - var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); - if (mrm && mrm.remainder === '') { - ret = mhchemParser.go(mrm.match_, 'pu'); - } else { - ret = { type_: 'rm', p1: buffer.rm }; - } - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '0': { action_: 'output-0' }, - 'o': { action_: 'output-o' } }, - ',': { - '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } }, - '.': { - '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; }, - 'output-0': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length % 3; - if (a === 0) { a = 3; } - for (var i=buffer.text_.length-3; i>0; i-=3) { - ret.push(buffer.text_.substr(i, 3)); - ret.push({ type_: '1000 separator' }); - } - ret.push(buffer.text_.substr(0, a)); - ret.reverse(); - } else { - ret.push(buffer.text_); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - }, - 'output-o': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length - 3; - for (var i=0; i, so we change \vphantom{X} to {} - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - } else { - if (b5.q) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - if (b5.d) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "^{"+b5.d+"}"; - } - } - break; - case 'rm': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'text': - if (buf.p1.match(/[\^_]/)) { - buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}"); - res = "\\mathrm{"+buf.p1+"}"; - } else { - res = "\\text{"+buf.p1+"}"; - } - break; - case 'roman numeral': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'state of aggregation': - res = "\\mskip2mu "+texify._goInner(buf.p1); - break; - case 'state of aggregation subscript': - res = "\\mskip1mu "+texify._goInner(buf.p1); - break; - case 'bond': - res = texify._getBond(buf.kind_); - if (!res) { - throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"]; - } - break; - case 'frac': - var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}"; - res = "\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}"; - break; - case 'pu-frac': - var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - res = "\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}"; - break; - case 'tex-math': - res = buf.p1 + " "; - break; - case 'frac-ce': - res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'overset': - res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underset': - res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underbrace': - res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}"; - break; - case 'color': - res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}"; - break; - case 'color0': - res = "\\color{" + buf.color + "}"; - break; - case 'arrow': - var b6 = { - rd: texify._goInner(buf.rd), - rq: texify._goInner(buf.rq) - }; - var arrow = texify._getArrow(buf.r); - if (b6.rq) { arrow += "[{\\rm " + b6.rq + "}]"; } - if (b6.rd) { - arrow += "{\\rm " + b6.rd + "}"; - } else { - arrow += "{}"; - } - res = arrow; - break; - case 'operator': - res = texify._getOperator(buf.kind_); - break; - case '1st-level escape': - res = buf.p1+" "; // &, \\\\, \\hlin - break; - case 'space': - res = " "; - break; - case 'entitySkip': - res = "~"; - break; - case 'pu-space-1': - res = "~"; - break; - case 'pu-space-2': - res = "\\mkern3mu "; - break; - case '1000 separator': - res = "\\mkern2mu "; - break; - case 'commaDecimal': - res = "{,}"; - break; - case 'comma enumeration L': - res = "{"+buf.p1+"}\\mkern6mu "; - break; - case 'comma enumeration M': - res = "{"+buf.p1+"}\\mkern3mu "; - break; - case 'comma enumeration S': - res = "{"+buf.p1+"}\\mkern1mu "; - break; - case 'hyphen': - res = "\\text{-}"; - break; - case 'addition compound': - res = "\\,{\\cdot}\\,"; - break; - case 'electron dot': - res = "\\mkern1mu \\text{\\textbullet}\\mkern1mu "; - break; - case 'KV x': - res = "{\\times}"; - break; - case 'prime': - res = "\\prime "; - break; - case 'cdot': - res = "\\cdot "; - break; - case 'tight cdot': - res = "\\mkern1mu{\\cdot}\\mkern1mu "; - break; - case 'times': - res = "\\times "; - break; - case 'circa': - res = "{\\sim}"; - break; - case '^': - res = "uparrow"; - break; - case 'v': - res = "downarrow"; - break; - case 'ellipsis': - res = "\\ldots "; - break; - case '/': - res = "/"; - break; - case ' / ': - res = "\\,/\\,"; - break; - default: - assertNever(buf); - throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output - } - assertString(res); - return res; - }, - _getArrow: function (a) { - switch (a) { - case "->": return "\\yields"; - case "\u2192": return "\\yields"; - case "\u27F6": return "\\yields"; - case "<-": return "\\yieldsLeft"; - case "<->": return "\\mesomerism"; - case "<-->": return "\\yieldsLeftRight"; - case "<=>": return "\\equilibrium"; - case "\u21CC": return "\\equilibrium"; - case "<=>>": return "\\equilibriumRight"; - case "<<=>": return "\\equilibriumLeft"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getBond: function (a) { - switch (a) { - case "-": return "{-}"; - case "1": return "{-}"; - case "=": return "{=}"; - case "2": return "{=}"; - case "#": return "{\\equiv}"; - case "3": return "{\\equiv}"; - case "~": return "{\\tripleDash}"; - case "~-": return "{\\tripleDashOverLine}"; - case "~=": return "{\\tripleDashOverDoubleLine}"; - case "~--": return "{\\tripleDashOverDoubleLine}"; - case "-~-": return "{\\tripleDashBetweenDoubleLine}"; - case "...": return "{{\\cdot}{\\cdot}{\\cdot}}"; - case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; - case "->": return "{\\rightarrow}"; - case "<-": return "{\\leftarrow}"; - case "<": return "{<}"; - case ">": return "{>}"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getOperator: function (a) { - switch (a) { - case "+": return " {}+{} "; - case "-": return " {}-{} "; - case "=": return " {}={} "; - case "<": return " {}<{} "; - case ">": return " {}>{} "; - case "<<": return " {}\\ll{} "; - case ">>": return " {}\\gg{} "; - case "\\pm": return " {}\\pm{} "; - case "\\approx": return " {}\\approx{} "; - case "$\\approx$": return " {}\\approx{} "; - case "v": return " \\downarrow{} "; - case "(v)": return " \\downarrow{} "; - case "^": return " \\uparrow{} "; - case "(^)": return " \\uparrow{} "; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - - // - // Helpers for code anaylsis - // Will show type error at calling position - // - /** @param {number} a */ - function assertNever(a) {} - /** @param {string} a */ - function assertString(a) {} - -/* eslint-disable no-undef */ - -////////////////////////////////////////////////////////////////////// -// texvc.sty - -// The texvc package contains macros available in mediawiki pages. -// We omit the functions deprecated at -// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax - -// We also omit texvc's \O, which conflicts with \text{\O} - -defineMacro("\\darr", "\\downarrow"); -defineMacro("\\dArr", "\\Downarrow"); -defineMacro("\\Darr", "\\Downarrow"); -defineMacro("\\lang", "\\langle"); -defineMacro("\\rang", "\\rangle"); -defineMacro("\\uarr", "\\uparrow"); -defineMacro("\\uArr", "\\Uparrow"); -defineMacro("\\Uarr", "\\Uparrow"); -defineMacro("\\N", "\\mathbb{N}"); -defineMacro("\\R", "\\mathbb{R}"); -defineMacro("\\Z", "\\mathbb{Z}"); -defineMacro("\\alef", "\\aleph"); -defineMacro("\\alefsym", "\\aleph"); -defineMacro("\\bull", "\\bullet"); -defineMacro("\\clubs", "\\clubsuit"); -defineMacro("\\cnums", "\\mathbb{C}"); -defineMacro("\\Complex", "\\mathbb{C}"); -defineMacro("\\Dagger", "\\ddagger"); -defineMacro("\\diamonds", "\\diamondsuit"); -defineMacro("\\empty", "\\emptyset"); -defineMacro("\\exist", "\\exists"); -defineMacro("\\harr", "\\leftrightarrow"); -defineMacro("\\hArr", "\\Leftrightarrow"); -defineMacro("\\Harr", "\\Leftrightarrow"); -defineMacro("\\hearts", "\\heartsuit"); -defineMacro("\\image", "\\Im"); -defineMacro("\\infin", "\\infty"); -defineMacro("\\isin", "\\in"); -defineMacro("\\larr", "\\leftarrow"); -defineMacro("\\lArr", "\\Leftarrow"); -defineMacro("\\Larr", "\\Leftarrow"); -defineMacro("\\lrarr", "\\leftrightarrow"); -defineMacro("\\lrArr", "\\Leftrightarrow"); -defineMacro("\\Lrarr", "\\Leftrightarrow"); -defineMacro("\\natnums", "\\mathbb{N}"); -defineMacro("\\plusmn", "\\pm"); -defineMacro("\\rarr", "\\rightarrow"); -defineMacro("\\rArr", "\\Rightarrow"); -defineMacro("\\Rarr", "\\Rightarrow"); -defineMacro("\\real", "\\Re"); -defineMacro("\\reals", "\\mathbb{R}"); -defineMacro("\\Reals", "\\mathbb{R}"); -defineMacro("\\sdot", "\\cdot"); -defineMacro("\\sect", "\\S"); -defineMacro("\\spades", "\\spadesuit"); -defineMacro("\\sub", "\\subset"); -defineMacro("\\sube", "\\subseteq"); -defineMacro("\\supe", "\\supseteq"); -defineMacro("\\thetasym", "\\vartheta"); -defineMacro("\\weierp", "\\wp"); - -/* eslint-disable no-undef */ - -/**************************************************** - * - * physics.js - * - * Implements the Physics Package for LaTeX input. - * - * --------------------------------------------------------------------- - * - * The original version of this file is licensed as follows: - * Copyright (c) 2015-2016 Kolen Cheung . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * --------------------------------------------------------------------- - * - * This file has been revised from the original in the following ways: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \Re and \Im are not used, to avoid conflict with existing LaTeX letters. - * - * This revision of the file is released under the MIT license. - * https://mit-license.org/ - */ -defineMacro("\\quantity", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\qty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\pqty", "{\\left( #1 \\right)}"); -defineMacro("\\bqty", "{\\left[ #1 \\right]}"); -defineMacro("\\vqty", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\Bqty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\absolutevalue", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\abs", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\norm", "{\\left\\Vert #1 \\right\\Vert}"); -defineMacro("\\evaluated", "{\\left.#1 \\right\\vert}"); -defineMacro("\\eval", "{\\left.#1 \\right\\vert}"); -defineMacro("\\order", "{\\mathcal{O} \\left( #1 \\right)}"); -defineMacro("\\commutator", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\comm", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\anticommutator", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\acomm", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\poissonbracket", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\pb", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\vectorbold", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vb", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vectorarrow", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\va", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\vectorunit", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\vu", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\dotproduct", "\\mathbin{\\boldsymbol\\cdot}"); -defineMacro("\\vdot", "{\\boldsymbol\\cdot}"); -defineMacro("\\crossproduct", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cross", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cp", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\gradient", "{\\boldsymbol\\nabla}"); -defineMacro("\\grad", "{\\boldsymbol\\nabla}"); -defineMacro("\\divergence", "{\\grad\\vdot}"); -//defineMacro("\\div", "{\\grad\\vdot}"); Not included in Temml. Conflicts w/LaTeX \div -defineMacro("\\curl", "{\\grad\\cross}"); -defineMacro("\\laplacian", "\\nabla^2"); -defineMacro("\\tr", "{\\operatorname{tr}}"); -defineMacro("\\Tr", "{\\operatorname{Tr}}"); -defineMacro("\\rank", "{\\operatorname{rank}}"); -defineMacro("\\erf", "{\\operatorname{erf}}"); -defineMacro("\\Res", "{\\operatorname{Res}}"); -defineMacro("\\principalvalue", "{\\mathcal{P}}"); -defineMacro("\\pv", "{\\mathcal{P}}"); -defineMacro("\\PV", "{\\operatorname{P.V.}}"); -// Temml does not use the next two lines. They conflict with LaTeX letters. -//defineMacro("\\Re", "{\\operatorname{Re} \\left\\{ #1 \\right\\}}"); -//defineMacro("\\Im", "{\\operatorname{Im} \\left\\{ #1 \\right\\}}"); -defineMacro("\\qqtext", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qq", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qcomma", "{\\text{,}\\quad}"); -defineMacro("\\qc", "{\\text{,}\\quad}"); -defineMacro("\\qcc", "{\\quad\\text{c.c.}\\quad}"); -defineMacro("\\qif", "{\\quad\\text{if}\\quad}"); -defineMacro("\\qthen", "{\\quad\\text{then}\\quad}"); -defineMacro("\\qelse", "{\\quad\\text{else}\\quad}"); -defineMacro("\\qotherwise", "{\\quad\\text{otherwise}\\quad}"); -defineMacro("\\qunless", "{\\quad\\text{unless}\\quad}"); -defineMacro("\\qgiven", "{\\quad\\text{given}\\quad}"); -defineMacro("\\qusing", "{\\quad\\text{using}\\quad}"); -defineMacro("\\qassume", "{\\quad\\text{assume}\\quad}"); -defineMacro("\\qsince", "{\\quad\\text{since}\\quad}"); -defineMacro("\\qlet", "{\\quad\\text{let}\\quad}"); -defineMacro("\\qfor", "{\\quad\\text{for}\\quad}"); -defineMacro("\\qall", "{\\quad\\text{all}\\quad}"); -defineMacro("\\qeven", "{\\quad\\text{even}\\quad}"); -defineMacro("\\qodd", "{\\quad\\text{odd}\\quad}"); -defineMacro("\\qinteger", "{\\quad\\text{integer}\\quad}"); -defineMacro("\\qand", "{\\quad\\text{and}\\quad}"); -defineMacro("\\qor", "{\\quad\\text{or}\\quad}"); -defineMacro("\\qas", "{\\quad\\text{as}\\quad}"); -defineMacro("\\qin", "{\\quad\\text{in}\\quad}"); -defineMacro("\\differential", "{\\text{d}}"); -defineMacro("\\dd", "{\\text{d}}"); -defineMacro("\\derivative", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\dv", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\partialderivative", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}"); -defineMacro("\\variation", "{\\delta}"); -defineMacro("\\var", "{\\delta}"); -defineMacro("\\functionalderivative", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\fdv", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\innerproduct", "{\\left\\langle {#1} \\mid { #2} \\right\\rangle}"); -defineMacro("\\outerproduct", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\dyad", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\ketbra", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\op", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\expectationvalue", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\expval", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\ev", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\matrixelement", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\matrixel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\mel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); - -/** - * This file contains the “gullet” where macros are expanded - * until only non-macro tokens remain. - */ - -// List of commands that act like macros but aren't defined as a macro, -// function, or symbol. Used in `isDefined`. -const implicitCommands = { - "^": true, // Parser.js - _: true, // Parser.js - "\\limits": true, // Parser.js - "\\nolimits": true // Parser.js -}; - -class MacroExpander { - constructor(input, settings, mode) { - this.settings = settings; - this.expansionCount = 0; - this.feed(input); - // Make new global namespace - this.macros = new Namespace(macros, settings.macros); - this.mode = mode; - this.stack = []; // contains tokens in REVERSE order - } - - /** - * Feed a new input string to the same MacroExpander - * (with existing macros etc.). - */ - feed(input) { - this.lexer = new Lexer(input, this.settings); - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - } - - /** - * Start a new group nesting within all namespaces. - */ - beginGroup() { - this.macros.beginGroup(); - } - - /** - * End current group nesting within all namespaces. - */ - endGroup() { - this.macros.endGroup(); - } - - /** - * Returns the topmost token on the stack, without expanding it. - * Similar in behavior to TeX's `\futurelet`. - */ - future() { - if (this.stack.length === 0) { - this.pushToken(this.lexer.lex()); - } - return this.stack[this.stack.length - 1] - } - - /** - * Remove and return the next unexpanded token. - */ - popToken() { - this.future(); // ensure non-empty stack - return this.stack.pop(); - } - - /** - * Add a given token to the token stack. In particular, this get be used - * to put back a token returned from one of the other methods. - */ - pushToken(token) { - this.stack.push(token); - } - - /** - * Append an array of tokens to the token stack. - */ - pushTokens(tokens) { - this.stack.push(...tokens); - } - - /** - * Find an macro argument without expanding tokens and append the array of - * tokens to the token stack. Uses Token as a container for the result. - */ - scanArgument(isOptional) { - let start; - let end; - let tokens; - if (isOptional) { - this.consumeSpaces(); // \@ifnextchar gobbles any space following it - if (this.future().text !== "[") { - return null; - } - start = this.popToken(); // don't include [ in tokens - ({ tokens, end } = this.consumeArg(["]"])); - } else { - ({ tokens, start, end } = this.consumeArg()); - } - - // indicate the end of an argument - this.pushToken(new Token("EOF", end.loc)); - - this.pushTokens(tokens); - return start.range(end, ""); - } - - /** - * Consume all following space tokens, without expansion. - */ - consumeSpaces() { - for (;;) { - const token = this.future(); - if (token.text === " ") { - this.stack.pop(); - } else { - break; - } - } - } - - /** - * Consume an argument from the token stream, and return the resulting array - * of tokens and start/end token. - */ - consumeArg(delims) { - // The argument for a delimited parameter is the shortest (possibly - // empty) sequence of tokens with properly nested {...} groups that is - // followed ... by this particular list of non-parameter tokens. - // The argument for an undelimited parameter is the next nonblank - // token, unless that token is ‘{’, when the argument will be the - // entire {...} group that follows. - const tokens = []; - const isDelimited = delims && delims.length > 0; - if (!isDelimited) { - // Ignore spaces between arguments. As the TeXbook says: - // "After you have said ‘\def\row#1#2{...}’, you are allowed to - // put spaces between the arguments (e.g., ‘\row x n’), because - // TeX doesn’t use single spaces as undelimited arguments." - this.consumeSpaces(); - } - const start = this.future(); - let tok; - let depth = 0; - let match = 0; - do { - tok = this.popToken(); - tokens.push(tok); - if (tok.text === "{") { - ++depth; - } else if (tok.text === "}") { - --depth; - if (depth === -1) { - throw new ParseError("Extra }", tok); - } - } else if (tok.text === "EOF") { - throw new ParseError( - "Unexpected end of input in a macro argument" + - ", expected '" + - (delims && isDelimited ? delims[match] : "}") + - "'", - tok - ); - } - if (delims && isDelimited) { - if ((depth === 0 || (depth === 1 && delims[match] === "{")) && tok.text === delims[match]) { - ++match; - if (match === delims.length) { - // don't include delims in tokens - tokens.splice(-match, match); - break; - } - } else { - match = 0; - } - } - } while (depth !== 0 || isDelimited); - // If the argument found ... has the form ‘{}’, - // ... the outermost braces enclosing the argument are removed - if (start.text === "{" && tokens[tokens.length - 1].text === "}") { - tokens.pop(); - tokens.shift(); - } - tokens.reverse(); // to fit in with stack order - return { tokens, start, end: tok }; - } - - /** - * Consume the specified number of (delimited) arguments from the token - * stream and return the resulting array of arguments. - */ - consumeArgs(numArgs, delimiters) { - if (delimiters) { - if (delimiters.length !== numArgs + 1) { - throw new ParseError("The length of delimiters doesn't match the number of args!"); - } - const delims = delimiters[0]; - for (let i = 0; i < delims.length; i++) { - const tok = this.popToken(); - if (delims[i] !== tok.text) { - throw new ParseError("Use of the macro doesn't match its definition", tok); - } - } - } - - const args = []; - for (let i = 0; i < numArgs; i++) { - args.push(this.consumeArg(delimiters && delimiters[i + 1]).tokens); - } - return args; - } - - /** - * Expand the next token only once if possible. - * - * If the token is expanded, the resulting tokens will be pushed onto - * the stack in reverse order and will be returned as an array, - * also in reverse order. - * - * If not, the next token will be returned without removing it - * from the stack. This case can be detected by a `Token` return value - * instead of an `Array` return value. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty. - * - * Used to implement `expandAfterFuture` and `expandNextToken`. - * - * If expandableOnly, only expandable tokens are expanded and - * an undefined control sequence results in an error. - */ - expandOnce(expandableOnly) { - const topToken = this.popToken(); - const name = topToken.text; - const expansion = !topToken.noexpand ? this._getExpansion(name) : null; - if (expansion == null || (expandableOnly && expansion.unexpandable)) { - if (expandableOnly && expansion == null && name[0] === "\\" && !this.isDefined(name)) { - throw new ParseError("Undefined control sequence: " + name); - } - this.pushToken(topToken); - return topToken; - } - this.expansionCount++; - if (this.expansionCount > this.settings.maxExpand) { - throw new ParseError( - "Too many expansions: infinite loop or " + "need to increase maxExpand setting" - ); - } - let tokens = expansion.tokens; - const args = this.consumeArgs(expansion.numArgs, expansion.delimiters); - if (expansion.numArgs) { - // paste arguments in place of the placeholders - tokens = tokens.slice(); // make a shallow copy - for (let i = tokens.length - 1; i >= 0; --i) { - let tok = tokens[i]; - if (tok.text === "#") { - if (i === 0) { - throw new ParseError("Incomplete placeholder at end of macro body", tok); - } - tok = tokens[--i]; // next token on stack - if (tok.text === "#") { - // ## → # - tokens.splice(i + 1, 1); // drop first # - } else if (/^[1-9]$/.test(tok.text)) { - // replace the placeholder with the indicated argument - tokens.splice(i, 2, ...args[+tok.text - 1]); - } else { - throw new ParseError("Not a valid argument number", tok); - } - } - } - } - // Concatenate expansion onto top of stack. - this.pushTokens(tokens); - return tokens; - } - - /** - * Expand the next token only once (if possible), and return the resulting - * top token on the stack (without removing anything from the stack). - * Similar in behavior to TeX's `\expandafter\futurelet`. - * Equivalent to expandOnce() followed by future(). - */ - expandAfterFuture() { - this.expandOnce(); - return this.future(); - } - - /** - * Recursively expand first token, then return first non-expandable token. - */ - expandNextToken() { - for (;;) { - const expanded = this.expandOnce(); - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (expanded.treatAsRelax) { - expanded.text = "\\relax"; - } - return this.stack.pop(); // === expanded - } - } - - // This pathway is impossible. - throw new Error(); // eslint-disable-line no-unreachable - } - - /** - * Fully expand the given macro name and return the resulting list of - * tokens, or return `undefined` if no such macro is defined. - */ - expandMacro(name) { - return this.macros.has(name) ? this.expandTokens([new Token(name)]) : undefined; - } - - /** - * Fully expand the given token stream and return the resulting list of - * tokens. Note that the input tokens are in reverse order, but the - * output tokens are in forward order. - */ - expandTokens(tokens) { - const output = []; - const oldStackLength = this.stack.length; - this.pushTokens(tokens); - while (this.stack.length > oldStackLength) { - const expanded = this.expandOnce(true); // expand only expandable tokens - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - if (expanded.treatAsRelax) { - // the expansion of \noexpand is the token itself - expanded.noexpand = false; - expanded.treatAsRelax = false; - } - output.push(this.stack.pop()); - } - } - return output; - } - - /** - * Fully expand the given macro name and return the result as a string, - * or return `undefined` if no such macro is defined. - */ - expandMacroAsText(name) { - const tokens = this.expandMacro(name); - if (tokens) { - return tokens.map((token) => token.text).join(""); - } else { - return tokens; - } - } - - /** - * Returns the expanded macro as a reversed array of tokens and a macro - * argument count. Or returns `null` if no such macro. - */ - _getExpansion(name) { - const definition = this.macros.get(name); - if (definition == null) { - // mainly checking for undefined here - return definition; - } - // If a single character has an associated catcode other than 13 - // (active character), then don't expand it. - if (name.length === 1) { - const catcode = this.lexer.catcodes[name]; - if (catcode != null && catcode !== 13) { - return - } - } - const expansion = typeof definition === "function" ? definition(this) : definition; - if (typeof expansion === "string") { - let numArgs = 0; - if (expansion.indexOf("#") !== -1) { - const stripped = expansion.replace(/##/g, ""); - while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { - ++numArgs; - } - } - const bodyLexer = new Lexer(expansion, this.settings); - const tokens = []; - let tok = bodyLexer.lex(); - while (tok.text !== "EOF") { - tokens.push(tok); - tok = bodyLexer.lex(); - } - tokens.reverse(); // to fit in with stack using push and pop - const expanded = { tokens, numArgs }; - return expanded; - } - - return expansion; - } - - /** - * Determine whether a command is currently "defined" (has some - * functionality), meaning that it's a macro (in the current group), - * a function, a symbol, or one of the special commands listed in - * `implicitCommands`. - */ - isDefined(name) { - return ( - this.macros.has(name) || - Object.prototype.hasOwnProperty.call(functions, name ) || - Object.prototype.hasOwnProperty.call(symbols.math, name ) || - Object.prototype.hasOwnProperty.call(symbols.text, name ) || - Object.prototype.hasOwnProperty.call(implicitCommands, name ) - ); - } - - /** - * Determine whether a command is expandable. - */ - isExpandable(name) { - const macro = this.macros.get(name); - return macro != null - ? typeof macro === "string" || typeof macro === "function" || !macro.unexpandable - : Object.prototype.hasOwnProperty.call(functions, name ) && !functions[name].primitive; - } -} - -/* - * This file defines the Unicode scripts and script families that we - * support. To add new scripts or families, just add a new entry to the - * scriptData array below. Adding scripts to the scriptData array allows - * characters from that script to appear in \text{} environments. - */ - -/** - * Each script or script family has a name and an array of blocks. - * Each block is an array of two numbers which specify the start and - * end points (inclusive) of a block of Unicode codepoints. - -/** - * Unicode block data for the families of scripts we support in \text{}. - * Scripts only need to appear here if they do not have font metrics. - */ -const scriptData = [ - { - // Latin characters beyond the Latin-1 characters we have metrics for. - // Needed for Czech, Hungarian and Turkish text, for example. - name: "latin", - blocks: [ - [0x0100, 0x024f], // Latin Extended-A and Latin Extended-B - [0x0300, 0x036f] // Combining Diacritical marks - ] - }, - { - // The Cyrillic script used by Russian and related languages. - // A Cyrillic subset used to be supported as explicitly defined - // symbols in symbols.js - name: "cyrillic", - blocks: [[0x0400, 0x04ff]] - }, - { - // Armenian - name: "armenian", - blocks: [[0x0530, 0x058f]] - }, - { - // The Brahmic scripts of South and Southeast Asia - // Devanagari (0900–097F) - // Bengali (0980–09FF) - // Gurmukhi (0A00–0A7F) - // Gujarati (0A80–0AFF) - // Oriya (0B00–0B7F) - // Tamil (0B80–0BFF) - // Telugu (0C00–0C7F) - // Kannada (0C80–0CFF) - // Malayalam (0D00–0D7F) - // Sinhala (0D80–0DFF) - // Thai (0E00–0E7F) - // Lao (0E80–0EFF) - // Tibetan (0F00–0FFF) - // Myanmar (1000–109F) - name: "brahmic", - blocks: [[0x0900, 0x109f]] - }, - { - name: "georgian", - blocks: [[0x10a0, 0x10ff]] - }, - { - // Chinese and Japanese. - // The "k" in cjk is for Korean, but we've separated Korean out - name: "cjk", - blocks: [ - [0x3000, 0x30ff], // CJK symbols and punctuation, Hiragana, Katakana - [0x4e00, 0x9faf], // CJK ideograms - [0xff00, 0xff60] // Fullwidth punctuation - // TODO: add halfwidth Katakana and Romanji glyphs - ] - }, - { - // Korean - name: "hangul", - blocks: [[0xac00, 0xd7af]] - } -]; - -/** - * A flattened version of all the supported blocks in a single array. - * This is an optimization to make supportedCodepoint() fast. - */ -const allBlocks = []; -scriptData.forEach((s) => s.blocks.forEach((b) => allBlocks.push(...b))); - -/** - * Given a codepoint, return true if it falls within one of the - * scripts or script families defined above and false otherwise. - * - * Micro benchmarks shows that this is faster than - * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() - * in Firefox, Chrome and Node. - */ -function supportedCodepoint(codepoint) { - for (let i = 0; i < allBlocks.length; i += 2) { - if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { - return true; - } - } - return false; -} - -// Helpers for Parser.js handling of Unicode (sub|super)script characters. - -const unicodeSubRegEx = /^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/; - -const uSubsAndSups = Object.freeze({ - '₊': '+', - '₋': '-', - '₌': '=', - '₍': '(', - '₎': ')', - '₀': '0', - '₁': '1', - '₂': '2', - '₃': '3', - '₄': '4', - '₅': '5', - '₆': '6', - '₇': '7', - '₈': '8', - '₉': '9', - '\u2090': 'a', - '\u2091': 'e', - '\u2095': 'h', - '\u1D62': 'i', - '\u2C7C': 'j', - '\u2096': 'k', - '\u2097': 'l', - '\u2098': 'm', - '\u2099': 'n', - '\u2092': 'o', - '\u209A': 'p', - '\u1D63': 'r', - '\u209B': 's', - '\u209C': 't', - '\u1D64': 'u', - '\u1D65': 'v', - '\u2093': 'x', - '\u1D66': 'β', - '\u1D67': 'γ', - '\u1D68': 'ρ', - '\u1D69': '\u03d5', - '\u1D6A': 'χ', - '⁺': '+', - '⁻': '-', - '⁼': '=', - '⁽': '(', - '⁾': ')', - '⁰': '0', - '¹': '1', - '²': '2', - '³': '3', - '⁴': '4', - '⁵': '5', - '⁶': '6', - '⁷': '7', - '⁸': '8', - '⁹': '9', - '\u1D2C': 'A', - '\u1D2E': 'B', - '\u1D30': 'D', - '\u1D31': 'E', - '\u1D33': 'G', - '\u1D34': 'H', - '\u1D35': 'I', - '\u1D36': 'J', - '\u1D37': 'K', - '\u1D38': 'L', - '\u1D39': 'M', - '\u1D3A': 'N', - '\u1D3C': 'O', - '\u1D3E': 'P', - '\u1D3F': 'R', - '\u1D40': 'T', - '\u1D41': 'U', - '\u2C7D': 'V', - '\u1D42': 'W', - '\u1D43': 'a', - '\u1D47': 'b', - '\u1D9C': 'c', - '\u1D48': 'd', - '\u1D49': 'e', - '\u1DA0': 'f', - '\u1D4D': 'g', - '\u02B0': 'h', - '\u2071': 'i', - '\u02B2': 'j', - '\u1D4F': 'k', - '\u02E1': 'l', - '\u1D50': 'm', - '\u207F': 'n', - '\u1D52': 'o', - '\u1D56': 'p', - '\u02B3': 'r', - '\u02E2': 's', - '\u1D57': 't', - '\u1D58': 'u', - '\u1D5B': 'v', - '\u02B7': 'w', - '\u02E3': 'x', - '\u02B8': 'y', - '\u1DBB': 'z', - '\u1D5D': 'β', - '\u1D5E': 'γ', - '\u1D5F': 'δ', - '\u1D60': '\u03d5', - '\u1D61': 'χ', - '\u1DBF': 'θ' -}); - -// Mapping of Unicode accent characters to their LaTeX equivalent in text and -// math mode (when they exist). -var unicodeAccents = { - "\u0301": { text: "\\'", math: "\\acute" }, - "\u0300": { text: "\\`", math: "\\grave" }, - "\u0308": { text: '\\"', math: "\\ddot" }, - "\u0303": { text: "\\~", math: "\\tilde" }, - "\u0304": { text: "\\=", math: "\\bar" }, - "\u0306": { text: "\\u", math: "\\breve" }, - "\u030c": { text: "\\v", math: "\\check" }, - "\u0302": { text: "\\^", math: "\\hat" }, - "\u0307": { text: "\\.", math: "\\dot" }, - "\u030a": { text: "\\r", math: "\\mathring" }, - "\u030b": { text: "\\H" }, - '\u0327': { text: '\\c' } -}; - -var unicodeSymbols = { - "á": "á", - "à": "à", - "ä": "ä", - "ǟ": "ǟ", - "ã": "ã", - "ā": "ā", - "ă": "ă", - "ắ": "ắ", - "ằ": "ằ", - "ẵ": "ẵ", - "ǎ": "ǎ", - "â": "â", - "ấ": "ấ", - "ầ": "ầ", - "ẫ": "ẫ", - "ȧ": "ȧ", - "ǡ": "ǡ", - "å": "å", - "ǻ": "ǻ", - "ḃ": "ḃ", - "ć": "ć", - "č": "č", - "ĉ": "ĉ", - "ċ": "ċ", - "ď": "ď", - "ḋ": "ḋ", - "é": "é", - "è": "è", - "ë": "ë", - "ẽ": "ẽ", - "ē": "ē", - "ḗ": "ḗ", - "ḕ": "ḕ", - "ĕ": "ĕ", - "ě": "ě", - "ê": "ê", - "ế": "ế", - "ề": "ề", - "ễ": "ễ", - "ė": "ė", - "ḟ": "ḟ", - "ǵ": "ǵ", - "ḡ": "ḡ", - "ğ": "ğ", - "ǧ": "ǧ", - "ĝ": "ĝ", - "ġ": "ġ", - "ḧ": "ḧ", - "ȟ": "ȟ", - "ĥ": "ĥ", - "ḣ": "ḣ", - "í": "í", - "ì": "ì", - "ï": "ï", - "ḯ": "ḯ", - "ĩ": "ĩ", - "ī": "ī", - "ĭ": "ĭ", - "ǐ": "ǐ", - "î": "î", - "ǰ": "ǰ", - "ĵ": "ĵ", - "ḱ": "ḱ", - "ǩ": "ǩ", - "ĺ": "ĺ", - "ľ": "ľ", - "ḿ": "ḿ", - "ṁ": "ṁ", - "ń": "ń", - "ǹ": "ǹ", - "ñ": "ñ", - "ň": "ň", - "ṅ": "ṅ", - "ó": "ó", - "ò": "ò", - "ö": "ö", - "ȫ": "ȫ", - "õ": "õ", - "ṍ": "ṍ", - "ṏ": "ṏ", - "ȭ": "ȭ", - "ō": "ō", - "ṓ": "ṓ", - "ṑ": "ṑ", - "ŏ": "ŏ", - "ǒ": "ǒ", - "ô": "ô", - "ố": "ố", - "ồ": "ồ", - "ỗ": "ỗ", - "ȯ": "ȯ", - "ȱ": "ȱ", - "ő": "ő", - "ṕ": "ṕ", - "ṗ": "ṗ", - "ŕ": "ŕ", - "ř": "ř", - "ṙ": "ṙ", - "ś": "ś", - "ṥ": "ṥ", - "š": "š", - "ṧ": "ṧ", - "ŝ": "ŝ", - "ṡ": "ṡ", - "ẗ": "ẗ", - "ť": "ť", - "ṫ": "ṫ", - "ú": "ú", - "ù": "ù", - "ü": "ü", - "ǘ": "ǘ", - "ǜ": "ǜ", - "ǖ": "ǖ", - "ǚ": "ǚ", - "ũ": "ũ", - "ṹ": "ṹ", - "ū": "ū", - "ṻ": "ṻ", - "ŭ": "ŭ", - "ǔ": "ǔ", - "û": "û", - "ů": "ů", - "ű": "ű", - "ṽ": "ṽ", - "ẃ": "ẃ", - "ẁ": "ẁ", - "ẅ": "ẅ", - "ŵ": "ŵ", - "ẇ": "ẇ", - "ẘ": "ẘ", - "ẍ": "ẍ", - "ẋ": "ẋ", - "ý": "ý", - "ỳ": "ỳ", - "ÿ": "ÿ", - "ỹ": "ỹ", - "ȳ": "ȳ", - "ŷ": "ŷ", - "ẏ": "ẏ", - "ẙ": "ẙ", - "ź": "ź", - "ž": "ž", - "ẑ": "ẑ", - "ż": "ż", - "Á": "Á", - "À": "À", - "Ä": "Ä", - "Ǟ": "Ǟ", - "Ã": "Ã", - "Ā": "Ā", - "Ă": "Ă", - "Ắ": "Ắ", - "Ằ": "Ằ", - "Ẵ": "Ẵ", - "Ǎ": "Ǎ", - "Â": "Â", - "Ấ": "Ấ", - "Ầ": "Ầ", - "Ẫ": "Ẫ", - "Ȧ": "Ȧ", - "Ǡ": "Ǡ", - "Å": "Å", - "Ǻ": "Ǻ", - "Ḃ": "Ḃ", - "Ć": "Ć", - "Č": "Č", - "Ĉ": "Ĉ", - "Ċ": "Ċ", - "Ď": "Ď", - "Ḋ": "Ḋ", - "É": "É", - "È": "È", - "Ë": "Ë", - "Ẽ": "Ẽ", - "Ē": "Ē", - "Ḗ": "Ḗ", - "Ḕ": "Ḕ", - "Ĕ": "Ĕ", - "Ě": "Ě", - "Ê": "Ê", - "Ế": "Ế", - "Ề": "Ề", - "Ễ": "Ễ", - "Ė": "Ė", - "Ḟ": "Ḟ", - "Ǵ": "Ǵ", - "Ḡ": "Ḡ", - "Ğ": "Ğ", - "Ǧ": "Ǧ", - "Ĝ": "Ĝ", - "Ġ": "Ġ", - "Ḧ": "Ḧ", - "Ȟ": "Ȟ", - "Ĥ": "Ĥ", - "Ḣ": "Ḣ", - "Í": "Í", - "Ì": "Ì", - "Ï": "Ï", - "Ḯ": "Ḯ", - "Ĩ": "Ĩ", - "Ī": "Ī", - "Ĭ": "Ĭ", - "Ǐ": "Ǐ", - "Î": "Î", - "İ": "İ", - "Ĵ": "Ĵ", - "Ḱ": "Ḱ", - "Ǩ": "Ǩ", - "Ĺ": "Ĺ", - "Ľ": "Ľ", - "Ḿ": "Ḿ", - "Ṁ": "Ṁ", - "Ń": "Ń", - "Ǹ": "Ǹ", - "Ñ": "Ñ", - "Ň": "Ň", - "Ṅ": "Ṅ", - "Ó": "Ó", - "Ò": "Ò", - "Ö": "Ö", - "Ȫ": "Ȫ", - "Õ": "Õ", - "Ṍ": "Ṍ", - "Ṏ": "Ṏ", - "Ȭ": "Ȭ", - "Ō": "Ō", - "Ṓ": "Ṓ", - "Ṑ": "Ṑ", - "Ŏ": "Ŏ", - "Ǒ": "Ǒ", - "Ô": "Ô", - "Ố": "Ố", - "Ồ": "Ồ", - "Ỗ": "Ỗ", - "Ȯ": "Ȯ", - "Ȱ": "Ȱ", - "Ő": "Ő", - "Ṕ": "Ṕ", - "Ṗ": "Ṗ", - "Ŕ": "Ŕ", - "Ř": "Ř", - "Ṙ": "Ṙ", - "Ś": "Ś", - "Ṥ": "Ṥ", - "Š": "Š", - "Ṧ": "Ṧ", - "Ŝ": "Ŝ", - "Ṡ": "Ṡ", - "Ť": "Ť", - "Ṫ": "Ṫ", - "Ú": "Ú", - "Ù": "Ù", - "Ü": "Ü", - "Ǘ": "Ǘ", - "Ǜ": "Ǜ", - "Ǖ": "Ǖ", - "Ǚ": "Ǚ", - "Ũ": "Ũ", - "Ṹ": "Ṹ", - "Ū": "Ū", - "Ṻ": "Ṻ", - "Ŭ": "Ŭ", - "Ǔ": "Ǔ", - "Û": "Û", - "Ů": "Ů", - "Ű": "Ű", - "Ṽ": "Ṽ", - "Ẃ": "Ẃ", - "Ẁ": "Ẁ", - "Ẅ": "Ẅ", - "Ŵ": "Ŵ", - "Ẇ": "Ẇ", - "Ẍ": "Ẍ", - "Ẋ": "Ẋ", - "Ý": "Ý", - "Ỳ": "Ỳ", - "Ÿ": "Ÿ", - "Ỹ": "Ỹ", - "Ȳ": "Ȳ", - "Ŷ": "Ŷ", - "Ẏ": "Ẏ", - "Ź": "Ź", - "Ž": "Ž", - "Ẑ": "Ẑ", - "Ż": "Ż", - "ά": "ά", - "ὰ": "ὰ", - "ᾱ": "ᾱ", - "ᾰ": "ᾰ", - "έ": "έ", - "ὲ": "ὲ", - "ή": "ή", - "ὴ": "ὴ", - "ί": "ί", - "ὶ": "ὶ", - "ϊ": "ϊ", - "ΐ": "ΐ", - "ῒ": "ῒ", - "ῑ": "ῑ", - "ῐ": "ῐ", - "ό": "ό", - "ὸ": "ὸ", - "ύ": "ύ", - "ὺ": "ὺ", - "ϋ": "ϋ", - "ΰ": "ΰ", - "ῢ": "ῢ", - "ῡ": "ῡ", - "ῠ": "ῠ", - "ώ": "ώ", - "ὼ": "ὼ", - "Ύ": "Ύ", - "Ὺ": "Ὺ", - "Ϋ": "Ϋ", - "Ῡ": "Ῡ", - "Ῠ": "Ῠ", - "Ώ": "Ώ", - "Ὼ": "Ὼ" -}; - -/* eslint no-constant-condition:0 */ - -const numberRegEx = /^\d(?:[\d,.]*\d)?$/; // Keep in sync with numberRegEx in symbolsOrd.js - -/** - * This file contains the parser used to parse out a TeX expression from the - * input. Since TeX isn't context-free, standard parsers don't work particularly - * well. - * - * The strategy of this parser is as such: - * - * The main functions (the `.parse...` ones) take a position in the current - * parse string to parse tokens from. The lexer (found in Lexer.js, stored at - * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When - * individual tokens are needed at a position, the lexer is called to pull out a - * token, which is then used. - * - * The parser has a property called "mode" indicating the mode that - * the parser is currently in. Currently it has to be one of "math" or - * "text", which denotes whether the current environment is a math-y - * one or a text-y one (e.g. inside \text). Currently, this serves to - * limit the functions which can be used in text mode. - * - * The main functions then return an object which contains the useful data that - * was parsed at its given point, and a new position at the end of the parsed - * data. The main functions can call each other and continue the parsing by - * using the returned position as a new starting point. - * - * There are also extra `.handle...` functions, which pull out some reused - * functionality into self-contained functions. - * - * The functions return ParseNodes. - */ - -class Parser { - constructor(input, settings, isPreamble = false) { - // Start in math mode - this.mode = "math"; - // Create a new macro expander (gullet) and (indirectly via that) also a - // new lexer (mouth) for this parser (stomach, in the language of TeX) - this.gullet = new MacroExpander(input, settings, this.mode); - // Store the settings for use in parsing - this.settings = settings; - // Are we defining a preamble? - this.isPreamble = isPreamble; - // Count leftright depth (for \middle errors) - this.leftrightDepth = 0; - this.prevAtomType = ""; - } - - /** - * Checks a result to make sure it has the right type, and throws an - * appropriate error otherwise. - */ - expect(text, consume = true) { - if (this.fetch().text !== text) { - throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); - } - if (consume) { - this.consume(); - } - } - - /** - * Discards the current lookahead token, considering it consumed. - */ - consume() { - this.nextToken = null; - } - - /** - * Return the current lookahead token, or if there isn't one (at the - * beginning, or if the previous lookahead token was consume()d), - * fetch the next token as the new lookahead token and return it. - */ - fetch() { - if (this.nextToken == null) { - this.nextToken = this.gullet.expandNextToken(); - } - return this.nextToken; - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - this.gullet.switchMode(newMode); - } - - /** - * Main parsing function, which parses an entire input. - */ - parse() { - // Create a group namespace for every $...$, $$...$$, \[...\].) - // A \def is then valid only within that pair of delimiters. - this.gullet.beginGroup(); - - if (this.settings.colorIsTextColor) { - // Use old \color behavior (same as LaTeX's \textcolor) if requested. - // We do this within the group for the math expression, so it doesn't - // pollute settings.macros. - this.gullet.macros.set("\\color", "\\textcolor"); - } - - // Try to parse the input - const parse = this.parseExpression(false); - - // If we succeeded, make sure there's an EOF at the end - this.expect("EOF"); - - if (this.isPreamble) { - const macros = Object.create(null); - Object.entries(this.gullet.macros.current).forEach(([key, value]) => { - macros[key] = value; - }); - this.gullet.endGroup(); - return macros - } - - // The only local macro that we want to save is from \tag. - const tag = this.gullet.macros.get("\\df@tag"); - - // End the group namespace for the expression - this.gullet.endGroup(); - - if (tag) { this.gullet.macros.current["\\df@tag"] = tag; } - - return parse; - } - - static get endOfExpression() { - return ["}", "\\endgroup", "\\end", "\\right", "\\endtoggle", "&"]; - } - - /** - * Parses an "expression", which is a list of atoms. - * - * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This - * happens when functions have higher precendence han infix - * nodes in implicit parses. - * - * `breakOnTokenText`: The text of the token that the expression should end - * with, or `null` if something else should end the - * expression. - */ - parseExpression(breakOnInfix, breakOnTokenText) { - const body = []; - // Keep adding atoms to the body until we can't parse any more atoms (either - // we reached the end, a }, or a \right) - while (true) { - // Ignore spaces in math mode - if (this.mode === "math") { - this.consumeSpaces(); - } - const lex = this.fetch(); - if (Parser.endOfExpression.indexOf(lex.text) !== -1) { - break; - } - if (breakOnTokenText && lex.text === breakOnTokenText) { - break; - } - if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { - break; - } - const atom = this.parseAtom(breakOnTokenText); - if (!atom) { - break; - } else if (atom.type === "internal") { - continue; - } - body.push(atom); - // Keep a record of the atom type, so that op.js can set correct spacing. - this.prevAtomType = atom.type === "atom" ? atom.family : atom.type; - } - if (this.mode === "text") { - this.formLigatures(body); - } - return this.handleInfixNodes(body); - } - - /** - * Rewrites infix operators such as \over with corresponding commands such - * as \frac. - * - * There can only be one infix operator per group. If there's more than one - * then the expression is ambiguous. This can be resolved by adding {}. - */ - handleInfixNodes(body) { - let overIndex = -1; - let funcName; - - for (let i = 0; i < body.length; i++) { - if (body[i].type === "infix") { - if (overIndex !== -1) { - throw new ParseError("only one infix operator per group", body[i].token); - } - overIndex = i; - funcName = body[i].replaceWith; - } - } - - if (overIndex !== -1 && funcName) { - let numerNode; - let denomNode; - - const numerBody = body.slice(0, overIndex); - const denomBody = body.slice(overIndex + 1); - - if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { - numerNode = numerBody[0]; - } else { - numerNode = { type: "ordgroup", mode: this.mode, body: numerBody }; - } - - if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { - denomNode = denomBody[0]; - } else { - denomNode = { type: "ordgroup", mode: this.mode, body: denomBody }; - } - - let node; - if (funcName === "\\\\abovefrac") { - node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); - } else { - node = this.callFunction(funcName, [numerNode, denomNode], []); - } - return [node]; - } else { - return body; - } - } - - /** - * Handle a subscript or superscript with nice errors. - */ - handleSupSubscript( - name // For error reporting. - ) { - const symbolToken = this.fetch(); - const symbol = symbolToken.text; - this.consume(); - this.consumeSpaces(); // ignore spaces before sup/subscript argument - const group = this.parseGroup(name); - - if (!group) { - throw new ParseError("Expected group after '" + symbol + "'", symbolToken); - } - - return group; - } - - /** - * Converts the textual input of an unsupported command into a text node - * contained within a color node whose color is determined by errorColor - */ - formatUnsupportedCmd(text) { - const textordArray = []; - - for (let i = 0; i < text.length; i++) { - textordArray.push({ type: "textord", mode: "text", text: text[i] }); - } - - const textNode = { - type: "text", - mode: this.mode, - body: textordArray - }; - - const colorNode = { - type: "color", - mode: this.mode, - color: this.settings.errorColor, - body: [textNode] - }; - - return colorNode; - } - - /** - * Parses a group with optional super/subscripts. - */ - parseAtom(breakOnTokenText) { - // The body of an atom is an implicit group, so that things like - // \left(x\right)^2 work correctly. - const base = this.parseGroup("atom", breakOnTokenText); - - // In text mode, we don't have superscripts or subscripts - if (this.mode === "text") { - return base; - } - - // Note that base may be empty (i.e. null) at this point. - - let superscript; - let subscript; - while (true) { - // Guaranteed in math mode, so eat any spaces first. - this.consumeSpaces(); - - // Lex the first token - const lex = this.fetch(); - - if (lex.text === "\\limits" || lex.text === "\\nolimits") { - // We got a limit control - if (base && base.type === "op") { - const limits = lex.text === "\\limits"; - base.limits = limits; - base.alwaysHandleSupSub = true; - } else if (base && base.type === "operatorname") { - if (base.alwaysHandleSupSub) { - base.limits = lex.text === "\\limits"; - } - } else { - throw new ParseError("Limit controls must follow a math operator", lex); - } - this.consume(); - } else if (lex.text === "^") { - // We got a superscript start - if (superscript) { - throw new ParseError("Double superscript", lex); - } - superscript = this.handleSupSubscript("superscript"); - } else if (lex.text === "_") { - // We got a subscript start - if (subscript) { - throw new ParseError("Double subscript", lex); - } - subscript = this.handleSupSubscript("subscript"); - } else if (lex.text === "'") { - // We got a prime - if (superscript) { - throw new ParseError("Double superscript", lex); - } - const prime = { type: "textord", mode: this.mode, text: "\\prime" }; - - // Many primes can be grouped together, so we handle this here - const primes = [prime]; - this.consume(); - // Keep lexing tokens until we get something that's not a prime - while (this.fetch().text === "'") { - // For each one, add another prime to the list - primes.push(prime); - this.consume(); - } - // If there's a superscript following the primes, combine that - // superscript in with the primes. - if (this.fetch().text === "^") { - primes.push(this.handleSupSubscript("superscript")); - } - // Put everything into an ordgroup as the superscript - superscript = { type: "ordgroup", mode: this.mode, body: primes }; - } else if (uSubsAndSups[lex.text]) { - // A Unicode subscript or superscript character. - // We treat these similarly to the unicode-math package. - // So we render a string of Unicode (sub|super)scripts the - // same as a (sub|super)script of regular characters. - let str = uSubsAndSups[lex.text]; - const isSub = unicodeSubRegEx.test(lex.text); - this.consume(); - // Continue fetching tokens to fill out the string. - while (true) { - const token = this.fetch().text; - if (!(uSubsAndSups[token])) { break } - if (unicodeSubRegEx.test(token) !== isSub) { break } - this.consume(); - str += uSubsAndSups[token]; - } - // Now create a (sub|super)script. - const body = (new Parser(str, this.settings)).parse(); - if (isSub) { - subscript = { type: "ordgroup", mode: "math", body }; - } else { - superscript = { type: "ordgroup", mode: "math", body }; - } - } else { - // If it wasn't ^, _, a Unicode (sub|super)script, or ', stop parsing super/subscripts - break; - } - } - - if (superscript || subscript) { - if (base && base.type === "multiscript" && !base.postscripts) { - // base is the result of a \prescript function. - // Write the sub- & superscripts into the multiscript element. - base.postscripts = { sup: superscript, sub: subscript }; - return base - } else { - // We got either a superscript or subscript, create a supsub - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript - } - } - } else { - // Otherwise return the original body - return base; - } - } - - /** - * Parses an entire function, including its base and all of its arguments. - */ - parseFunction( - breakOnTokenText, - name // For determining its context - ) { - const token = this.fetch(); - const func = token.text; - const funcData = functions[func]; - if (!funcData) { - return null; - } - this.consume(); // consume command token - - if (name && name !== "atom" && !funcData.allowedInArgument) { - throw new ParseError( - "Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), - token - ); - } else if (this.mode === "text" && !funcData.allowedInText) { - throw new ParseError("Can't use function '" + func + "' in text mode", token); - } else if (this.mode === "math" && funcData.allowedInMath === false) { - throw new ParseError("Can't use function '" + func + "' in math mode", token); - } - - const prevAtomType = this.prevAtomType; - const { args, optArgs } = this.parseArguments(func, funcData); - this.prevAtomType = prevAtomType; - return this.callFunction(func, args, optArgs, token, breakOnTokenText); - } - - /** - * Call a function handler with a suitable context and arguments. - */ - callFunction(name, args, optArgs, token, breakOnTokenText) { - const context = { - funcName: name, - parser: this, - token, - breakOnTokenText - }; - const func = functions[name]; - if (func && func.handler) { - return func.handler(context, args, optArgs); - } else { - throw new ParseError(`No function handler for ${name}`); - } - } - - /** - * Parses the arguments of a function or environment - */ - parseArguments( - func, // Should look like "\name" or "\begin{name}". - funcData - ) { - const totalArgs = funcData.numArgs + funcData.numOptionalArgs; - if (totalArgs === 0) { - return { args: [], optArgs: [] }; - } - - const args = []; - const optArgs = []; - - for (let i = 0; i < totalArgs; i++) { - let argType = funcData.argTypes && funcData.argTypes[i]; - const isOptional = i < funcData.numOptionalArgs; - - if ( - (funcData.primitive && argType == null) || - // \sqrt expands into primitive if optional argument doesn't exist - (funcData.type === "sqrt" && i === 1 && optArgs[0] == null) - ) { - argType = "primitive"; - } - - const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional); - if (isOptional) { - optArgs.push(arg); - } else if (arg != null) { - args.push(arg); - } else { - // should be unreachable - throw new ParseError("Null argument, please report this as a bug"); - } - } - - return { args, optArgs }; - } - - /** - * Parses a group when the mode is changing. - */ - parseGroupOfType(name, type, optional) { - switch (type) { - case "size": - return this.parseSizeGroup(optional); - case "url": - return this.parseUrlGroup(optional); - case "math": - case "text": - return this.parseArgumentGroup(optional, type); - case "hbox": { - // hbox argument type wraps the argument in the equivalent of - // \hbox, which is like \text but switching to \textstyle size. - const group = this.parseArgumentGroup(optional, "text"); - return group != null - ? { - type: "styling", - mode: group.mode, - body: [group], - scriptLevel: "text" // simulate \textstyle - } - : null; - } - case "raw": { - const token = this.parseStringGroup("raw", optional); - return token != null - ? { - type: "raw", - mode: "text", - string: token.text - } - : null; - } - case "primitive": { - if (optional) { - throw new ParseError("A primitive argument cannot be optional"); - } - const group = this.parseGroup(name); - if (group == null) { - throw new ParseError("Expected group as " + name, this.fetch()); - } - return group; - } - case "original": - case null: - case undefined: - return this.parseArgumentGroup(optional); - default: - throw new ParseError("Unknown group type as " + name, this.fetch()); - } - } - - /** - * Discard any space tokens, fetching the next non-space token. - */ - consumeSpaces() { - while (this.fetch().text === " ") { - this.consume(); - } - } - - /** - * Parses a group, essentially returning the string formed by the - * brace-enclosed tokens plus some position information. - */ - parseStringGroup( - modeName, // Used to describe the mode in error messages. - optional - ) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF") { - str += nextToken.text; - this.consume(); - } - this.consume(); // consume the end of the argument - argToken.text = str; - return argToken; - } - - /** - * Parses a regex-delimited group: the largest sequence of tokens - * whose concatenated strings match `regex`. Returns the string - * formed by the tokens plus some position information. - */ - parseRegexGroup( - regex, - modeName // Used to describe the mode in error messages. - ) { - const firstToken = this.fetch(); - let lastToken = firstToken; - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { - lastToken = nextToken; - str += lastToken.text; - this.consume(); - } - if (str === "") { - throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); - } - return firstToken.range(lastToken, str); - } - - /** - * Parses a size specification, consisting of magnitude and unit. - */ - parseSizeGroup(optional) { - let res; - let isBlank = false; - // don't expand before parseStringGroup - this.gullet.consumeSpaces(); - if (!optional && this.gullet.future().text !== "{") { - res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); - } else { - res = this.parseStringGroup("size", optional); - } - if (!res) { - return null; - } - if (!optional && res.text.length === 0) { - // Because we've tested for what is !optional, this block won't - // affect \kern, \hspace, etc. It will capture the mandatory arguments - // to \genfrac and \above. - res.text = "0pt"; // Enable \above{} - isBlank = true; // This is here specifically for \genfrac - } - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); - if (!match) { - throw new ParseError("Invalid size: '" + res.text + "'", res); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "'", res); - } - return { - type: "size", - mode: this.mode, - value: data, - isBlank - }; - } - - /** - * Parses an URL, checking escaped letters and allowed protocols, - * and setting the catcode of % as an active character (as in \hyperref). - */ - parseUrlGroup(optional) { - this.gullet.lexer.setCatcode("%", 13); // active character - this.gullet.lexer.setCatcode("~", 12); // other character - const res = this.parseStringGroup("url", optional); - this.gullet.lexer.setCatcode("%", 14); // comment character - this.gullet.lexer.setCatcode("~", 13); // active character - if (res == null) { - return null; - } - // hyperref package allows backslashes alone in href, but doesn't - // generate valid links in such cases; we interpret this as - // "undefined" behaviour, and keep them as-is. Some browser will - // replace backslashes with forward slashes. - let url = res.text.replace(/\\([#$%&~_^{}])/g, "$1"); - url = res.text.replace(/{\u2044}/g, "/"); - return { - type: "url", - mode: this.mode, - url - }; - } - - /** - * Parses an argument with the mode specified. - */ - parseArgumentGroup(optional, mode) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - const outerMode = this.mode; - if (mode) { - // Switch to specified mode - this.switchMode(mode); - } - - this.gullet.beginGroup(); - const expression = this.parseExpression(false, "EOF"); - // TODO: find an alternative way to denote the end - this.expect("EOF"); // expect the end of the argument - this.gullet.endGroup(); - const result = { - type: "ordgroup", - mode: this.mode, - loc: argToken.loc, - body: expression - }; - - if (mode) { - // Switch mode back - this.switchMode(outerMode); - } - return result; - } - - /** - * Parses an ordinary group, which is either a single nucleus (like "x") - * or an expression in braces (like "{x+y}") or an implicit group, a group - * that starts at the current position, and ends right before a higher explicit - * group ends, or at EOF. - */ - parseGroup( - name, // For error reporting. - breakOnTokenText - ) { - const firstToken = this.fetch(); - const text = firstToken.text; - - let result; - // Try to parse an open brace or \begingroup - if (text === "{" || text === "\\begingroup" || text === "\\toggle") { - this.consume(); - const groupEnd = text === "{" - ? "}" - : text === "\\begingroup" - ? "\\endgroup" - : "\\endtoggle"; - - this.gullet.beginGroup(); - // If we get a brace, parse an expression - const expression = this.parseExpression(false, groupEnd); - const lastToken = this.fetch(); - this.expect(groupEnd); // Check that we got a matching closing brace - this.gullet.endGroup(); - result = { - type: (lastToken.text === "\\endtoggle" ? "toggle" : "ordgroup"), - mode: this.mode, - loc: SourceLocation.range(firstToken, lastToken), - body: expression, - // A group formed by \begingroup...\endgroup is a semi-simple group - // which doesn't affect spacing in math mode, i.e., is transparent. - // https://tex.stackexchange.com/questions/1930/when-should-one- - // use-begingroup-instead-of-bgroup - semisimple: text === "\\begingroup" || undefined - }; - } else { - // If there exists a function with this name, parse the function. - // Otherwise, just return a nucleus - result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol(); - if (result == null && text[0] === "\\" && - !Object.prototype.hasOwnProperty.call(implicitCommands, text )) { - result = this.formatUnsupportedCmd(text); - this.consume(); - } - } - return result; - } - - /** - * Form ligature-like combinations of characters for text mode. - * This includes inputs like "--", "---", "``" and "''". - * The result will simply replace multiple textord nodes with a single - * character in each value by a single textord node having multiple - * characters in its value. The representation is still ASCII source. - * The group will be modified in place. - */ - formLigatures(group) { - let n = group.length - 1; - for (let i = 0; i < n; ++i) { - const a = group[i]; - const v = a.text; - if (v === "-" && group[i + 1].text === "-") { - if (i + 1 < n && group[i + 2].text === "-") { - group.splice(i, 3, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 2]), - text: "---" - }); - n -= 2; - } else { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: "--" - }); - n -= 1; - } - } - if ((v === "'" || v === "`") && group[i + 1].text === v) { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: v + v - }); - n -= 1; - } - } - } - - /** - * Parse a single symbol out of the string. Here, we handle single character - * symbols and special functions like \verb. - */ - parseSymbol() { - const nucleus = this.fetch(); - let text = nucleus.text; - - if (/^\\verb[^a-zA-Z]/.test(text)) { - this.consume(); - let arg = text.slice(5); - const star = arg.charAt(0) === "*"; - if (star) { - arg = arg.slice(1); - } - // Lexer's tokenRegex is constructed to always have matching - // first/last characters. - if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { - throw new ParseError(`\\verb assertion failed -- - please report what input caused this bug`); - } - arg = arg.slice(1, -1); // remove first and last char - return { - type: "verb", - mode: "text", - body: arg, - star - }; - } - // At this point, we should have a symbol, possibly with accents. - // First expand any accented base symbol according to unicodeSymbols. - if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0]) && - !symbols[this.mode][text[0]]) { - // This behavior is not strict (XeTeX-compatible) in math mode. - if (this.settings.strict && this.mode === "math") { - throw new ParseError(`Accented Unicode text character "${text[0]}" used in ` + `math mode`, - nucleus - ); - } - text = unicodeSymbols[text[0]] + text.slice(1); - } - // Strip off any combining characters - const match = combiningDiacriticalMarksEndRegex.exec(text); - if (match) { - text = text.substring(0, match.index); - if (text === "i") { - text = "\u0131"; // dotless i, in math and text mode - } else if (text === "j") { - text = "\u0237"; // dotless j, in math and text mode - } - } - // Recognize base symbol - let symbol; - if (symbols[this.mode][text]) { - const group = symbols[this.mode][text].group; - const loc = SourceLocation.range(nucleus); - let s; - if (Object.prototype.hasOwnProperty.call(ATOMS, group )) { - const family = group; - s = { - type: "atom", - mode: this.mode, - family, - loc, - text - }; - } else { - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (!this.strict && numberRegEx.test(text)) { - // A number. Wrap in a if in math mode; otherwise. - this.consume(); - return { - type: "textord", - mode: this.mode, - loc: SourceLocation.range(nucleus), - text - } - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict) { - if (!supportedCodepoint(text.charCodeAt(0))) { - throw new ParseError(`Unrecognized Unicode character "${text[0]}"` + - ` (${text.charCodeAt(0)})`, nucleus); - } else if (this.mode === "math") { - throw new ParseError(`Unicode text character "${text[0]}" used in math mode`, nucleus) - } - } - // All nonmathematical Unicode characters are rendered as if they - // are in text mode (wrapped in \text) because that's what it - // takes to render them in LaTeX. - symbol = { - type: "textord", - mode: "text", - loc: SourceLocation.range(nucleus), - text - }; - } else { - return null; // EOF, ^, _, {, }, etc. - } - this.consume(); - // Transform combining characters into accents - if (match) { - for (let i = 0; i < match[0].length; i++) { - const accent = match[0][i]; - if (!unicodeAccents[accent]) { - throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); - } - const command = unicodeAccents[accent][this.mode] || - unicodeAccents[accent].text; - if (!command) { - throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); - } - symbol = { - type: "accent", - mode: this.mode, - loc: SourceLocation.range(nucleus), - label: command, - isStretchy: false, - isShifty: true, - base: symbol - }; - } - } - return symbol; - } -} - -/** - * Parses an expression using a Parser, then returns the parsed result. - */ -const parseTree = function(toParse, settings) { - if (!(typeof toParse === "string" || toParse instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(toParse, settings); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - - let tree = parser.parse(); - - // LaTeX ignores a \tag placed outside an AMS environment. - if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) { - // If the input used \tag, it will set the \df@tag macro to the tag. - // In this case, we separately parse the tag and wrap the tree. - if (parser.gullet.macros.get("\\df@tag")) { - if (!settings.displayMode) { - throw new ParseError("\\tag works only in display mode") - } - parser.gullet.feed("\\df@tag"); - tree = [ - { - type: "tag", - mode: "text", - body: tree, - tag: parser.parse() - } - ]; - } - } - - return tree -}; - -/** - * This file contains information about the style that the mathmlBuilder carries - * around with it. Data is held in an `Style` object, and when - * recursing, a new `Style` object can be created with the `.with*` functions. - */ - -const subOrSupLevel = [2, 2, 3, 3]; - -/** - * This is the main Style class. It contains the current style.level, color, and font. - * - * Style objects should not be modified. To create a new Style with - * different properties, call a `.with*` method. - */ -class Style { - constructor(data) { - // Style.level can be 0 | 1 | 2 | 3, which correspond to - // displaystyle, textstyle, scriptstyle, and scriptscriptstyle. - // style.level does not directly set MathML's script level. MathML does that itself. - // We use style.level to track, not set, math style so that we can get the - // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em. - this.level = data.level; - this.color = data.color; // string | void - // A font family applies to a group of fonts (i.e. SansSerif), while a font - // represents a specific font (i.e. SansSerif Bold). - // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm - this.font = data.font || ""; // string - this.fontFamily = data.fontFamily || ""; // string - this.fontSize = data.fontSize || 1.0; // number - this.fontWeight = data.fontWeight || ""; - this.fontShape = data.fontShape || ""; - this.maxSize = data.maxSize; // [number, number] - } - - /** - * Returns a new style object with the same properties as "this". Properties - * from "extension" will be copied to the new style object. - */ - extend(extension) { - const data = { - level: this.level, - color: this.color, - font: this.font, - fontFamily: this.fontFamily, - fontSize: this.fontSize, - fontWeight: this.fontWeight, - fontShape: this.fontShape, - maxSize: this.maxSize - }; - - for (const key in extension) { - if (Object.prototype.hasOwnProperty.call(extension, key)) { - data[key] = extension[key]; - } - } - - return new Style(data); - } - - withLevel(n) { - return this.extend({ - level: n - }); - } - - incrementLevel() { - return this.extend({ - level: Math.min(this.level + 1, 3) - }); - } - - inSubOrSup() { - return this.extend({ - level: subOrSupLevel[this.level] - }) - } - - /** - * Create a new style object with the given color. - */ - withColor(color) { - return this.extend({ - color: color - }); - } - - /** - * Creates a new style object with the given math font or old text font. - * @type {[type]} - */ - withFont(font) { - return this.extend({ - font - }); - } - - /** - * Create a new style objects with the given fontFamily. - */ - withTextFontFamily(fontFamily) { - return this.extend({ - fontFamily, - font: "" - }); - } - - /** - * Creates a new style object with the given font size - */ - withFontSize(num) { - return this.extend({ - fontSize: num - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontWeight(fontWeight) { - return this.extend({ - fontWeight, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontShape(fontShape) { - return this.extend({ - fontShape, - font: "" - }); - } - - /** - * Gets the CSS color of the current style object - */ - getColor() { - return this.color; - } -} - -/* Temml Post Process - * Perform two tasks not done by Temml when it created each individual Temml element. - * Given a block of block, - * 1. At each AMS auto-numbered environment, assign an id. - * 2. Populate the text contents of each \ref & \eqref - * - * As with other Temml code, this file is released under terms of the MIT license. - * https://mit-license.org/ - */ - -const version = "0.6.9"; - -function postProcess(block) { - const labelMap = {}; - let i = 0; - - // Get a collection of the parents of each \tag & auto-numbered equation - const parents = block.getElementsByClassName("tml-tageqn"); - for (const parent of parents) { - const eqns = parent.getElementsByClassName("tml-eqn"); - if (eqns. length > 0 ) { - // AMS automatically numbered equation. - // Assign an id. - i += 1; - eqns[0].id = "tml-eqn-" + i; - // No need to write a number into the text content of the element. - // A CSS counter does that even if this postProcess() function is not used. - } - // If there is a \label, add it to labelMap - const labels = parent.getElementsByClassName("tml-label"); - if (labels.length === 0) { continue } - if (eqns.length > 0) { - labelMap[labels[0].id] = String(i); - } else { - const tags = parent.getElementsByClassName("tml-tag"); - if (tags.length > 0) { - labelMap[labels[0].id] = tags[0].textContent; - } - } - } - - // Populate \ref & \eqref text content - const refs = block.getElementsByClassName("tml-ref"); - [...refs].forEach(ref => { - let str = labelMap[ref.getAttribute("href").slice(1)]; - if (ref.className.indexOf("tml-eqref") === -1) { - // \ref. Omit parens. - str = str.replace(/^\(/, ""); - str = str.replace(/\($/, ""); - } { - // \eqref. Include parens - if (str.charAt(0) !== "(") { str = "(" + str; } - if (str.slice(-1) !== ")") { str = str + ")"; } - } - ref.textContent = str; - }); -} - -/* eslint no-console:0 */ - -/** - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options) { - baseNode.textContent = ""; - const math = renderToMathMLTree(expression, options); - if (options.elementIsMath) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else { - baseNode.appendChild(math.toNode()); - } -}; - -// Temml's styles don't work properly in quirks mode. Print out an error, and -// disable rendering. -if (typeof document !== "undefined") { - if (document.compatMode !== "CSS1Compat") { - typeof console !== "undefined" && - console.warn( - "Warning: Temml doesn't work in quirks mode. Make sure your " + - "website has a suitable doctype." - ); - - render = function() { - throw new ParseError("Temml doesn't work in quirks mode."); - }; - } -} - -/** - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * Take an expression which contains a preamble. - * Parse it and return the macros. - */ -const definePreamble = function(expression, options) { - const settings = new Settings(options); - settings.macros = {}; - if (!(typeof expression === "string" || expression instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(expression, settings, true); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - const macros = parser.parse(); - return macros -}; - -/** - * If the given error is a Temml ParseError, - * renders the invalid LaTeX as a span with hover title giving the Temml - * error message. Otherwise, simply throws the error. - */ -const renderError = function(error, expression, options) { - if (options.throwOnError || !(error instanceof ParseError)) { - throw error; - } - const node = new Span(["temml-error"], [new TextNode$1(expression + "\n" + error.toString())]); - node.style.color = options.errorColor; - node.style.whiteSpace = "pre-line"; - return node; -}; - -/** - * Generates and returns the Temml build tree. This is used for advanced - * use cases (like rendering to custom output). - */ -const renderToMathMLTree = function(expression, options) { - const settings = new Settings(options); - try { - const tree = parseTree(expression, settings); - const style = new Style({ - level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT, - maxSize: settings.maxSize - }); - return buildMathML(tree, expression, style, settings); - } catch (error) { - return renderError(error, expression, settings); - } -}; - -var temml = { - /** - * Current Temml version - */ - version: version, - /** - * Renders the given LaTeX into MathML, and adds - * it as a child to the specified DOM node. - */ - render, - /** - * Renders the given LaTeX into MathML string, - * for sending to the client. - */ - renderToString, - /** - * Post-process an entire HTML block. - * Writes AMS auto-numbers and implements \ref{}. - * Typcally called once, after a loop has rendered many individual spans. - */ - postProcess, - /** - * Temml error, usually during parsing. - */ - ParseError, - /** - * Creates a set of macros with document-wide scope. - */ - definePreamble, - /** - * Parses the given LaTeX into Temml's internal parse tree structure, - * without rendering to HTML or MathML. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __parse: generateParseTree, - /** - * Renders the given LaTeX into a MathML internal DOM tree - * representation, without flattening that representation to a string. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __renderToMathMLTree: renderToMathMLTree, - /** - * adds a new symbol to builtin symbols table - */ - __defineSymbol: defineSymbol, - /** - * adds a new macro to builtin macro list - */ - __defineMacro: defineMacro -}; - -export { temml as default }; diff --git a/utils/temml.mjs.js b/utils/temml.mjs.js deleted file mode 100644 index 504be204..00000000 --- a/utils/temml.mjs.js +++ /dev/null @@ -1,13020 +0,0 @@ -/** - * This is the ParseError class, which is the main error thrown by Temml - * functions when something has gone wrong. This is used to distinguish internal - * errors from errors in the expression that the user provided. - * - * If possible, a caller should provide a Token or ParseNode with information - * about where in the source string the problem occurred. - */ -class ParseError { - constructor( - message, // The error message - token // An object providing position information - ) { - let error = " " + message; - let start; - - const loc = token && token.loc; - if (loc && loc.start <= loc.end) { - // If we have the input and a position, make the error a bit fancier - - // Get the input - const input = loc.lexer.input; - - // Prepend some information - start = loc.start; - const end = loc.end; - if (start === input.length) { - error += " at end of input: "; - } else { - error += " at position " + (start + 1) + ": "; - } - - // Underline token in question using combining underscores - const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); - - // Extract some context from the input and add it to the error - let left; - if (start > 15) { - left = "…" + input.slice(start - 15, start); - } else { - left = input.slice(0, start); - } - let right; - if (end + 15 < input.length) { - right = input.slice(end, end + 15) + "…"; - } else { - right = input.slice(end); - } - error += left + underlined + right; - } - - // Some hackery to make ParseError a prototype of Error - // See http://stackoverflow.com/a/8460753 - const self = new Error(error); - self.name = "TemmlParseError"; - self.__proto__ = ParseError.prototype; - self.position = start; - return self; - } -} - -ParseError.prototype.__proto__ = Error.prototype; - -// -/** - * This file contains a list of utility functions which are useful in other - * files. - */ - -/** - * Return whether an element is contained in a list - */ -const contains = function(list, elem) { - return list.indexOf(elem) !== -1; -}; - -/** - * Provide a default value if a setting is undefined - */ -const deflt = function(setting, defaultIfUndefined) { - return setting === undefined ? defaultIfUndefined : setting; -}; - -// hyphenate and escape adapted from Facebook's React under Apache 2 license - -const uppercase = /([A-Z])/g; -const hyphenate = function(str) { - return str.replace(uppercase, "-$1").toLowerCase(); -}; - -const ESCAPE_LOOKUP = { - "&": "&", - ">": ">", - "<": "<", - '"': """, - "'": "'" -}; - -const ESCAPE_REGEX = /[&><"']/g; - -/** - * Escapes text to prevent scripting attacks. - */ -function escape(text) { - return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); -} - -/** - * Sometimes we want to pull out the innermost element of a group. In most - * cases, this will just be the group itself, but when ordgroups and colors have - * a single element, we want to pull that out. - */ -const getBaseElem = function(group) { - if (group.type === "ordgroup") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "color") { - if (group.body.length === 1) { - return getBaseElem(group.body[0]); - } else { - return group; - } - } else if (group.type === "font") { - return getBaseElem(group.body); - } else { - return group; - } -}; - -/** - * TeXbook algorithms often reference "character boxes", which are simply groups - * with a single character in them. To decide if something is a character box, - * we find its innermost group, and see if it is a single character. - */ -const isCharacterBox = function(group) { - const baseElem = getBaseElem(group); - - // These are all the types of groups which hold single characters - return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom" -}; - -const assert = function(value) { - if (!value) { - throw new Error("Expected non-null, but got " + String(value)); - } - return value; -}; - -/** - * Return the protocol of a URL, or "_relative" if the URL does not specify a - * protocol (and thus is relative). - */ -const protocolFromUrl = function(url) { - const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url); - return protocol != null ? protocol[1] : "_relative"; -}; - -/** - * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook - * gives an acceptable rounding error of 100sp (which would be the nearest - * 1/6551.6em with our ptPerEm = 10): - * http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69 - */ -const round = function(n) { - return +n.toFixed(4); -}; - -var utils = { - contains, - deflt, - escape, - hyphenate, - getBaseElem, - isCharacterBox, - protocolFromUrl, - round -}; - -/** - * This is a module for storing settings passed into Temml. It correctly handles - * default settings. - */ - -/** - * The main Settings object - */ -class Settings { - constructor(options) { - // allow null options - options = options || {}; - this.displayMode = utils.deflt(options.displayMode, false); // boolean - this.annotate = utils.deflt(options.annotate, false); // boolean - this.elementIsMath = utils.deflt(options.elementIsMath, false); // boolean - this.leqno = utils.deflt(options.leqno, false); // boolean - this.errorColor = utils.deflt(options.errorColor, "#b22222"); // string - this.preventTagLap = utils.deflt(options.preventTagLap, false); // boolean - this.macros = options.macros || {}; - this.xml = utils.deflt(options.xml, false); // boolean - this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); // booelean - this.strict = utils.deflt(options.strict, false); // boolean - this.trust = utils.deflt(options.trust, false); // trust context. See html.js. - this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity)); // number - this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000)); // number - } - - /** - * Report nonstrict (non-LaTeX-compatible) input. - * Can safely not be called if `this.strict` is false in JavaScript. - */ - reportNonstrict(errorCode, errorMsg, token) { - const strict = this.strict; - if (strict === false) { - return; - } else if (strict === true) { - throw new ParseError( - "LaTeX-incompatible input and strict mode is set to 'error': " + - `${errorMsg} [${errorCode}]`, - token - ); - } else { - // won't happen in type-safe code - return; - } - } - - /** - * Check whether to test potentially dangerous input, and return - * `true` (trusted) or `false` (untrusted). The sole argument `context` - * should be an object with `command` field specifying the relevant LaTeX - * command (as a string starting with `\`), and any other arguments, etc. - * If `context` has a `url` field, a `protocol` field will automatically - * get added by this function (changing the specified object). - */ - isTrusted(context) { - if (context.url && !context.protocol) { - context.protocol = utils.protocolFromUrl(context.url); - } - const trust = typeof this.trust === "function" ? this.trust(context) : this.trust; - return Boolean(trust); - } -} - -/** - * All registered functions. - * `functions.js` just exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary. - */ -const _functions = {}; - -/** - * All MathML builders. Should be only used in the `define*` and the `build*ML` - * functions. - */ -const _mathmlGroupBuilders = {}; - -function defineFunction({ - type, - names, - props, - handler, - mathmlBuilder -}) { - // Set default values of functions - const data = { - type, - numArgs: props.numArgs, - argTypes: props.argTypes, - allowedInArgument: !!props.allowedInArgument, - allowedInText: !!props.allowedInText, - allowedInMath: props.allowedInMath === undefined ? true : props.allowedInMath, - numOptionalArgs: props.numOptionalArgs || 0, - infix: !!props.infix, - primitive: !!props.primitive, - handler: handler - }; - for (let i = 0; i < names.length; ++i) { - _functions[names[i]] = data; - } - if (type) { - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } - } -} - -/** - * Use this to register only the MathML builder for a function(e.g. - * if the function's ParseNode is generated in Parser.js rather than via a - * stand-alone handler provided to `defineFunction`). - */ -function defineFunctionBuilders({ type, mathmlBuilder }) { - defineFunction({ - type, - names: [], - props: { numArgs: 0 }, - handler() { - throw new Error("Should never be called.") - }, - mathmlBuilder - }); -} - -const normalizeArgument = function(arg) { - return arg.type === "ordgroup" && arg.body.length === 1 ? arg.body[0] : arg -}; - -// Since the corresponding buildMathML function expects a -// list of elements, we normalize for different kinds of arguments -const ordargument = function(arg) { - return arg.type === "ordgroup" ? arg.body : [arg] -}; - -/** - * This node represents a document fragment, which contains elements, but when - * placed into the DOM doesn't have any representation itself. It only contains - * children and doesn't have any DOM node properties. - */ -class DocumentFragment { - constructor(children) { - this.children = children; - this.classes = []; - this.style = {}; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - /** Convert the fragment into a node. */ - toNode() { - const frag = document.createDocumentFragment(); - - for (let i = 0; i < this.children.length; i++) { - frag.appendChild(this.children[i].toNode()); - } - - return frag; - } - - /** Convert the fragment into HTML markup. */ - toMarkup() { - let markup = ""; - - // Simply concatenate the markup for the children together. - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText. Applies to - * MathDomNode's only. - */ - toText() { - // To avoid this, we would subclass documentFragment separately for - // MathML, but polyfills for subclassing is expensive per PR 1469. - const toText = (child) => child.toText(); - return this.children.map(toText).join(""); - } -} - -/** - * These objects store the data about the DOM nodes we create, as well as some - * extra data. They can then be transformed into real DOM nodes with the - * `toNode` function or HTML markup using `toMarkup`. They are useful for both - * storing extra properties on the nodes, as well as providing a way to easily - * work with the DOM. - * - * Similar functions for working with MathML nodes exist in mathMLTree.js. - * - */ - -/** - * Create an HTML className based on a list of classes. In addition to joining - * with spaces, we also remove empty classes. - */ -const createClass = function(classes) { - return classes.filter((cls) => cls).join(" "); -}; - -const initNode = function(classes, style) { - this.classes = classes || []; - this.attributes = {}; - this.style = style || {}; -}; - -/** - * Convert into an HTML node - */ -const toNode = function(tagName) { - const node = document.createElement(tagName); - - // Apply the class - node.className = createClass(this.classes); - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - // Apply attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - // Append the children, also as HTML nodes - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; -}; - -/** - * Convert into an HTML markup string - */ -const toMarkup = function(tagName) { - let markup = `<${tagName}`; - - // Add the class - if (this.classes.length) { - markup += ` class="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr )) { - markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`; - } - } - - markup += ">"; - - // Add the markup of the children, also as markup - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ``; - - return markup; -}; - -/** - * This node represents a span node, with a className, a list of children, and - * an inline style. - * - */ -class Span { - constructor(classes, children, style) { - initNode.call(this, classes, style); - this.children = children || []; - } - - setAttribute(attribute, value) { - this.attributes[attribute] = value; - } - - toNode() { - return toNode.call(this, "span"); - } - - toMarkup() { - return toMarkup.call(this, "span"); - } -} - -class TextNode { - constructor(text) { - this.text = text; - } - toNode() { - return document.createTextNode(this.text); - } - toMarkup() { - return utils.escape(this.text); - } -} - -/** - * This node represents an image embed () element. - */ -class Img { - constructor(src, alt, style) { - this.alt = alt; - this.src = src; - this.classes = ["mord"]; - this.style = style; - } - - hasClass(className) { - return utils.contains(this.classes, className); - } - - toNode() { - const node = document.createElement("img"); - node.src = this.src; - node.alt = this.alt; - node.className = "mord"; - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - return node; - } - - toMarkup() { - let markup = `${this.alt}` and - * `` tags). - */ -class MathNode { - constructor(type, children, classes, style, isSVG) { - this.type = type; - this.attributes = {}; - this.children = children || []; - this.classes = classes || []; - this.style = style || {}; // Used for elements - this.isSVG = isSVG || false; - } - - /** - * Sets an attribute on a MathML node. MathML depends on attributes to convey a - * semantic content, so this is used heavily. - */ - setAttribute(name, value) { - this.attributes[name] = value; - } - - /** - * Gets an attribute on a MathML node. - */ - getAttribute(name) { - return this.attributes[name]; - } - - /** - * Converts the math node into a MathML-namespaced DOM element. - */ - toNode() { - const node = this.isSVG - ? document.createElementNS("http://www.w3.org/2000/svg", this.type) - : document.createElementNS("http://www.w3.org/1998/Math/MathML", this.type); - - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - node.setAttribute(attr, this.attributes[attr]); - } - } - - if (this.classes.length > 0) { - node.className = createClass(this.classes); - } - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - node.style[style] = this.style[style]; - } - } - - for (let i = 0; i < this.children.length; i++) { - node.appendChild(this.children[i].toNode()); - } - - return node; - } - - /** - * Converts the math node into an HTML markup string. - */ - toMarkup() { - let markup = "<" + this.type; - - // Add the attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - markup += " " + attr + '="'; - markup += utils.escape(this.attributes[attr]); - markup += '"'; - } - } - - if (this.classes.length > 0) { - markup += ` class ="${utils.escape(createClass(this.classes))}"`; - } - - let styles = ""; - - // Add the styles, after hyphenation - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style )) { - styles += `${utils.hyphenate(style)}:${this.style[style]};`; - } - } - - if (styles) { - markup += ` style="${styles}"`; - } - - markup += ">"; - - for (let i = 0; i < this.children.length; i++) { - markup += this.children[i].toMarkup(); - } - - markup += ""; - - return markup; - } - - /** - * Converts the math node into a string, similar to innerText, but escaped. - */ - toText() { - return this.children.map((child) => child.toText()).join(""); - } -} - -/** - * This node represents a piece of text. - */ -class TextNode$1 { - constructor(text) { - this.text = text; - } - - /** - * Converts the text node into a DOM text node. - */ - toNode() { - return document.createTextNode(this.text); - } - - /** - * Converts the text node into escaped HTML markup - * (representing the text itself). - */ - toMarkup() { - return utils.escape(this.toText()); - } - - /** - * Converts the text node into a string - * (representing the text iteself). - */ - toText() { - return this.text; - } -} - -// Do not make an the only child of a . -// An acts as its own implicit . -const wrapWithMstyle = expression => { - let node; - if (expression.length === 1 && expression[0].type === "mrow") { - node = expression.pop(); - node.type = "mstyle"; - } else { - node = new MathNode("mstyle", expression); - } - return node -}; - -var mathMLTree = { - MathNode, - TextNode: TextNode$1, - newDocumentFragment -}; - -/** - * This file provides support for building horizontal stretchy elements. - */ - -// From mhchem reaction arrows \ce{A <=>> B} and \ce{A <<=> B} -const keysWithoutUnicodePoints = ["equilibriumRight", "equilibriumLeft"]; - -const stretchyCodePoint = { - widehat: "^", - widecheck: "ˇ", - widetilde: "~", - wideparen: "⏜", // \u23dc - utilde: "~", - overleftarrow: "\u2190", - underleftarrow: "\u2190", - xleftarrow: "\u2190", - overrightarrow: "\u2192", - underrightarrow: "\u2192", - xrightarrow: "\u2192", - underbrace: "\u23df", - overbrace: "\u23de", - overgroup: "\u23e0", - overparen: "⏜", - undergroup: "\u23e1", - underparen: "\u23dd", - overleftrightarrow: "\u2194", - underleftrightarrow: "\u2194", - xleftrightarrow: "\u2194", - Overrightarrow: "\u21d2", - xRightarrow: "\u21d2", - overleftharpoon: "\u21bc", - xleftharpoonup: "\u21bc", - overrightharpoon: "\u21c0", - xrightharpoonup: "\u21c0", - xLeftarrow: "\u21d0", - xLeftrightarrow: "\u21d4", - xhookleftarrow: "\u21a9", - xhookrightarrow: "\u21aa", - xmapsto: "\u21a6", - xrightharpoondown: "\u21c1", - xleftharpoondown: "\u21bd", - xtwoheadleftarrow: "\u219e", - xtwoheadrightarrow: "\u21a0", - xlongequal: "=", - xrightleftarrows: "\u21c4", - yields: "\u2192", - yieldsLeft: "\u2190", - mesomerism: "\u2194", - longrightharpoonup: "\u21c0", - longleftharpoondown: "\u21bd", - "\\cdrightarrow": "\u2192", - "\\cdleftarrow": "\u2190", - "\\cdlongequal": "=" -}; - -const nodeFromObject = (obj) => { - // Build a stretchy arrow from two SVGs. - const children = []; - if (obj.children) { - obj.children.map(child => { children.push(nodeFromObject(child)); }); - } - const node = obj.type === "span" - ? new Span(null, children, obj.style) - : new mathMLTree.MathNode(obj.type, children, [], obj.style, true); - Object.entries(obj.attributes).forEach(([key, value]) => { - node.setAttribute(key, value); - }); - return node -}; - -const mathMLnode = function(label, macros = {}) { - const key = label.slice(1); - let child; - if (!keysWithoutUnicodePoints.includes(key)) { - child = new mathMLTree.TextNode(stretchyCodePoint[key]); - } else { - const atKey = "\\@" + key; - if (!macros.has(atKey)) { - throw new ParseError("Arrow not available. The mhchem package is needed.") - } - child = nodeFromObject(JSON.parse(macros.get(atKey))); - } - const node = new mathMLTree.MathNode("mo", [child]); - node.setAttribute("stretchy", "true"); - return node -}; - -var stretchy = { - mathMLnode -}; - -/** - * This file holds a list of all no-argument functions and single-character - * symbols (like 'a' or ';'). - * - * For each of the symbols, there are two properties they can have: - * - group (required): the ParseNode group type the symbol should have (i.e. - "textord", "mathord", etc). - * - replace: the character that this symbol or function should be - * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi - * character in the main font). - * - * The outermost map in the table indicates what mode the symbols should be - * accepted in (e.g. "math" or "text"). - */ - -// Some of these have a "-token" suffix since these are also used as `ParseNode` -// types for raw text tokens, and we want to avoid conflicts with higher-level -// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by -// looking up the `symbols` map. -const ATOMS = { - bin: 1, - close: 1, - inner: 1, - open: 1, - punct: 1, - rel: 1 -}; -const NON_ATOMS = { - "accent-token": 1, - mathord: 1, - "op-token": 1, - spacing: 1, - textord: 1 -}; - -const symbols = { - math: {}, - text: {} -}; - -/** `acceptUnicodeChar = true` is only applicable if `replace` is set. */ -function defineSymbol(mode, group, replace, name, acceptUnicodeChar) { - symbols[mode][name] = { group, replace }; - - if (acceptUnicodeChar && replace) { - symbols[mode][replace] = symbols[mode][name]; - } -} - -// Some abbreviations for commonly used strings. -// This helps minify the code, and also spotting typos using jshint. - -// modes: -const math = "math"; -const text = "text"; - -// groups: -const accent = "accent-token"; -const bin = "bin"; -const close = "close"; -const inner = "inner"; -const mathord = "mathord"; -const op = "op-token"; -const open = "open"; -const punct = "punct"; -const rel = "rel"; -const spacing = "spacing"; -const textord = "textord"; - -// Now comes the symbol table - -// Relation Symbols -defineSymbol(math, rel, "\u2261", "\\equiv", true); -defineSymbol(math, rel, "\u227a", "\\prec", true); -defineSymbol(math, rel, "\u227b", "\\succ", true); -defineSymbol(math, rel, "\u223c", "\\sim", true); -defineSymbol(math, rel, "\u27c2", "\\perp", true); -defineSymbol(math, rel, "\u2aaf", "\\preceq", true); -defineSymbol(math, rel, "\u2ab0", "\\succeq", true); -defineSymbol(math, rel, "\u2243", "\\simeq", true); -defineSymbol(math, rel, "\u224c", "\\backcong", true); -defineSymbol(math, rel, "|", "\\mid", true); -defineSymbol(math, rel, "\u226a", "\\ll", true); -defineSymbol(math, rel, "\u226b", "\\gg", true); -defineSymbol(math, rel, "\u224d", "\\asymp", true); -defineSymbol(math, rel, "\u2225", "\\parallel"); -defineSymbol(math, rel, "\u22c8", "\\bowtie", true); -defineSymbol(math, rel, "\u2323", "\\smile", true); -defineSymbol(math, rel, "\u2291", "\\sqsubseteq", true); -defineSymbol(math, rel, "\u2292", "\\sqsupseteq", true); -defineSymbol(math, rel, "\u2250", "\\doteq", true); -defineSymbol(math, rel, "\u2322", "\\frown", true); -defineSymbol(math, rel, "\u220b", "\\ni", true); -defineSymbol(math, rel, "\u220c", "\\notni", true); -defineSymbol(math, rel, "\u221d", "\\propto", true); -defineSymbol(math, rel, "\u22a2", "\\vdash", true); -defineSymbol(math, rel, "\u22a3", "\\dashv", true); -defineSymbol(math, rel, "\u220b", "\\owns"); -defineSymbol(math, rel, "\u2258", "\\arceq", true); -defineSymbol(math, rel, "\u2259", "\\wedgeq", true); -defineSymbol(math, rel, "\u225a", "\\veeeq", true); -defineSymbol(math, rel, "\u225b", "\\stareq", true); -defineSymbol(math, rel, "\u225d", "\\eqdef", true); -defineSymbol(math, rel, "\u225e", "\\measeq", true); -defineSymbol(math, rel, "\u225f", "\\questeq", true); -defineSymbol(math, rel, "\u2260", "\\ne", true); -defineSymbol(math, rel, "\u2260", "\\neq"); -// mathtools.sty -defineSymbol(math, rel, "\u2237", "\\dblcolon", true); -defineSymbol(math, rel, "\u2254", "\\coloneqq", true); -defineSymbol(math, rel, "\u2255", "\\eqqcolon", true); -defineSymbol(math, rel, "\u2239", "\\eqcolon", true); -defineSymbol(math, rel, "\u2A74", "\\Coloneqq", true); - -// Punctuation -defineSymbol(math, punct, "\u002e", "\\ldotp"); -defineSymbol(math, punct, "\u00b7", "\\cdotp"); - -// Misc Symbols -defineSymbol(math, textord, "\u0023", "\\#"); -defineSymbol(text, textord, "\u0023", "\\#"); -defineSymbol(math, textord, "\u0026", "\\&"); -defineSymbol(text, textord, "\u0026", "\\&"); -defineSymbol(math, textord, "\u2135", "\\aleph", true); -defineSymbol(math, textord, "\u2200", "\\forall", true); -defineSymbol(math, textord, "\u210f", "\\hbar", true); -defineSymbol(math, textord, "\u2203", "\\exists", true); -defineSymbol(math, textord, "\u2207", "\\nabla", true); -defineSymbol(math, textord, "\u266d", "\\flat", true); -defineSymbol(math, textord, "\u2113", "\\ell", true); -defineSymbol(math, textord, "\u266e", "\\natural", true); -defineSymbol(math, textord, "Å", "\\AA", true); -defineSymbol(text, textord, "Å", "\\AA", true); -defineSymbol(math, textord, "\u2663", "\\clubsuit", true); -defineSymbol(math, textord, "\u2667", "\\varclubsuit", true); -defineSymbol(math, textord, "\u2118", "\\wp", true); -defineSymbol(math, textord, "\u266f", "\\sharp", true); -defineSymbol(math, textord, "\u2662", "\\diamondsuit", true); -defineSymbol(math, textord, "\u2666", "\\vardiamondsuit", true); -defineSymbol(math, textord, "\u211c", "\\Re", true); -defineSymbol(math, textord, "\u2661", "\\heartsuit", true); -defineSymbol(math, textord, "\u2665", "\\varheartsuit", true); -defineSymbol(math, textord, "\u2111", "\\Im", true); -defineSymbol(math, textord, "\u2660", "\\spadesuit", true); -defineSymbol(math, textord, "\u2664", "\\varspadesuit", true); -defineSymbol(math, textord, "\u2640", "\\female", true); -defineSymbol(math, textord, "\u2642", "\\male", true); -defineSymbol(math, textord, "\u00a7", "\\S", true); -defineSymbol(text, textord, "\u00a7", "\\S"); -defineSymbol(math, textord, "\u00b6", "\\P", true); -defineSymbol(text, textord, "\u00b6", "\\P"); -defineSymbol(text, textord, "\u263a", "\\smiley", true); -defineSymbol(math, textord, "\u263a", "\\smiley", true); - -// Math and Text -defineSymbol(math, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\dag"); -defineSymbol(text, textord, "\u2020", "\\textdagger"); -defineSymbol(math, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\ddag"); -defineSymbol(text, textord, "\u2021", "\\textdaggerdbl"); - -// Large Delimiters -defineSymbol(math, close, "\u23b1", "\\rmoustache", true); -defineSymbol(math, open, "\u23b0", "\\lmoustache", true); -defineSymbol(math, close, "\u27ef", "\\rgroup", true); -defineSymbol(math, open, "\u27ee", "\\lgroup", true); - -// Binary Operators -defineSymbol(math, bin, "\u2213", "\\mp", true); -defineSymbol(math, bin, "\u2296", "\\ominus", true); -defineSymbol(math, bin, "\u228e", "\\uplus", true); -defineSymbol(math, bin, "\u2293", "\\sqcap", true); -defineSymbol(math, bin, "\u2217", "\\ast"); -defineSymbol(math, bin, "\u2294", "\\sqcup", true); -defineSymbol(math, bin, "\u25ef", "\\bigcirc", true); -defineSymbol(math, bin, "\u2219", "\\bullet"); -defineSymbol(math, bin, "\u2021", "\\ddagger"); -defineSymbol(math, bin, "\u2240", "\\wr", true); -defineSymbol(math, bin, "\u2a3f", "\\amalg"); -defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath - -// Arrow Symbols -defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true); -defineSymbol(math, rel, "\u21d0", "\\Leftarrow", true); -defineSymbol(math, rel, "\u27f8", "\\Longleftarrow", true); -defineSymbol(math, rel, "\u27f6", "\\longrightarrow", true); -defineSymbol(math, rel, "\u21d2", "\\Rightarrow", true); -defineSymbol(math, rel, "\u27f9", "\\Longrightarrow", true); -defineSymbol(math, rel, "\u2194", "\\leftrightarrow", true); -defineSymbol(math, rel, "\u27f7", "\\longleftrightarrow", true); -defineSymbol(math, rel, "\u21d4", "\\Leftrightarrow", true); -defineSymbol(math, rel, "\u27fa", "\\Longleftrightarrow", true); -defineSymbol(math, rel, "\u21a6", "\\mapsto", true); -defineSymbol(math, rel, "\u27fc", "\\longmapsto", true); -defineSymbol(math, rel, "\u2197", "\\nearrow", true); -defineSymbol(math, rel, "\u21a9", "\\hookleftarrow", true); -defineSymbol(math, rel, "\u21aa", "\\hookrightarrow", true); -defineSymbol(math, rel, "\u2198", "\\searrow", true); -defineSymbol(math, rel, "\u21bc", "\\leftharpoonup", true); -defineSymbol(math, rel, "\u21c0", "\\rightharpoonup", true); -defineSymbol(math, rel, "\u2199", "\\swarrow", true); -defineSymbol(math, rel, "\u21bd", "\\leftharpoondown", true); -defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true); -defineSymbol(math, rel, "\u2196", "\\nwarrow", true); -defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true); -defineSymbol(math, mathord, "\u21af", "\\lightning", true); -defineSymbol(math, mathord, "\u2030", "\\permil", true); -defineSymbol(text, textord, "\u2030", "\\permil"); - -// AMS Negated Binary Relations -defineSymbol(math, rel, "\u226e", "\\nless", true); -// Symbol names preceeded by "@" each have a corresponding macro. -defineSymbol(math, rel, "\u2a87", "\\lneq", true); -defineSymbol(math, rel, "\u2268", "\\lneqq", true); -defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq"); -defineSymbol(math, rel, "\u22e6", "\\lnsim", true); -defineSymbol(math, rel, "\u2a89", "\\lnapprox", true); -defineSymbol(math, rel, "\u2280", "\\nprec", true); -// unicode-math maps \u22e0 to \npreccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e0", "\\npreceq", true); -defineSymbol(math, rel, "\u22e8", "\\precnsim", true); -defineSymbol(math, rel, "\u2ab9", "\\precnapprox", true); -defineSymbol(math, rel, "\u2241", "\\nsim", true); -defineSymbol(math, rel, "\u2224", "\\nmid", true); -defineSymbol(math, rel, "\u2224", "\\nshortmid"); -defineSymbol(math, rel, "\u22ac", "\\nvdash", true); -defineSymbol(math, rel, "\u22ad", "\\nvDash", true); -defineSymbol(math, rel, "\u22ea", "\\ntriangleleft"); -defineSymbol(math, rel, "\u22ec", "\\ntrianglelefteq", true); -defineSymbol(math, rel, "\u2284", "\\nsubset", true); -defineSymbol(math, rel, "\u2285", "\\nsupset", true); -defineSymbol(math, rel, "\u228a", "\\subsetneq", true); -defineSymbol(math, rel, "\u228a\ufe00", "\\varsubsetneq"); -defineSymbol(math, rel, "\u2acb", "\\subsetneqq", true); -defineSymbol(math, rel, "\u2acb\ufe00", "\\varsubsetneqq"); -defineSymbol(math, rel, "\u226f", "\\ngtr", true); -defineSymbol(math, rel, "\u2a88", "\\gneq", true); -defineSymbol(math, rel, "\u2269", "\\gneqq", true); -defineSymbol(math, rel, "\u2269\ufe00", "\\gvertneqq"); -defineSymbol(math, rel, "\u22e7", "\\gnsim", true); -defineSymbol(math, rel, "\u2a8a", "\\gnapprox", true); -defineSymbol(math, rel, "\u2281", "\\nsucc", true); -// unicode-math maps \u22e1 to \nsucccurlyeq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u22e1", "\\nsucceq", true); -defineSymbol(math, rel, "\u22e9", "\\succnsim", true); -defineSymbol(math, rel, "\u2aba", "\\succnapprox", true); -// unicode-math maps \u2246 to \simneqq. We'll use the AMS synonym. -defineSymbol(math, rel, "\u2246", "\\ncong", true); -defineSymbol(math, rel, "\u2226", "\\nparallel", true); -defineSymbol(math, rel, "\u2226", "\\nshortparallel"); -defineSymbol(math, rel, "\u22af", "\\nVDash", true); -defineSymbol(math, rel, "\u22eb", "\\ntriangleright"); -defineSymbol(math, rel, "\u22ed", "\\ntrianglerighteq", true); -defineSymbol(math, rel, "\u228b", "\\supsetneq", true); -defineSymbol(math, rel, "\u228b", "\\varsupsetneq"); -defineSymbol(math, rel, "\u2acc", "\\supsetneqq", true); -defineSymbol(math, rel, "\u2acc\ufe00", "\\varsupsetneqq"); -defineSymbol(math, rel, "\u22ae", "\\nVdash", true); -defineSymbol(math, rel, "\u2ab5", "\\precneqq", true); -defineSymbol(math, rel, "\u2ab6", "\\succneqq", true); -defineSymbol(math, bin, "\u22b4", "\\unlhd"); -defineSymbol(math, bin, "\u22b5", "\\unrhd"); - -// AMS Negated Arrows -defineSymbol(math, rel, "\u219a", "\\nleftarrow", true); -defineSymbol(math, rel, "\u219b", "\\nrightarrow", true); -defineSymbol(math, rel, "\u21cd", "\\nLeftarrow", true); -defineSymbol(math, rel, "\u21cf", "\\nRightarrow", true); -defineSymbol(math, rel, "\u21ae", "\\nleftrightarrow", true); -defineSymbol(math, rel, "\u21ce", "\\nLeftrightarrow", true); - -// AMS Misc -defineSymbol(math, rel, "\u25b3", "\\vartriangle"); -defineSymbol(math, textord, "\u210f", "\\hslash"); -defineSymbol(math, textord, "\u25bd", "\\triangledown"); -defineSymbol(math, textord, "\u25ca", "\\lozenge"); -defineSymbol(math, textord, "\u24c8", "\\circledS"); -defineSymbol(math, textord, "\u00ae", "\\circledR", true); -defineSymbol(text, textord, "\u00ae", "\\circledR"); -defineSymbol(text, textord, "\u00ae", "\\textregistered"); -defineSymbol(math, textord, "\u2221", "\\measuredangle", true); -defineSymbol(math, textord, "\u2204", "\\nexists"); -defineSymbol(math, textord, "\u2127", "\\mho"); -defineSymbol(math, textord, "\u2132", "\\Finv", true); -defineSymbol(math, textord, "\u2141", "\\Game", true); -defineSymbol(math, textord, "\u2035", "\\backprime"); -defineSymbol(math, textord, "\u25b2", "\\blacktriangle"); -defineSymbol(math, textord, "\u25bc", "\\blacktriangledown"); -defineSymbol(math, textord, "\u25a0", "\\blacksquare"); -defineSymbol(math, textord, "\u29eb", "\\blacklozenge"); -defineSymbol(math, textord, "\u2605", "\\bigstar"); -defineSymbol(math, textord, "\u2222", "\\sphericalangle", true); -defineSymbol(math, textord, "\u2201", "\\complement", true); -// unicode-math maps U+F0 to \matheth. We map to AMS function \eth -defineSymbol(math, textord, "\u00f0", "\\eth", true); -defineSymbol(text, textord, "\u00f0", "\u00f0"); -defineSymbol(math, textord, "\u2571", "\\diagup"); -defineSymbol(math, textord, "\u2572", "\\diagdown"); -defineSymbol(math, textord, "\u25a1", "\\square"); -defineSymbol(math, textord, "\u25a1", "\\Box"); -defineSymbol(math, textord, "\u25ca", "\\Diamond"); -// unicode-math maps U+A5 to \mathyen. We map to AMS function \yen -defineSymbol(math, textord, "\u00a5", "\\yen", true); -defineSymbol(text, textord, "\u00a5", "\\yen", true); -defineSymbol(math, textord, "\u2713", "\\checkmark", true); -defineSymbol(text, textord, "\u2713", "\\checkmark"); -defineSymbol(math, textord, "\u2717", "\\ballotx", true); -defineSymbol(text, textord, "\u2717", "\\ballotx"); -defineSymbol(text, textord, "\u2022", "\\textbullet"); - -// AMS Hebrew -defineSymbol(math, textord, "\u2136", "\\beth", true); -defineSymbol(math, textord, "\u2138", "\\daleth", true); -defineSymbol(math, textord, "\u2137", "\\gimel", true); - -// AMS Greek -defineSymbol(math, textord, "\u03dd", "\\digamma", true); -defineSymbol(math, textord, "\u03f0", "\\varkappa"); - -// AMS Delimiters -defineSymbol(math, open, "\u231C", "\\ulcorner", true); -defineSymbol(math, close, "\u231D", "\\urcorner", true); -defineSymbol(math, open, "\u231E", "\\llcorner", true); -defineSymbol(math, close, "\u231F", "\\lrcorner", true); - -// AMS Binary Relations -defineSymbol(math, rel, "\u2266", "\\leqq", true); -defineSymbol(math, rel, "\u2a7d", "\\leqslant", true); -defineSymbol(math, rel, "\u2a95", "\\eqslantless", true); -defineSymbol(math, rel, "\u2272", "\\lesssim", true); -defineSymbol(math, rel, "\u2a85", "\\lessapprox", true); -defineSymbol(math, rel, "\u224a", "\\approxeq", true); -defineSymbol(math, bin, "\u22d6", "\\lessdot"); -defineSymbol(math, rel, "\u22d8", "\\lll", true); -defineSymbol(math, rel, "\u2276", "\\lessgtr", true); -defineSymbol(math, rel, "\u22da", "\\lesseqgtr", true); -defineSymbol(math, rel, "\u2a8b", "\\lesseqqgtr", true); -defineSymbol(math, rel, "\u2251", "\\doteqdot"); -defineSymbol(math, rel, "\u2253", "\\risingdotseq", true); -defineSymbol(math, rel, "\u2252", "\\fallingdotseq", true); -defineSymbol(math, rel, "\u223d", "\\backsim", true); -defineSymbol(math, rel, "\u22cd", "\\backsimeq", true); -defineSymbol(math, rel, "\u2ac5", "\\subseteqq", true); -defineSymbol(math, rel, "\u22d0", "\\Subset", true); -defineSymbol(math, rel, "\u228f", "\\sqsubset", true); -defineSymbol(math, rel, "\u227c", "\\preccurlyeq", true); -defineSymbol(math, rel, "\u22de", "\\curlyeqprec", true); -defineSymbol(math, rel, "\u227e", "\\precsim", true); -defineSymbol(math, rel, "\u2ab7", "\\precapprox", true); -defineSymbol(math, rel, "\u22b2", "\\vartriangleleft"); -defineSymbol(math, rel, "\u22b4", "\\trianglelefteq"); -defineSymbol(math, rel, "\u22a8", "\\vDash", true); -defineSymbol(math, rel, "\u22aa", "\\Vvdash", true); -defineSymbol(math, rel, "\u2323", "\\smallsmile"); -defineSymbol(math, rel, "\u2322", "\\smallfrown"); -defineSymbol(math, rel, "\u224f", "\\bumpeq", true); -defineSymbol(math, rel, "\u224e", "\\Bumpeq", true); -defineSymbol(math, rel, "\u2267", "\\geqq", true); -defineSymbol(math, rel, "\u2a7e", "\\geqslant", true); -defineSymbol(math, rel, "\u2a96", "\\eqslantgtr", true); -defineSymbol(math, rel, "\u2273", "\\gtrsim", true); -defineSymbol(math, rel, "\u2a86", "\\gtrapprox", true); -defineSymbol(math, bin, "\u22d7", "\\gtrdot"); -defineSymbol(math, rel, "\u22d9", "\\ggg", true); -defineSymbol(math, rel, "\u2277", "\\gtrless", true); -defineSymbol(math, rel, "\u22db", "\\gtreqless", true); -defineSymbol(math, rel, "\u2a8c", "\\gtreqqless", true); -defineSymbol(math, rel, "\u2256", "\\eqcirc", true); -defineSymbol(math, rel, "\u2257", "\\circeq", true); -defineSymbol(math, rel, "\u225c", "\\triangleq", true); -defineSymbol(math, rel, "\u223c", "\\thicksim"); -defineSymbol(math, rel, "\u2248", "\\thickapprox"); -defineSymbol(math, rel, "\u2ac6", "\\supseteqq", true); -defineSymbol(math, rel, "\u22d1", "\\Supset", true); -defineSymbol(math, rel, "\u2290", "\\sqsupset", true); -defineSymbol(math, rel, "\u227d", "\\succcurlyeq", true); -defineSymbol(math, rel, "\u22df", "\\curlyeqsucc", true); -defineSymbol(math, rel, "\u227f", "\\succsim", true); -defineSymbol(math, rel, "\u2ab8", "\\succapprox", true); -defineSymbol(math, rel, "\u22b3", "\\vartriangleright"); -defineSymbol(math, rel, "\u22b5", "\\trianglerighteq"); -defineSymbol(math, rel, "\u22a9", "\\Vdash", true); -defineSymbol(math, rel, "\u2223", "\\shortmid"); -defineSymbol(math, rel, "\u2225", "\\shortparallel"); -defineSymbol(math, rel, "\u226c", "\\between", true); -defineSymbol(math, rel, "\u22d4", "\\pitchfork", true); -defineSymbol(math, rel, "\u221d", "\\varpropto"); -defineSymbol(math, rel, "\u25c0", "\\blacktriangleleft"); -// unicode-math says that \therefore is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2234", "\\therefore", true); -defineSymbol(math, rel, "\u220d", "\\backepsilon"); -defineSymbol(math, rel, "\u25b6", "\\blacktriangleright"); -// unicode-math says that \because is a mathord atom. -// We kept the amssymb atom type, which is rel. -defineSymbol(math, rel, "\u2235", "\\because", true); -defineSymbol(math, rel, "\u22d8", "\\llless"); -defineSymbol(math, rel, "\u22d9", "\\gggtr"); -defineSymbol(math, bin, "\u22b2", "\\lhd"); -defineSymbol(math, bin, "\u22b3", "\\rhd"); -defineSymbol(math, rel, "\u2242", "\\eqsim", true); -defineSymbol(math, rel, "\u22c8", "\\Join"); -defineSymbol(math, rel, "\u2251", "\\Doteq", true); - -// AMS Binary Operators -defineSymbol(math, bin, "\u2214", "\\dotplus", true); -defineSymbol(math, bin, "\u2216", "\\smallsetminus"); -defineSymbol(math, bin, "\u22d2", "\\Cap", true); -defineSymbol(math, bin, "\u22d3", "\\Cup", true); -defineSymbol(math, bin, "\u2a5e", "\\doublebarwedge", true); -defineSymbol(math, bin, "\u229f", "\\boxminus", true); -defineSymbol(math, bin, "\u229e", "\\boxplus", true); -defineSymbol(math, bin, "\u22c7", "\\divideontimes", true); -defineSymbol(math, bin, "\u22c9", "\\ltimes", true); -defineSymbol(math, bin, "\u22ca", "\\rtimes", true); -defineSymbol(math, bin, "\u22cb", "\\leftthreetimes", true); -defineSymbol(math, bin, "\u22cc", "\\rightthreetimes", true); -defineSymbol(math, bin, "\u22cf", "\\curlywedge", true); -defineSymbol(math, bin, "\u22ce", "\\curlyvee", true); -defineSymbol(math, bin, "\u229d", "\\circleddash", true); -defineSymbol(math, bin, "\u229b", "\\circledast", true); -defineSymbol(math, bin, "\u22ba", "\\intercal", true); -defineSymbol(math, bin, "\u22d2", "\\doublecap"); -defineSymbol(math, bin, "\u22d3", "\\doublecup"); -defineSymbol(math, bin, "\u22a0", "\\boxtimes", true); - -// AMS Arrows -// Note: unicode-math maps \u21e2 to their own function \rightdasharrow. -// We'll map it to AMS function \dashrightarrow. It produces the same atom. -defineSymbol(math, rel, "\u21e2", "\\dashrightarrow", true); -// unicode-math maps \u21e0 to \leftdasharrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21e0", "\\dashleftarrow", true); -defineSymbol(math, rel, "\u21c7", "\\leftleftarrows", true); -defineSymbol(math, rel, "\u21c6", "\\leftrightarrows", true); -defineSymbol(math, rel, "\u21da", "\\Lleftarrow", true); -defineSymbol(math, rel, "\u219e", "\\twoheadleftarrow", true); -defineSymbol(math, rel, "\u21a2", "\\leftarrowtail", true); -defineSymbol(math, rel, "\u21ab", "\\looparrowleft", true); -defineSymbol(math, rel, "\u21cb", "\\leftrightharpoons", true); -defineSymbol(math, rel, "\u21b6", "\\curvearrowleft", true); -// unicode-math maps \u21ba to \acwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21ba", "\\circlearrowleft", true); -defineSymbol(math, rel, "\u21b0", "\\Lsh", true); -defineSymbol(math, rel, "\u21c8", "\\upuparrows", true); -defineSymbol(math, rel, "\u21bf", "\\upharpoonleft", true); -defineSymbol(math, rel, "\u21c3", "\\downharpoonleft", true); -defineSymbol(math, rel, "\u22b6", "\\origof", true); -defineSymbol(math, rel, "\u22b7", "\\imageof", true); -defineSymbol(math, rel, "\u22b8", "\\multimap", true); -defineSymbol(math, rel, "\u21ad", "\\leftrightsquigarrow", true); -defineSymbol(math, rel, "\u21c9", "\\rightrightarrows", true); -defineSymbol(math, rel, "\u21c4", "\\rightleftarrows", true); -defineSymbol(math, rel, "\u21a0", "\\twoheadrightarrow", true); -defineSymbol(math, rel, "\u21a3", "\\rightarrowtail", true); -defineSymbol(math, rel, "\u21ac", "\\looparrowright", true); -defineSymbol(math, rel, "\u21b7", "\\curvearrowright", true); -// unicode-math maps \u21bb to \cwopencirclearrow. We'll use the AMS synonym. -defineSymbol(math, rel, "\u21bb", "\\circlearrowright", true); -defineSymbol(math, rel, "\u21b1", "\\Rsh", true); -defineSymbol(math, rel, "\u21ca", "\\downdownarrows", true); -defineSymbol(math, rel, "\u21be", "\\upharpoonright", true); -defineSymbol(math, rel, "\u21c2", "\\downharpoonright", true); -defineSymbol(math, rel, "\u21dd", "\\rightsquigarrow", true); -defineSymbol(math, rel, "\u21dd", "\\leadsto"); -defineSymbol(math, rel, "\u21db", "\\Rrightarrow", true); -defineSymbol(math, rel, "\u21be", "\\restriction"); - -defineSymbol(math, textord, "\u2018", "`"); -defineSymbol(math, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\$"); -defineSymbol(text, textord, "$", "\\textdollar"); -defineSymbol(math, textord, "%", "\\%"); -defineSymbol(text, textord, "%", "\\%"); -defineSymbol(math, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\_"); -defineSymbol(text, textord, "_", "\\textunderscore"); -defineSymbol(text, textord, "\u2423", "\\textvisiblespace", true); -defineSymbol(math, textord, "\u2220", "\\angle", true); -defineSymbol(math, textord, "\u221e", "\\infty", true); -defineSymbol(math, textord, "\u2032", "\\prime"); -defineSymbol(math, textord, "\u25b3", "\\triangle"); -defineSymbol(text, textord, "\u0391", "\\Alpha", true); -defineSymbol(text, textord, "\u0392", "\\Beta", true); -defineSymbol(text, textord, "\u0393", "\\Gamma", true); -defineSymbol(text, textord, "\u0394", "\\Delta", true); -defineSymbol(text, textord, "\u0395", "\\Epsilon", true); -defineSymbol(text, textord, "\u0396", "\\Zeta", true); -defineSymbol(text, textord, "\u0397", "\\Eta", true); -defineSymbol(text, textord, "\u0398", "\\Theta", true); -defineSymbol(text, textord, "\u0399", "\\Iota", true); -defineSymbol(text, textord, "\u039a", "\\Kappa", true); -defineSymbol(text, textord, "\u039b", "\\Lambda", true); -defineSymbol(text, textord, "\u039c", "\\Mu", true); -defineSymbol(text, textord, "\u039d", "\\Nu", true); -defineSymbol(text, textord, "\u039e", "\\Xi", true); -defineSymbol(text, textord, "\u039f", "\\Omicron", true); -defineSymbol(text, textord, "\u03a0", "\\Pi", true); -defineSymbol(text, textord, "\u03a1", "\\Rho", true); -defineSymbol(text, textord, "\u03a3", "\\Sigma", true); -defineSymbol(text, textord, "\u03a4", "\\Tau", true); -defineSymbol(text, textord, "\u03a5", "\\Upsilon", true); -defineSymbol(text, textord, "\u03a6", "\\Phi", true); -defineSymbol(text, textord, "\u03a7", "\\Chi", true); -defineSymbol(text, textord, "\u03a8", "\\Psi", true); -defineSymbol(text, textord, "\u03a9", "\\Omega", true); -defineSymbol(math, mathord, "\u0391", "\\Alpha", true); -defineSymbol(math, mathord, "\u0392", "\\Beta", true); -defineSymbol(math, mathord, "\u0393", "\\Gamma", true); -defineSymbol(math, mathord, "\u0394", "\\Delta", true); -defineSymbol(math, mathord, "\u0395", "\\Epsilon", true); -defineSymbol(math, mathord, "\u0396", "\\Zeta", true); -defineSymbol(math, mathord, "\u0397", "\\Eta", true); -defineSymbol(math, mathord, "\u0398", "\\Theta", true); -defineSymbol(math, mathord, "\u0399", "\\Iota", true); -defineSymbol(math, mathord, "\u039a", "\\Kappa", true); -defineSymbol(math, mathord, "\u039b", "\\Lambda", true); -defineSymbol(math, mathord, "\u039c", "\\Mu", true); -defineSymbol(math, mathord, "\u039d", "\\Nu", true); -defineSymbol(math, mathord, "\u039e", "\\Xi", true); -defineSymbol(math, mathord, "\u039f", "\\Omicron", true); -defineSymbol(math, mathord, "\u03a0", "\\Pi", true); -defineSymbol(math, mathord, "\u03a1", "\\Rho", true); -defineSymbol(math, mathord, "\u03a3", "\\Sigma", true); -defineSymbol(math, mathord, "\u03a4", "\\Tau", true); -defineSymbol(math, mathord, "\u03a5", "\\Upsilon", true); -defineSymbol(math, mathord, "\u03a6", "\\Phi", true); -defineSymbol(math, mathord, "\u03a7", "\\Chi", true); -defineSymbol(math, mathord, "\u03a8", "\\Psi", true); -defineSymbol(math, mathord, "\u03a9", "\\Omega", true); -defineSymbol(math, textord, "\u00ac", "\\neg", true); -defineSymbol(math, textord, "\u00ac", "\\lnot"); -defineSymbol(math, textord, "\u22a4", "\\top"); -defineSymbol(math, textord, "\u22a5", "\\bot"); -defineSymbol(math, textord, "\u2205", "\\emptyset"); -defineSymbol(math, textord, "\u00f8", "\\varnothing"); -defineSymbol(math, mathord, "\u03b1", "\\alpha", true); -defineSymbol(math, mathord, "\u03b2", "\\beta", true); -defineSymbol(math, mathord, "\u03b3", "\\gamma", true); -defineSymbol(math, mathord, "\u03b4", "\\delta", true); -defineSymbol(math, mathord, "\u03f5", "\\epsilon", true); -defineSymbol(math, mathord, "\u03b6", "\\zeta", true); -defineSymbol(math, mathord, "\u03b7", "\\eta", true); -defineSymbol(math, mathord, "\u03b8", "\\theta", true); -defineSymbol(math, mathord, "\u03b9", "\\iota", true); -defineSymbol(math, mathord, "\u03ba", "\\kappa", true); -defineSymbol(math, mathord, "\u03bb", "\\lambda", true); -defineSymbol(math, mathord, "\u03bc", "\\mu", true); -defineSymbol(math, mathord, "\u03bd", "\\nu", true); -defineSymbol(math, mathord, "\u03be", "\\xi", true); -defineSymbol(math, mathord, "\u03bf", "\\omicron", true); -defineSymbol(math, mathord, "\u03c0", "\\pi", true); -defineSymbol(math, mathord, "\u03c1", "\\rho", true); -defineSymbol(math, mathord, "\u03c3", "\\sigma", true); -defineSymbol(math, mathord, "\u03c4", "\\tau", true); -defineSymbol(math, mathord, "\u03c5", "\\upsilon", true); -defineSymbol(math, mathord, "\u03d5", "\\phi", true); -defineSymbol(math, mathord, "\u03c7", "\\chi", true); -defineSymbol(math, mathord, "\u03c8", "\\psi", true); -defineSymbol(math, mathord, "\u03c9", "\\omega", true); -defineSymbol(math, mathord, "\u03b5", "\\varepsilon", true); -defineSymbol(math, mathord, "\u03d1", "\\vartheta", true); -defineSymbol(math, mathord, "\u03d6", "\\varpi", true); -defineSymbol(math, mathord, "\u03f1", "\\varrho", true); -defineSymbol(math, mathord, "\u03c2", "\\varsigma", true); -defineSymbol(math, mathord, "\u03c6", "\\varphi", true); -defineSymbol(math, mathord, "\u03d8", "\\Coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\coppa", true); -defineSymbol(math, mathord, "\u03d9", "\\varcoppa", true); -defineSymbol(math, mathord, "\u03de", "\\Koppa", true); -defineSymbol(math, mathord, "\u03df", "\\koppa", true); -defineSymbol(math, mathord, "\u03e0", "\\Sampi", true); -defineSymbol(math, mathord, "\u03e1", "\\sampi", true); -defineSymbol(math, mathord, "\u03da", "\\Stigma", true); -defineSymbol(math, mathord, "\u03db", "\\stigma", true); -defineSymbol(math, bin, "\u2217", "\u2217", true); -defineSymbol(math, bin, "+", "+"); -defineSymbol(math, bin, "*", "*"); -defineSymbol(math, bin, "\u2044", "\u2044"); -defineSymbol(math, bin, "\u2212", "-", true); -defineSymbol(math, bin, "\u22c5", "\\cdot", true); -defineSymbol(math, bin, "\u2218", "\\circ"); -defineSymbol(math, bin, "\u00f7", "\\div", true); -defineSymbol(math, bin, "\u00b1", "\\pm", true); -defineSymbol(math, bin, "\u00d7", "\\times", true); -defineSymbol(math, bin, "\u2229", "\\cap", true); -defineSymbol(math, bin, "\u222a", "\\cup", true); -defineSymbol(math, bin, "\u2216", "\\setminus"); -defineSymbol(math, bin, "\u2227", "\\land"); -defineSymbol(math, bin, "\u2228", "\\lor"); -defineSymbol(math, bin, "\u2227", "\\wedge", true); -defineSymbol(math, bin, "\u2228", "\\vee", true); -defineSymbol(math, textord, "\u221a", "\\surd"); -defineSymbol(math, open, "\u27e6", "\\llbracket", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u27e7", "\\rrbracket", true); -defineSymbol(math, open, "\u27e8", "\\langle", true); -defineSymbol(math, open, "|", "\\lvert"); -defineSymbol(math, open, "\u2016", "\\lVert"); -defineSymbol(math, close, "?", "?"); -defineSymbol(math, close, "!", "!"); -defineSymbol(math, close, "‼", "‼"); -defineSymbol(math, close, "\u27e9", "\\rangle", true); -defineSymbol(math, close, "|", "\\rvert"); -defineSymbol(math, close, "\u2016", "\\rVert"); -defineSymbol(math, open, "\u2983", "\\lBrace", true); // stmaryrd/semantic packages -defineSymbol(math, close, "\u2984", "\\rBrace", true); -defineSymbol(math, rel, "=", "="); -defineSymbol(math, rel, "\u2248", "\\approx", true); -defineSymbol(math, rel, "\u2245", "\\cong", true); -defineSymbol(math, rel, "\u2265", "\\ge"); -defineSymbol(math, rel, "\u2265", "\\geq", true); -defineSymbol(math, rel, "\u2190", "\\gets"); -defineSymbol(math, rel, ">", "\\gt", true); -defineSymbol(math, rel, "\u2208", "\\in", true); -defineSymbol(math, rel, "\u2209", "\\notin", true); -defineSymbol(math, rel, "\ue020", "\\@not"); -defineSymbol(math, rel, "\u2282", "\\subset", true); -defineSymbol(math, rel, "\u2283", "\\supset", true); -defineSymbol(math, rel, "\u2286", "\\subseteq", true); -defineSymbol(math, rel, "\u2287", "\\supseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteq", true); -defineSymbol(math, rel, "\u2288", "\\nsubseteqq"); -defineSymbol(math, rel, "\u2289", "\\nsupseteq", true); -defineSymbol(math, rel, "\u2289", "\\nsupseteqq"); -defineSymbol(math, rel, "\u22a8", "\\models"); -defineSymbol(math, rel, "\u2190", "\\leftarrow", true); -defineSymbol(math, rel, "\u2264", "\\le"); -defineSymbol(math, rel, "\u2264", "\\leq", true); -defineSymbol(math, rel, "<", "\\lt", true); -defineSymbol(math, rel, "\u2192", "\\rightarrow", true); -defineSymbol(math, rel, "\u2192", "\\to"); -defineSymbol(math, rel, "\u2271", "\\ngeq", true); -defineSymbol(math, rel, "\u2271", "\\ngeqq"); -defineSymbol(math, rel, "\u2271", "\\ngeqslant"); -defineSymbol(math, rel, "\u2270", "\\nleq", true); -defineSymbol(math, rel, "\u2270", "\\nleqq"); -defineSymbol(math, rel, "\u2270", "\\nleqslant"); -defineSymbol(math, spacing, "\u00a0", "\\ "); -defineSymbol(math, spacing, "\u00a0", "\\space"); -// Ref: LaTeX Source 2e: \DeclareRobustCommand{\nobreakspace}{% -defineSymbol(math, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(text, spacing, "\u00a0", "\\ "); -defineSymbol(text, spacing, "\u00a0", " "); -defineSymbol(text, spacing, "\u00a0", "\\space"); -defineSymbol(text, spacing, "\u00a0", "\\nobreakspace"); -defineSymbol(math, spacing, null, "\\nobreak"); -defineSymbol(math, spacing, null, "\\allowbreak"); -defineSymbol(math, punct, ",", ","); -defineSymbol(math, punct, ";", ";"); -defineSymbol(math, bin, "\u22bc", "\\barwedge", true); -defineSymbol(math, bin, "\u22bb", "\\veebar", true); -defineSymbol(math, bin, "\u2299", "\\odot", true); -defineSymbol(math, bin, "\u2295", "\\oplus", true); -defineSymbol(math, bin, "\u2297", "\\otimes", true); -defineSymbol(math, textord, "\u2202", "\\partial", true); -defineSymbol(math, bin, "\u2298", "\\oslash", true); -defineSymbol(math, bin, "\u229a", "\\circledcirc", true); -defineSymbol(math, bin, "\u22a1", "\\boxdot", true); -defineSymbol(math, bin, "\u25b3", "\\bigtriangleup"); -defineSymbol(math, bin, "\u25bd", "\\bigtriangledown"); -defineSymbol(math, bin, "\u2020", "\\dagger"); -defineSymbol(math, bin, "\u22c4", "\\diamond"); -defineSymbol(math, bin, "\u22c6", "\\star"); -defineSymbol(math, bin, "\u25c3", "\\triangleleft"); -defineSymbol(math, bin, "\u25b9", "\\triangleright"); -defineSymbol(math, open, "{", "\\{"); -defineSymbol(text, textord, "{", "\\{"); -defineSymbol(text, textord, "{", "\\textbraceleft"); -defineSymbol(math, close, "}", "\\}"); -defineSymbol(text, textord, "}", "\\}"); -defineSymbol(text, textord, "}", "\\textbraceright"); -defineSymbol(math, open, "{", "\\lbrace"); -defineSymbol(math, close, "}", "\\rbrace"); -defineSymbol(math, open, "[", "\\lbrack", true); -defineSymbol(text, textord, "[", "\\lbrack", true); -defineSymbol(math, close, "]", "\\rbrack", true); -defineSymbol(text, textord, "]", "\\rbrack", true); -defineSymbol(math, open, "(", "\\lparen", true); -defineSymbol(math, close, ")", "\\rparen", true); -defineSymbol(text, textord, "<", "\\textless", true); // in T1 fontenc -defineSymbol(text, textord, ">", "\\textgreater", true); // in T1 fontenc -defineSymbol(math, open, "\u230a", "\\lfloor", true); -defineSymbol(math, close, "\u230b", "\\rfloor", true); -defineSymbol(math, open, "\u2308", "\\lceil", true); -defineSymbol(math, close, "\u2309", "\\rceil", true); -defineSymbol(math, textord, "\\", "\\backslash"); -defineSymbol(math, textord, "|", "|"); -defineSymbol(math, textord, "|", "\\vert"); -defineSymbol(text, textord, "|", "\\textbar", true); // in T1 fontenc -defineSymbol(math, textord, "\u2016", "\\|"); -defineSymbol(math, textord, "\u2016", "\\Vert"); -defineSymbol(text, textord, "\u2016", "\\textbardbl"); -defineSymbol(text, textord, "~", "\\textasciitilde"); -defineSymbol(text, textord, "\\", "\\textbackslash"); -defineSymbol(text, textord, "^", "\\textasciicircum"); -defineSymbol(math, rel, "\u2191", "\\uparrow", true); -defineSymbol(math, rel, "\u21d1", "\\Uparrow", true); -defineSymbol(math, rel, "\u2193", "\\downarrow", true); -defineSymbol(math, rel, "\u21d3", "\\Downarrow", true); -defineSymbol(math, rel, "\u2195", "\\updownarrow", true); -defineSymbol(math, rel, "\u21d5", "\\Updownarrow", true); -defineSymbol(math, op, "\u2210", "\\coprod"); -defineSymbol(math, op, "\u22c1", "\\bigvee"); -defineSymbol(math, op, "\u22c0", "\\bigwedge"); -defineSymbol(math, op, "\u2a04", "\\biguplus"); -defineSymbol(math, op, "\u22c2", "\\bigcap"); -defineSymbol(math, op, "\u22c3", "\\bigcup"); -defineSymbol(math, op, "\u222b", "\\int"); -defineSymbol(math, op, "\u222b", "\\intop"); -defineSymbol(math, op, "\u222c", "\\iint"); -defineSymbol(math, op, "\u222d", "\\iiint"); -defineSymbol(math, op, "\u220f", "\\prod"); -defineSymbol(math, op, "\u2211", "\\sum"); -defineSymbol(math, op, "\u2a02", "\\bigotimes"); -defineSymbol(math, op, "\u2a01", "\\bigoplus"); -defineSymbol(math, op, "\u2a00", "\\bigodot"); -defineSymbol(math, op, "\u222e", "\\oint"); -defineSymbol(math, op, "\u222f", "\\oiint"); -defineSymbol(math, op, "\u2230", "\\oiiint"); -defineSymbol(math, op, "\u2231", "\\intclockwise"); -defineSymbol(math, op, "\u2232", "\\varointclockwise"); -defineSymbol(math, op, "\u2a0c", "\\iiiint"); -defineSymbol(math, op, "\u2a0d", "\\intbar"); -defineSymbol(math, op, "\u2a0e", "\\intBar"); -defineSymbol(math, op, "\u2a0f", "\\fint"); -defineSymbol(math, op, "\u2a12", "\\rppolint"); -defineSymbol(math, op, "\u2a13", "\\scpolint"); -defineSymbol(math, op, "\u2a15", "\\pointint"); -defineSymbol(math, op, "\u2a16", "\\sqint"); -defineSymbol(math, op, "\u2a17", "\\intlarhk"); -defineSymbol(math, op, "\u2a18", "\\intx"); -defineSymbol(math, op, "\u2a19", "\\intcap"); -defineSymbol(math, op, "\u2a1a", "\\intcup"); -defineSymbol(math, op, "\u2a05", "\\bigsqcap"); -defineSymbol(math, op, "\u2a06", "\\bigsqcup"); -defineSymbol(math, op, "\u222b", "\\smallint"); -defineSymbol(text, inner, "\u2026", "\\textellipsis"); -defineSymbol(math, inner, "\u2026", "\\mathellipsis"); -defineSymbol(text, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u2026", "\\ldots", true); -defineSymbol(math, inner, "\u22f0", "\\iddots", true); -defineSymbol(math, inner, "\u22ef", "\\@cdots", true); -defineSymbol(math, inner, "\u22f1", "\\ddots", true); -defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro -defineSymbol(math, accent, "\u02ca", "\\acute"); -defineSymbol(math, accent, "\u0060", "\\grave"); -defineSymbol(math, accent, "\u00a8", "\\ddot"); -defineSymbol(math, accent, "\u20db", "\\dddot"); -defineSymbol(math, accent, "\u20dc", "\\ddddot"); -defineSymbol(math, accent, "\u007e", "\\tilde"); -defineSymbol(math, accent, "\u00af", "\\bar"); -defineSymbol(math, accent, "\u02d8", "\\breve"); -defineSymbol(math, accent, "\u02c7", "\\check"); -defineSymbol(math, accent, "\u005e", "\\hat"); -defineSymbol(math, accent, "\u20d7", "\\vec"); -defineSymbol(math, accent, "\u02d9", "\\dot"); -defineSymbol(math, accent, "\u02da", "\\mathring"); -defineSymbol(math, mathord, "\u0131", "\\imath", true); -defineSymbol(math, mathord, "\u0237", "\\jmath", true); -defineSymbol(math, textord, "\u0131", "\u0131"); -defineSymbol(math, textord, "\u0237", "\u0237"); -defineSymbol(text, textord, "\u0131", "\\i", true); -defineSymbol(text, textord, "\u0237", "\\j", true); -defineSymbol(text, textord, "\u00df", "\\ss", true); -defineSymbol(text, textord, "\u00e6", "\\ae", true); -defineSymbol(text, textord, "\u0153", "\\oe", true); -defineSymbol(text, textord, "\u00f8", "\\o", true); -defineSymbol(math, mathord, "\u00f8", "\\o", true); -defineSymbol(text, textord, "\u00c6", "\\AE", true); -defineSymbol(text, textord, "\u0152", "\\OE", true); -defineSymbol(text, textord, "\u00d8", "\\O", true); -defineSymbol(math, mathord, "\u00d8", "\\O", true); -defineSymbol(text, accent, "\u02ca", "\\'"); // acute -defineSymbol(text, accent, "\u02cb", "\\`"); // grave -defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(text, accent, "\u02dc", "\\~"); // tilde -defineSymbol(text, accent, "\u02c9", "\\="); // macron -defineSymbol(text, accent, "\u02d8", "\\u"); // breve -defineSymbol(text, accent, "\u02d9", "\\."); // dot above -defineSymbol(text, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(text, accent, "\u02da", "\\r"); // ring above -defineSymbol(text, accent, "\u02c7", "\\v"); // caron -defineSymbol(text, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(text, accent, "\u02dd", "\\H"); // double acute -defineSymbol(math, accent, "\u02ca", "\\'"); // acute -defineSymbol(math, accent, "\u02cb", "\\`"); // grave -defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex -defineSymbol(math, accent, "\u02dc", "\\~"); // tilde -defineSymbol(math, accent, "\u02c9", "\\="); // macron -defineSymbol(math, accent, "\u02d8", "\\u"); // breve -defineSymbol(math, accent, "\u02d9", "\\."); // dot above -defineSymbol(math, accent, "\u00b8", "\\c"); // cedilla -defineSymbol(math, accent, "\u02da", "\\r"); // ring above -defineSymbol(math, accent, "\u02c7", "\\v"); // caron -defineSymbol(math, accent, "\u00a8", '\\"'); // diaresis -defineSymbol(math, accent, "\u02dd", "\\H"); // double acute - -// These ligatures are detected and created in Parser.js's `formLigatures`. -const ligatures = { - "--": true, - "---": true, - "``": true, - "''": true -}; - -defineSymbol(text, textord, "\u2013", "--", true); -defineSymbol(text, textord, "\u2013", "\\textendash"); -defineSymbol(text, textord, "\u2014", "---", true); -defineSymbol(text, textord, "\u2014", "\\textemdash"); -defineSymbol(text, textord, "\u2018", "`", true); -defineSymbol(text, textord, "\u2018", "\\textquoteleft"); -defineSymbol(text, textord, "\u2019", "'", true); -defineSymbol(text, textord, "\u2019", "\\textquoteright"); -defineSymbol(text, textord, "\u201c", "``", true); -defineSymbol(text, textord, "\u201c", "\\textquotedblleft"); -defineSymbol(text, textord, "\u201d", "''", true); -defineSymbol(text, textord, "\u201d", "\\textquotedblright"); -// \degree from gensymb package -defineSymbol(math, textord, "\u00b0", "\\degree", true); -defineSymbol(text, textord, "\u00b0", "\\degree"); -// \textdegree from inputenc package -defineSymbol(text, textord, "\u00b0", "\\textdegree", true); -// TODO: In LaTeX, \pounds can generate a different character in text and math -// mode, but among our fonts, only Main-Regular defines this character "163". -defineSymbol(math, textord, "\u00a3", "\\pounds"); -defineSymbol(math, textord, "\u00a3", "\\mathsterling", true); -defineSymbol(text, textord, "\u00a3", "\\pounds"); -defineSymbol(text, textord, "\u00a3", "\\textsterling", true); -defineSymbol(math, textord, "\u2720", "\\maltese"); -defineSymbol(text, textord, "\u2720", "\\maltese"); -defineSymbol(math, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\euro", true); -defineSymbol(text, textord, "\u20ac", "\\texteuro"); -defineSymbol(math, textord, "\u00a9", "\\copyright", true); -defineSymbol(text, textord, "\u00a9", "\\textcopyright"); - -// Italic Greek -defineSymbol(math, textord, "𝛤", "\\varGamma"); -defineSymbol(math, textord, "𝛥", "\\varDelta"); -defineSymbol(math, textord, "𝛩", "\\varTheta"); -defineSymbol(math, textord, "𝛬", "\\varLambda"); -defineSymbol(math, textord, "𝛯", "\\varXi"); -defineSymbol(math, textord, "𝛱", "\\varPi"); -defineSymbol(math, textord, "𝛴", "\\varSigma"); -defineSymbol(math, textord, "𝛶", "\\varUpsilon"); -defineSymbol(math, textord, "𝛷", "\\varPhi"); -defineSymbol(math, textord, "𝛹", "\\varPsi"); -defineSymbol(math, textord, "𝛺", "\\varOmega"); -defineSymbol(text, textord, "𝛤", "\\varGamma"); -defineSymbol(text, textord, "𝛥", "\\varDelta"); -defineSymbol(text, textord, "𝛩", "\\varTheta"); -defineSymbol(text, textord, "𝛬", "\\varLambda"); -defineSymbol(text, textord, "𝛯", "\\varXi"); -defineSymbol(text, textord, "𝛱", "\\varPi"); -defineSymbol(text, textord, "𝛴", "\\varSigma"); -defineSymbol(text, textord, "𝛶", "\\varUpsilon"); -defineSymbol(text, textord, "𝛷", "\\varPhi"); -defineSymbol(text, textord, "𝛹", "\\varPsi"); -defineSymbol(text, textord, "𝛺", "\\varOmega"); - - -// There are lots of symbols which are the same, so we add them in afterwards. -// All of these are textords in math mode -const mathTextSymbols = '0123456789/@."'; -for (let i = 0; i < mathTextSymbols.length; i++) { - const ch = mathTextSymbols.charAt(i); - defineSymbol(math, textord, ch, ch); -} - -// All of these are textords in text mode -const textSymbols = '0123456789!@*()-=+";:?/.,'; -for (let i = 0; i < textSymbols.length; i++) { - const ch = textSymbols.charAt(i); - defineSymbol(text, textord, ch, ch); -} - -// All of these are textords in text mode, and mathords in math mode -const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -for (let i = 0; i < letters.length; i++) { - const ch = letters.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// Some more letters in Unicode Basic Multilingual Plane. -const narrow = "ÇÐÞçþℂℍℕℙℚℝℤℎℏℊℋℌℐℑℒℓ℘ℛℜℬℰℱℳℭℨ"; -for (let i = 0; i < narrow.length; i++) { - const ch = narrow.charAt(i); - defineSymbol(math, mathord, ch, ch); - defineSymbol(text, textord, ch, ch); -} - -// The next loop loads wide (surrogate pair) characters. -// We support some letters in the Unicode range U+1D400 to U+1D7FF, -// Mathematical Alphanumeric Symbols. -let wideChar = ""; -for (let i = 0; i < letters.length; i++) { - // The hex numbers in the next line are a surrogate pair. - // 0xD835 is the high surrogate for all letters in the range we support. - // 0xDC00 is the low surrogate for bold A. - wideChar = String.fromCharCode(0xd835, 0xdc00 + i); // A-Z a-z bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc34 + i); // A-Z a-z italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdc68 + i); // A-Z a-z bold italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd04 + i); // A-Z a-z Fractur - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdda0 + i); // A-Z a-z sans-serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xddd4 + i); // A-Z a-z sans bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde08 + i); // A-Z a-z sans italic - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xde70 + i); // A-Z a-z monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdd38 + i); // A-Z a-z double struck - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - const ch = letters.charAt(i); - wideChar = String.fromCharCode(0xd835, 0xdc9c + i); // A-Z a-z calligraphic - defineSymbol(math, mathord, ch, wideChar); - defineSymbol(text, textord, ch, wideChar); -} - -// Next, some wide character numerals -for (let i = 0; i < 10; i++) { - wideChar = String.fromCharCode(0xd835, 0xdfce + i); // 0-9 bold - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfe2 + i); // 0-9 sans serif - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdfec + i); // 0-9 bold sans - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); - - wideChar = String.fromCharCode(0xd835, 0xdff6 + i); // 0-9 monospace - defineSymbol(math, mathord, wideChar, wideChar); - defineSymbol(text, textord, wideChar, wideChar); -} - -/* - * Neither Firefox nor Chrome support hard line breaks or soft line breaks. - * (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs) - * So Temml has work-arounds for both hard and soft breaks. - * The work-arounds sadly do not work simultaneously. Any top-level hard - * break makes soft line breaks impossible. - * - * Hard breaks are simulated by creating a and putting each line in its own . - * - * To create soft line breaks, Temml avoids using the and tags. - * Then the top level of a element can be occupied by elements, and the browser - * will break after a if the expression extends beyond the container limit. - * - * We want the expression to render with soft line breaks after each top-level binary or - * relational operator, per TeXbook p. 173. So we gather the expression into s so that - * each ends in a binary or relational operator. - * - * Soft line breaks will not work in Chromium and Safari, only Firefox. - * - * Hopefully browsers will someday do their own linebreaking and we will be able to delete - * much of this module. - */ - -function setLineBreaks(expression, isDisplayMode, isAnnotated, color = undefined) { - if (color === undefined) { - // First, make one pass through the expression and split any color nodes. - const upperLimit = expression.length - 1; - for (let i = upperLimit; i >= 0; i--) { - const node = expression[i]; - if (node.type === "mstyle" && node.attributes.mathcolor) { - const color = node.attributes.mathcolor; - const fragment = setLineBreaks(node.children, isDisplayMode, isAnnotated, color); - if (!(fragment.type && fragment.type !== "mtable")) { - expression.splice(i, 1, ...fragment.children); - - } - } - } - } - - const tagName = color ? "mstyle" : "mrow"; - - const mtrs = []; - let mrows = []; - let block = []; - let canBeBIN = false; // The first node cannot be an infix binary operator. - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node.type && node.type === "mstyle" && node.attributes.mathcolor) { - // Start a new block. (Insert a soft linebreak.) - mrows.push(new mathMLTree.MathNode(tagName, block)); - // Insert the mstyle - mrows.push(node); - block = []; - continue - } - if (node.attributes && node.attributes.linebreak && - node.attributes.linebreak === "newline") { - // A hard line break. Create a for the current block. - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(new mathMLTree.MathNode(tagName, block)); - } - mrows.push(node); - block = []; - const mtd = new mathMLTree.MathNode("mtd", mrows); - mtrs.push(new mathMLTree.MathNode("mtr", [mtd])); - mrows = []; - continue - } - block.push(node); - if (node.type && node.type === "mo" && !isDisplayMode && !isAnnotated) { - // This may be a place for a soft line break. - if (canBeBIN && !node.attributes.form) { - // Check if the following node is a \nobreak text node, e.g. "~"" - const next = i < expression.length - 1 ? expression[i + 1] : null; - let glueIsFreeOfNobreak = true; - if ( - !( - next && - next.type === "mtext" && - next.attributes.linebreak && - next.attributes.linebreak === "nobreak" - ) - ) { - // We may need to start a new block. - // First, put any post-operator glue on same line as operator. - for (let j = i + 1; j < expression.length; j++) { - const nd = expression[j]; - if ( - nd.type && - nd.type === "mspace" && - !(nd.attributes.linebreak && nd.attributes.linebreak === "newline") - ) { - block.push(nd); - i += 1; - if ( - nd.attributes && - nd.attributes.linebreak && - nd.attributes.linebreak === "nobreak" - ) { - glueIsFreeOfNobreak = false; - } - } else { - break; - } - } - } - if (glueIsFreeOfNobreak) { - // Start a new block. (Insert a soft linebreak.) - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - block = []; - } - canBeBIN = false; - } - const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix"; - // Any operator that follows an open delimiter is unary. - canBeBIN = !(node.attributes.separator || isOpenDelimiter); - } else { - canBeBIN = true; - } - } - if (block.length > 0) { - const element = new mathMLTree.MathNode(tagName, block); - if (color) { element.setAttribute("mathcolor", color); } - mrows.push(element); - } - if (mtrs.length > 0) { - const mtd = new mathMLTree.MathNode("mtd", mrows); - const mtr = new mathMLTree.MathNode("mtr", [mtd]); - mtrs.push(mtr); - const mtable = new mathMLTree.MathNode("mtable", mtrs); - if (!isDisplayMode) { - mtable.setAttribute("columnalign", "left"); - mtable.setAttribute("rowspacing", "0em"); - } - return mtable - } - return mathMLTree.newDocumentFragment(mrows); -} - -/** - * This file converts a parse tree into a cooresponding MathML tree. The main - * entry point is the `buildMathML` function, which takes a parse tree from the - * parser. - */ - -/** - * Takes a symbol and converts it into a MathML text node after performing - * optional replacement from symbols.js. - */ -const makeText = function(text, mode, style) { - if ( - symbols[mode][text] && - symbols[mode][text].replace && - text.charCodeAt(0) !== 0xd835 && - !( - Object.prototype.hasOwnProperty.call(ligatures, text) && - style && - ((style.fontFamily && style.fontFamily.substr(4, 2) === "tt") || - (style.font && style.font.substr(4, 2) === "tt")) - ) - ) { - text = symbols[mode][text].replace; - } - - return new mathMLTree.TextNode(text); -}; - -/** - * Wrap the given array of nodes in an node if needed, i.e., - * unless the array has length 1. Always returns a single node. - */ -const makeRow = function(body) { - if (body.length === 1) { - return body[0]; - } else { - return new mathMLTree.MathNode("mrow", body); - } -}; - -/** - * Takes a list of nodes, builds them, and returns a list of the generated - * MathML nodes. Also combine consecutive outputs into a single - * tag. - */ -const buildExpression = function(expression, style, isOrdgroup) { - if (expression.length === 1) { - const group = buildGroup(expression[0], style); - if (isOrdgroup && group instanceof MathNode && group.type === "mo") { - // When TeX writers want to suppress spacing on an operator, - // they often put the operator by itself inside braces. - group.setAttribute("lspace", "0em"); - group.setAttribute("rspace", "0em"); - } - return [group]; - } - - const groups = []; - for (let i = 0; i < expression.length; i++) { - const group = buildGroup(expression[i], style); - groups.push(group); - } - return groups; -}; - -/** - * Equivalent to buildExpression, but wraps the elements in an - * if there's more than one. Returns a single node instead of an array. - */ -const buildExpressionRow = function(expression, style, isOrdgroup) { - return makeRow(buildExpression(expression, style, isOrdgroup)); -}; - -/** - * Takes a group from the parser and calls the appropriate groupBuilders function - * on it to produce a MathML node. - */ -const buildGroup = function(group, style) { - if (!group) { - return new mathMLTree.MathNode("mrow"); - } - - if (_mathmlGroupBuilders[group.type]) { - // Call the groupBuilders function - const result = _mathmlGroupBuilders[group.type](group, style); - return result; - } else { - throw new ParseError("Got group of unknown type: '" + group.type + "'"); - } -}; - - -const taggedExpression = (expression, tag, style, leqno, preventTagLap) => { - const glue = new mathMLTree.MathNode("mtd", []); - glue.setAttribute("style", "padding: 0;width: 50%;"); - tag = buildExpressionRow(tag[0].body, style); - tag.classes = ["tml-tag"]; - if (!preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - tag.setAttribute((leqno ? "rspace" : "lspace"), "-1width"); - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - - expression = new mathMLTree.MathNode("mtd", [expression]); - const rowArray = leqno - ? [tag, glue, expression, glue] - : [glue, expression, glue, tag]; - const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]); - const table = new mathMLTree.MathNode("mtable", [mtr]); - table.setAttribute("width", "100%"); - return table -}; - -/** - * Takes a full parse tree and settings and builds a MathML representation of - * it. - */ -function buildMathML(tree, texExpression, style, settings) { - // Strip off outer tag wrapper for processing below. - let tag = null; - if (tree.length === 1 && tree[0].type === "tag") { - tag = tree[0].tag; - tree = tree[0].body; - } - - const expression = buildExpression(tree, style); - - const n1 = expression.length === 0 ? null : expression[0]; - let wrapper = expression.length === 1 && tag === null && (n1 instanceof MathNode) - && !(n1.type === "mstyle" && n1.attributes.mathcolor) - ? expression[0] - : setLineBreaks(expression, settings.displayMode, settings.annotate); - - if (tag) { - wrapper = taggedExpression(wrapper, tag, style, settings.leqno, settings.preventTagLap); - } - - let semantics; - if (settings.annotate) { - // Build a TeX annotation of the source - const annotation = new mathMLTree.MathNode( - "annotation", [new mathMLTree.TextNode(texExpression)]); - annotation.setAttribute("encoding", "application/x-tex"); - semantics = new mathMLTree.MathNode("semantics", [wrapper, annotation]); - } - - const math = settings.annotate - ? new mathMLTree.MathNode("math", [semantics]) - : new mathMLTree.MathNode("math", [wrapper]); - - if (settings.xml) { - math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML"); - } - if (settings.displayMode) { - math.setAttribute("display", "block"); - } - return math; -} - -const mathmlBuilder = (group, style) => { - const accentNode = group.isStretchy - ? stretchy.mathMLnode(group.label) - : new mathMLTree.MathNode("mo", [makeText(group.label, group.mode)]); - - if (!group.isStretchy) { - accentNode.setAttribute("stretchy", "false"); - } - - const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"), - [buildGroup(group.base, style), accentNode] - ); - - node.setAttribute("accent", "true"); - return node; -}; - -const NON_STRETCHY_ACCENT_REGEX = new RegExp( - [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring" - ] - .map((accent) => `\\${accent}`) - .join("|") -); - -// Accents -defineFunction({ - type: "accent", - names: [ - "\\acute", - "\\grave", - "\\ddot", - "\\dddot", - "\\ddddot", - "\\tilde", - "\\bar", - "\\breve", - "\\check", - "\\hat", - "\\vec", - "\\dot", - "\\mathring", - "\\overparen", - "\\widecheck", - "\\widehat", - "\\wideparen", - "\\widetilde", - "\\overrightarrow", - "\\overleftarrow", - "\\Overrightarrow", - "\\overleftrightarrow", - "\\overgroup", - "\\overleftharpoon", - "\\overrightharpoon" - ], - props: { - numArgs: 1 - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - - const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName); - const isShifty = - !isStretchy || - context.funcName === "\\widehat" || - context.funcName === "\\widetilde" || - context.funcName === "\\widecheck"; - - return { - type: "accent", - mode: context.parser.mode, - label: context.funcName, - isStretchy: isStretchy, - isShifty: isShifty, - base: base - }; - }, - mathmlBuilder -}); - -// Text-mode accents -defineFunction({ - type: "accent", - names: ["\\'", "\\`", "\\^", "\\~", "\\=", "\\c", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"], - props: { - numArgs: 1, - allowedInText: true, - allowedInMath: true, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const base = normalizeArgument(args[0]); - const mode = context.parser.mode; - - if (mode === "math" && context.parser.settings.strict) { - // LaTeX only writes a warning. It doesn't stop. We'll issue the same warning. - // eslint-disable-next-line no-console - console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`); - } - - return { - type: "accent", - mode: mode, - label: context.funcName, - isStretchy: false, - isShifty: true, - base: base - }; - }, - mathmlBuilder -}); - -defineFunction({ - type: "accentUnder", - names: [ - "\\underleftarrow", - "\\underrightarrow", - "\\underleftrightarrow", - "\\undergroup", - "\\underparen", - "\\utilde" - ], - props: { - numArgs: 1 - }, - handler: ({ parser, funcName }, args) => { - const base = args[0]; - return { - type: "accentUnder", - mode: parser.mode, - label: funcName, - base: base - }; - }, - mathmlBuilder: (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - const node = new mathMLTree.MathNode("munder", [ - buildGroup(group.base, style), - accentNode - ]); - node.setAttribute("accentunder", "true"); - return node; - } -}); - -// Helper functions -const paddedNode = (group, width = "+0.6em") => { - const node = new mathMLTree.MathNode("mpadded", group ? [group] : []); - node.setAttribute("width", width); - node.setAttribute("lspace", "0.3em"); - return node; -}; - -const munderoverNode = (label, body, below, style, macros = {}) => { - const arrowNode = stretchy.mathMLnode(label, macros); - const minWidth = label.charAt(1) === "x" - ? "1.75em" // mathtools extensible arrows - : label.slice(2, 4) === "cd" - ? "3.0em" // cd package arrows - : "2.0em"; // mhchem arrows - arrowNode.setAttribute("minsize", minWidth); - // minsize attribute doesn't work in Firefox. - // https://bugzilla.mozilla.org/show_bug.cgi?id=320303 - const labelStyle = style.incrementLevel(); - - const upperNode = (body && body.body && - // \hphantom visible content - (body.body.body || body.body.length > 0)) - ? paddedNode(buildGroup(body, labelStyle)) - // Since Firefox does not recognize minsize set on the arrow, - // create an upper node w/correct width. - : paddedNode(null, minWidth); - const lowerNode = (below && below.body && - (below.body.body || below.body.length > 0)) - ? paddedNode(buildGroup(below, labelStyle)) - : paddedNode(null, minWidth); - const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]); - return node -}; - -// Stretchy arrows with an optional argument -defineFunction({ - type: "xArrow", - names: [ - "\\xleftarrow", - "\\xrightarrow", - "\\xLeftarrow", - "\\xRightarrow", - "\\xleftrightarrow", - "\\xLeftrightarrow", - "\\xhookleftarrow", - "\\xhookrightarrow", - "\\xmapsto", - "\\xrightharpoondown", - "\\xrightharpoonup", - "\\xleftharpoondown", - "\\xleftharpoonup", - "\\xlongequal", - "\\xtwoheadrightarrow", - "\\xtwoheadleftarrow", - // The next 7 functions are here only to support mhchem - "\\yields", - "\\yieldsLeft", - "\\mesomerism", - "\\longrightharpoonup", - "\\longleftharpoondown", - "\\equilibriumRight", - "\\equilibriumLeft", - // The next 3 functions are here only to support the {CD} environment. - "\\\\cdrightarrow", - "\\\\cdleftarrow", - "\\\\cdlongequal" - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - return { - type: "xArrow", - mode: parser.mode, - label: funcName, - body: args[0], - below: optArgs[0], - macros: parser.gullet.macros // Contains SVG paths for mhchem equilibrium arrows. - }; - }, - mathmlBuilder(group, style) { - return munderoverNode(group.label, group.body, group.below, style, group.macros) - } -}); - -const arrowComponent = { - "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"], - "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"], - "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"], - "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"], - "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"] -}; - -// Browser are not good at stretching stacked arrows such as ⇄. -// So we stack a pair of single arrows. -defineFunction({ - type: "stackedArrow", - names: [ - "\\xtofrom", // expfeil - "\\xleftrightharpoons", // mathtools - "\\xrightleftharpoons", // mathtools - "\\yieldsLeftRight", // mhchem - "\\equilibrium" // mhchem - ], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser, funcName }, args, optArgs) { - const lowerArrowBody = args[0] - ? { - type: "hphantom", - mode: parser.mode, - body: args[0] - } - : null; - const upperArrowBelow = optArgs[0] - ? { - type: "hphantom", - mode: parser.mode, - body: optArgs[0] - } - : null; - return { - type: "stackedArrow", - mode: parser.mode, - label: funcName, - body: args[0], - upperArrowBelow, - lowerArrowBody, - below: optArgs[0] - }; - }, - mathmlBuilder(group, style) { - const topLabel = arrowComponent[group.label][0]; - const botLabel = arrowComponent[group.label][1]; - const topArrow = munderoverNode(topLabel, group.body, group.upperArrowBelow, style); - const botArrow = munderoverNode(botLabel, group.lowerArrowBody, group.below, style); - - const topSpace = new mathMLTree.MathNode("mspace"); - topSpace.setAttribute("width", "0.2778em"); - const botSpace = new mathMLTree.MathNode("mspace"); - botSpace.setAttribute("width", "-0.2778em"); - - const raiseNode = new mathMLTree.MathNode("mpadded", [topSpace, topArrow]); - raiseNode.setAttribute("voffset", "0.3em"); - raiseNode.setAttribute("height", "+0.3em"); - raiseNode.setAttribute("depth", "-0.3em"); - raiseNode.setAttribute("width", "0em"); - - const botRow = new mathMLTree.MathNode("mrow", [botSpace, botArrow]); - - const wrapper = new mathMLTree.MathNode("mpadded", [raiseNode, botRow]); - wrapper.setAttribute("voffset", "-0.18em"); - wrapper.setAttribute("height", "-0.18em"); - wrapper.setAttribute("depth", "+0.18em"); - wrapper.setAttribute("lspace", "0em"); - wrapper.setAttribute("rspace", "0em"); - return wrapper - } -}); - -defineFunction({ - type: "cancelto", - names: ["\\cancelto"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "cancelto", - mode: parser.mode, - value: args[0], - expression: args[1] - }; - }, - mathmlBuilder(group, style) { - const value = new mathMLTree.MathNode( - "mpadded", - [buildGroup(group.value, style)] - ); - value.setAttribute("depth", `-0.1em`); - value.setAttribute("height", `+0.1em`); - value.setAttribute("voffset", `0.1em`); - - const expression = new mathMLTree.MathNode( - "menclose", - [buildGroup(group.expression, style)] - ); - expression.setAttribute("notation", `updiagonalarrow`); - - return new mathMLTree.MathNode("msup", [expression, value]) - } -}); - -/** - * Asserts that the node is of the given type and returns it with stricter - * typing. Throws if the node's type does not match. - */ -function assertNodeType(node, type) { - if (!node || node.type !== type) { - throw new Error( - `Expected node of type ${type}, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return node; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function assertSymbolNodeType(node) { - const typedNode = checkSymbolNodeType(node); - if (!typedNode) { - throw new Error( - `Expected node of symbol group type, but got ` + - (node ? `node of type ${node.type}` : String(node)) - ); - } - return typedNode; -} - -/** - * Returns the node more strictly typed iff it is of the given type. Otherwise, - * returns null. - */ -function checkSymbolNodeType(node) { - if (node && (node.type === "atom" || - Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) { - return node; - } - return null; -} - -const cdArrowFunctionName = { - ">": "\\\\cdrightarrow", - "<": "\\\\cdleftarrow", - "=": "\\\\cdlongequal", - A: "\\uparrow", - V: "\\downarrow", - "|": "\\Vert", - ".": "no arrow" -}; - -const newCell = () => { - // Create an empty cell, to be filled below with parse nodes. - return { type: "styling", body: [], mode: "math", scriptLevel: "display" }; -}; - -const isStartOfArrow = (node) => { - return node.type === "textord" && node.text === "@"; -}; - -const isLabelEnd = (node, endChar) => { - return (node.type === "mathord" || node.type === "atom") && node.text === endChar; -}; - -function cdArrow(arrowChar, labels, parser) { - // Return a parse tree of an arrow and its labels. - // This acts in a way similar to a macro expansion. - const funcName = cdArrowFunctionName[arrowChar]; - switch (funcName) { - case "\\\\cdrightarrow": - case "\\\\cdleftarrow": - return parser.callFunction(funcName, [labels[0]], [labels[1]]); - case "\\uparrow": - case "\\downarrow": { - const leftLabel = parser.callFunction("\\\\cdleft", [labels[0]], []); - const bareArrow = { - type: "atom", - text: funcName, - mode: "math", - family: "rel" - }; - const sizedArrow = parser.callFunction("\\Big", [bareArrow], []); - const rightLabel = parser.callFunction("\\\\cdright", [labels[1]], []); - const arrowGroup = { - type: "ordgroup", - mode: "math", - body: [leftLabel, sizedArrow, rightLabel] - }; - return parser.callFunction("\\\\cdparent", [arrowGroup], []); - } - case "\\\\cdlongequal": - return parser.callFunction("\\\\cdlongequal", [], []); - case "\\Vert": { - const arrow = { type: "textord", text: "\\Vert", mode: "math" }; - return parser.callFunction("\\Big", [arrow], []); - } - default: - return { type: "textord", text: " ", mode: "math" }; - } -} - -function parseCD(parser) { - // Get the array's parse nodes with \\ temporarily mapped to \cr. - const parsedRows = []; - parser.gullet.beginGroup(); - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - parser.gullet.beginGroup(); - while (true) { // eslint-disable-line no-constant-condition - // Get the parse nodes for the next row. - parsedRows.push(parser.parseExpression(false, "\\\\")); - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - const next = parser.fetch().text; - if (next === "&" || next === "\\\\") { - parser.consume(); - } else if (next === "\\end") { - if (parsedRows[parsedRows.length - 1].length === 0) { - parsedRows.pop(); // final row ended in \\ - } - break; - } else { - throw new ParseError("Expected \\\\ or \\cr or \\end", parser.nextToken); - } - } - - let row = []; - const body = [row]; - - // Loop thru the parse nodes. Collect them into cells and arrows. - for (let i = 0; i < parsedRows.length; i++) { - // Start a new row. - const rowNodes = parsedRows[i]; - // Create the first cell. - let cell = newCell(); - - for (let j = 0; j < rowNodes.length; j++) { - if (!isStartOfArrow(rowNodes[j])) { - // If a parseNode is not an arrow, it goes into a cell. - cell.body.push(rowNodes[j]); - } else { - // Parse node j is an "@", the start of an arrow. - // Before starting on the arrow, push the cell into `row`. - row.push(cell); - - // Now collect parseNodes into an arrow. - // The character after "@" defines the arrow type. - j += 1; - const arrowChar = assertSymbolNodeType(rowNodes[j]).text; - - // Create two empty label nodes. We may or may not use them. - const labels = new Array(2); - labels[0] = { type: "ordgroup", mode: "math", body: [] }; - labels[1] = { type: "ordgroup", mode: "math", body: [] }; - - // Process the arrow. - if ("=|.".indexOf(arrowChar) > -1) ; else if ("<>AV".indexOf(arrowChar) > -1) { - // Four arrows, `@>>>`, `@<<<`, `@AAA`, and `@VVV`, each take - // two optional labels. E.g. the right-point arrow syntax is - // really: @>{optional label}>{optional label}> - // Collect parseNodes into labels. - for (let labelNum = 0; labelNum < 2; labelNum++) { - let inLabel = true; - for (let k = j + 1; k < rowNodes.length; k++) { - if (isLabelEnd(rowNodes[k], arrowChar)) { - inLabel = false; - j = k; - break; - } - if (isStartOfArrow(rowNodes[k])) { - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[k] - ); - } - - labels[labelNum].body.push(rowNodes[k]); - } - if (inLabel) { - // isLabelEnd never returned a true. - throw new ParseError( - "Missing a " + arrowChar + " character to complete a CD arrow.", - rowNodes[j] - ); - } - } - } else { - throw new ParseError(`Expected one of "<>AV=|." after @.`); - } - - // Now join the arrow to its labels. - const arrow = cdArrow(arrowChar, labels, parser); - - // Wrap the arrow in a styling node - row.push(arrow); - // In CD's syntax, cells are implicit. That is, everything that - // is not an arrow gets collected into a cell. So create an empty - // cell now. It will collect upcoming parseNodes. - cell = newCell(); - } - } - if (i % 2 === 0) { - // Even-numbered rows consist of: cell, arrow, cell, arrow, ... cell - // The last cell is not yet pushed into `row`, so: - row.push(cell); - } else { - // Odd-numbered rows consist of: vert arrow, empty cell, ... vert arrow - // Remove the empty cell that was placed at the beginning of `row`. - row.shift(); - } - row = []; - body.push(row); - } - - // End row group - parser.gullet.endGroup(); - // End array group defining \\ - parser.gullet.endGroup(); - - // define column separation. - const cols = new Array(body[0].length).fill({ - type: "align", - align: "c" - }); - - return { - type: "array", - mode: "math", - body, - arraystretch: 1, - addJot: true, - rowGaps: [null], - cols, - colSeparationType: "CD", - hLinesBeforeRow: new Array(body.length + 1).fill([]) - }; -} - -// The functions below are not available for general use. -// They are here only for internal use by the {CD} environment in placing labels -// next to vertical arrows. - -// We don't need any such functions for horizontal arrows because we can reuse -// the functionality that already exists for extensible arrows. - -defineFunction({ - type: "cdlabel", - names: ["\\\\cdleft", "\\\\cdright"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "cdlabel", - mode: parser.mode, - side: funcName.slice(4), - label: args[0] - }; - }, - mathmlBuilder(group, style) { - let label = new mathMLTree.MathNode("mrow", [buildGroup(group.label, style)]); - label = new mathMLTree.MathNode("mpadded", [label]); - label.setAttribute("width", "0"); - if (group.side === "left") { - label.setAttribute("lspace", "-1width"); - } - // We have to guess at vertical alignment. We know the arrow is 1.8em tall, - // But we don't know the height or depth of the label. - label.setAttribute("voffset", "0.7em"); - label = new mathMLTree.MathNode("mstyle", [label]); - label.setAttribute("displaystyle", "false"); - label.setAttribute("scriptlevel", "1"); - return label; - } -}); - -defineFunction({ - type: "cdlabelparent", - names: ["\\\\cdparent"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - return { - type: "cdlabelparent", - mode: parser.mode, - fragment: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow", [buildGroup(group.fragment, style)]); - } -}); - -// \@char is an internal function that takes a grouped decimal argument like -// {123} and converts into symbol with code 123. It is used by the *macro* -// \char defined in macros.js. -defineFunction({ - type: "textord", - names: ["\\@char"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - const arg = assertNodeType(args[0], "ordgroup"); - const group = arg.body; - let number = ""; - for (let i = 0; i < group.length; i++) { - const node = assertNodeType(group[i], "textord"); - number += node.text; - } - const code = parseInt(number); - if (isNaN(code)) { - throw new ParseError(`\\@char has non-numeric argument ${number}`) - } - return { - type: "textord", - mode: parser.mode, - text: String.fromCodePoint(code) - } - } -}); - -/* In LaTeX, \colon is defined as: - * \renewcommand{\colon}{\nobreak\mskip2mu\mathpunct{}\nonscript - * \mkern-\thinmuskip{:}\mskip6muplus1mu\relax} - * - * Doing that with a Temml macro produces semantically poor MathML. Do it more directly. - */ - -defineFunction({ - type: "colonFunction", - names: ["\\colon"], - props: { numArgs: 0 }, - handler({ parser }) { return { type: "colonFunction", mode: parser.mode } }, - mathmlBuilder(group, style) { - const mo = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode(":")]); - // lspace depends on the script level. - mo.attributes.lspace = (style.level < 2 ? "0.05556em" : "0.1111em"); - mo.attributes.rspace = "0.3333em"; // 6mu - return mo - } -}); - -defineFunction({ - type: "colonequal", - names: [":"], - props: { numArgs: 0 }, - handler({ parser }, args) { - if (parser.fetch().text === "=") { - // Special case for := - parser.consume(); - return { type: "colonequal", mode: parser.mode } - } - return { type: "atom", family: "rel", text: ":", mode: parser.mode } - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u2254")]) - } -}); - -// Helpers -const htmlRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6})$/i; -const htmlOrNameRegEx = /^(#[a-f0-9]{3}|#?[a-f0-9]{6}|[a-z]+)$/i; -const RGBregEx = /^ *\d{1,3} *(?:, *\d{1,3} *){2}$/; -const rgbRegEx = /^ *[10](?:\.\d*)? *(?:, *[10](?:\.\d*)? *){2}$/; -const xcolorHtmlRegEx = /^[a-f0-9]{6}$/i; -const toHex = num => { - let str = num.toString(16); - if (str.length === 1) { str = "0" + str; } - return str -}; - -// Colors from Tables 4.1 and 4.2 of the xcolor package. -// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx. -// Table 4.2 (Capitalizzed) values were sampled, because Chroma contains a unreliable -// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274. -const xcolors = JSON.parse(`{ - "Apricot": "#ffb484", - "Aquamarine": "#08b4bc", - "Bittersweet": "#c84c14", - "blue": "#0000FF", - "Blue": "#303494", - "BlueGreen": "#08b4bc", - "BlueViolet": "#503c94", - "BrickRed": "#b8341c", - "brown": "#BF804", - "Brown": "#802404", - "BurntOrange": "#f8941c", - "CadetBlue": "#78749c", - "CarnationPink": "#f884b4", - "Cerulean": "#08a4e4", - "CornflowerBlue": "#40ace4", - "cyan": "#00FFF", - "Cyan": "#08acec", - "Dandelion": "#ffbc44", - "darkgray": "#404040", - "DarkOrchid": "#a8548c", - "Emerald": "#08ac9c", - "ForestGreen": "#089c54", - "Fuchsia": "#90348c", - "Goldenrod": "#ffdc44", - "gray": "#80808", - "Gray": "#98949c", - "green": "#00FF0", - "Green": "#08a44c", - "GreenYellow": "#e0e474", - "JungleGreen": "#08ac9c", - "Lavender": "#f89cc4", - "lightgray": "#BFBFB", - "lime": "#BFFF00", - "LimeGreen": "#90c43c", - "magenta": "#FF00F", - "Magenta": "#f0048c", - "Mahogany": "#b0341c", - "Maroon": "#b03434", - "Melon": "#f89c7c", - "MidnightBlue": "#086494", - "Mulberry": "#b03c94", - "NavyBlue": "#086cbc", - "olive": "#7F7F00", - "OliveGreen": "#407c34", - "orange": "#FF800", - "Orange": "#f8843c", - "OrangeRed": "#f0145c", - "Orchid": "#b074ac", - "Peach": "#f8945c", - "Periwinkle": "#8074bc", - "PineGreen": "#088c74", - "pink": "#ff7f7f", - "Plum": "#98248c", - "ProcessBlue": "#08b4ec", - "purple": "#BF0040", - "Purple": "#a0449c", - "RawSienna": "#983c04", - "red": "#ff0000", - "Red": "#f01c24", - "RedOrange": "#f86434", - "RedViolet": "#a0246c", - "Rhodamine": "#f0549c", - "Royallue": "#0874bc", - "RoyalPurple": "#683c9c", - "RubineRed": "#f0047c", - "Salmon": "#f8948c", - "SeaGreen": "#30bc9c", - "Sepia": "#701404", - "SkyBlue": "#48c4dc", - "SpringGreen": "#c8dc64", - "Tan": "#e09c74", - "teal": "#007F7F", - "TealBlue": "#08acb4", - "Thistle": "#d884b4", - "Turquoise": "#08b4cc", - "violet": "#800080", - "Violet": "#60449c", - "VioletRed": "#f054a4", - "WildStrawberry": "#f0246c", - "yellow": "#FFFF00", - "Yellow": "#fff404", - "YellowGreen": "#98cc6c", - "YellowOrange": "#ffa41c" -}`); - -const colorFromSpec = (model, spec) => { - let color = ""; - if (model === "HTML") { - if (!htmlRegEx.test(spec)) { - throw new ParseError("Invalid HTML input.") - } - color = spec; - } else if (model === "RGB") { - if (!RGBregEx.test(spec)) { - throw new ParseError("Invalid RGB input.") - } - spec.split(",").map(e => { color += toHex(Number(e.trim())); }); - } else { - if (!rgbRegEx.test(spec)) { - throw new ParseError("Invalid rbg input.") - } - spec.split(",").map(e => { - const num = Number(e.trim()); - if (num > 1) { throw new ParseError("Color rgb input must be < 1.") } - color += toHex((num * 255)); - }); - } - if (color.charAt(0) !== "#") { color = "#" + color; } - return color -}; - -const validateColor = (color, macros) => { - const macroName = `\\\\color@${color}`; // from \defineColor. - const match = htmlOrNameRegEx.exec(color); - if (!match) { throw new ParseError("Invalid color: '" + color + "'") } - // We allow a 6-digit HTML color spec without a leading "#". - // This follows the xcolor package's HTML color model. - // Predefined color names are all missed by this RegEx pattern. - if (xcolorHtmlRegEx.test(color)) { - return "#" + color - } else if (color.charAt(0) === "#") { - return color - } else if (macros.has(macroName)) { - color = macros.get(macroName).tokens[0].text; - } else if (xcolors[color]) { - color = xcolors[color]; - } - return color -}; - -const mathmlBuilder$1 = (group, style) => { - const inner = buildExpression(group.body, style.withColor(group.color)); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("mathcolor", group.color); - // Wrap w/. We get better operator spacing that way. - return new mathMLTree.MathNode("mrow", [node]) -}; - -defineFunction({ - type: "color", - names: ["\\textcolor"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "original"] - }, - handler({ parser }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - const body = args[1]; - return { - type: "color", - mode: parser.mode, - color, - body: ordargument(body) - } - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineFunction({ - type: "color", - names: ["\\color"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw"] - }, - handler({ parser, breakOnTokenText }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - - // Set macro \current@color in current namespace to store the current - // color, mimicking the behavior of color.sty. - // This is currently used just to correctly color a \right - // that follows a \color command. - parser.gullet.macros.set("\\current@color", color); - - // Parse out the implicit body that should be colored. - // Since \color nodes should not be nested, break on \color. - const body = parser.parseExpression(true, "\\color"); - - return { - type: "color", - mode: parser.mode, - color, - body - } - }, - mathmlBuilder: mathmlBuilder$1 -}); - -defineFunction({ - type: "color", - names: ["\\definecolor"], - props: { - numArgs: 3, - allowedInText: true, - argTypes: ["raw", "raw", "raw"] - }, - handler({ parser }, args) { - const name = assertNodeType(args[0], "raw").string; - if (!/^[A-Za-z]+$/.test(name)) { - throw new ParseError("Color name must be latin letters.") - } - const model = assertNodeType(args[1], "raw").string; - if (!["HTML", "RGB", "rgb"].includes(model)) { - throw new ParseError("Color model must be HTML, RGB, or rgb.") - } - const spec = assertNodeType(args[2], "raw").string; - const color = colorFromSpec(model, spec); - parser.gullet.macros.set(`\\\\color@${name}`, { tokens: [{ text: color }], numArgs: 0 }); - return { type: "internal", mode: parser.mode } - } - // No mathmlBuilder. The point of \definecolor is to set a macro. -}); - -/** - * This file does conversion between units. In particular, it provides - * calculateSize to convert other units into CSS units. - */ - -const ptPerUnit = { - // Convert to CSS (Postscipt) points, not TeX points - // https://en.wikibooks.org/wiki/LaTeX/Lengths and - // https://tex.stackexchange.com/a/8263 - pt: 800 / 803, // convert TeX point to CSS (Postscript) point - pc: (12 * 800) / 803, // pica - dd: ((1238 / 1157) * 800) / 803, // didot - cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot) - nd: ((685 / 642) * 800) / 803, // new didot - nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot) - sp: ((1 / 65536) * 800) / 803 // scaled point (TeX's internal smallest unit) -}; - -/** - * Determine whether the specified unit (either a string defining the unit - * or a "size" parse node containing a unit field) is valid. - */ -const validUnits = [ - "em", - "ex", - "mu", - "pt", - "mm", - "cm", - "in", - "px", - "bp", - "pc", - "dd", - "cc", - "nd", - "nc", - "sp" -]; - -const validUnit = function(unit) { - if (typeof unit !== "string") { - unit = unit.unit; - } - return validUnits.indexOf(unit) > -1 -}; - -const emScale = styleLevel => { - const scriptLevel = Math.max(styleLevel - 1, 0); - return [1, 0.7, 0.5][scriptLevel] -}; - -/* - * Convert a "size" parse node (with numeric "number" and string "unit" fields, - * as parsed by functions.js argType "size") into a CSS value. - */ -const calculateSize = function(sizeValue, style) { - const number = sizeValue.number; - const unit = sizeValue.unit; - switch (unit) { - case "mm": - case "cm": - case "in": - case "px": - return { number, unit }; // absolute CSS units. - case "em": - case "ex": - // In TeX, em and ex do not change size in \scriptstyle. - return { number: utils.round(number / emScale(style.level)), unit }; - case "bp": - return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch). - case "pt": - case "pc": - case "dd": - case "cc": - case "nd": - case "nc": - case "sp": - return { number: utils.round(number * ptPerUnit[unit]), unit: "pt" } - case "mu": { - return { number: utils.round(number / 18), unit: "em" } - } - default: - throw new ParseError("Invalid unit: '" + unit + "'") - } -}; - -// Row breaks within tabular environments, and line breaks at top level - -// \DeclareRobustCommand\\{...\@xnewline} -defineFunction({ - type: "cr", - names: ["\\\\"], - props: { - numArgs: 0, - numOptionalArgs: 1, - argTypes: ["size"], - allowedInText: true - }, - - handler({ parser }, args, optArgs) { - const size = optArgs[0]; - if (parser.settings.displayMode && parser.settings.strict === "warn") { - parser.settings.reportNonstrict( - "newLineInDisplayMode", - "In LaTeX, \\\\ or \\newline " + "does nothing in display mode" - ); - } - const newLine = !parser.settings.displayMode || parser.settings.strict !== true; - return { - type: "cr", - mode: parser.mode, - newLine, - size: size && assertNodeType(size, "size").value - } - }, - - // The following builder is called only at the top level, - // not within tabular/array environments. - - mathmlBuilder(group, style) { - // MathML 3.0 calls for newline to occur in an or an . - // Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.linebreaking - const node = new mathMLTree.MathNode("mo"); - if (group.newLine) { - node.setAttribute("linebreak", "newline"); - if (group.size) { - const size = calculateSize(group.size, style); - node.setAttribute("height", size.number + size.unit); - } - } - return node - } -}); - -const checkControlSequence = (tok) => { - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - return name; -}; - -const getRHS = (parser) => { - let tok = parser.gullet.popToken(); - if (tok.text === "=") { - // consume optional equals - tok = parser.gullet.popToken(); - if (tok.text === " ") { - // consume one optional space - tok = parser.gullet.popToken(); - } - } - return tok; -}; - -const letCommand = (parser, name, tok) => { - let macro = parser.gullet.macros.get(tok.text); - if (macro == null) { - // don't expand it later even if a macro with the same name is defined - // e.g., \let\foo=\frac \def\frac{\relax} \frac12 - tok.noexpand = true; - macro = { - tokens: [tok], - numArgs: 0, - // reproduce the same behavior in expansion - unexpandable: !parser.gullet.isExpandable(tok.text) - }; - } - parser.gullet.macros.set(name, macro); -}; - -// Basic support for macro definitions: \def -// -> -// -> -defineFunction({ - type: "internal", - names: ["\\def", "\\edef"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let tok = parser.gullet.popToken(); - const name = tok.text; - if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) { - throw new ParseError("Expected a control sequence", tok); - } - - let numArgs = 0; - let insert; - const delimiters = [[]]; - // contains no braces - while (parser.gullet.future().text !== "{") { - tok = parser.gullet.popToken(); - if (tok.text === "#") { - // If the very last character of the is #, so that - // this # is immediately followed by {, TeX will behave as if the { - // had been inserted at the right end of both the parameter text - // and the replacement text. - if (parser.gullet.future().text === "{") { - insert = parser.gullet.future(); - delimiters[numArgs].push("{"); - break; - } - - // A parameter, the first appearance of # must be followed by 1, - // the next by 2, and so on; up to nine #’s are allowed - tok = parser.gullet.popToken(); - if (!/^[1-9]$/.test(tok.text)) { - throw new ParseError(`Invalid argument number "${tok.text}"`); - } - if (parseInt(tok.text) !== numArgs + 1) { - throw new ParseError(`Argument number "${tok.text}" out of order`); - } - numArgs++; - delimiters.push([]); - } else if (tok.text === "EOF") { - throw new ParseError("Expected a macro definition"); - } else { - delimiters[numArgs].push(tok.text); - } - } - // replacement text, enclosed in '{' and '}' and properly nested - let { tokens } = parser.gullet.consumeArg(); - if (insert) { - tokens.unshift(insert); - } - - if (funcName === "\\edef") { - tokens = parser.gullet.expandTokens(tokens); - tokens.reverse(); // to fit in with stack order - } - // Final arg is the expansion of the macro - parser.gullet.macros.set(name, { tokens, numArgs, delimiters } - ); - return { type: "internal", mode: parser.mode }; - } -}); - -// -> -// -> \futurelet -// | \let -// -> |= -defineFunction({ - type: "internal", - names: ["\\let"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.consumeSpaces(); - const tok = getRHS(parser); - letCommand(parser, name, tok); - return { type: "internal", mode: parser.mode }; - } -}); - -// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf -defineFunction({ - type: "internal", - names: ["\\futurelet"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - const name = checkControlSequence(parser.gullet.popToken()); - const middle = parser.gullet.popToken(); - const tok = parser.gullet.popToken(); - letCommand(parser, name, tok); - parser.gullet.pushToken(tok); - parser.gullet.pushToken(middle); - return { type: "internal", mode: parser.mode }; - } -}); - -defineFunction({ - type: "internal", - names: ["\\newcommand", "\\renewcommand", "\\providecommand"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ parser, funcName }) { - let name = ""; - const tok = parser.gullet.popToken(); - if (tok.text === "{") { - name = checkControlSequence(parser.gullet.popToken()); - parser.gullet.popToken(); - } else { - name = checkControlSequence(tok); - } - - const exists = parser.gullet.isDefined(name); - if (exists && funcName === "\\newcommand") { - throw new ParseError( - `\\newcommand{${name}} attempting to redefine ${name}; use \\renewcommand` - ); - } - if (!exists && funcName === "\\renewcommand") { - throw new ParseError( - `\\renewcommand{${name}} when command ${name} does not yet exist; use \\newcommand` - ); - } - - let numArgs = 0; - if (parser.gullet.future().text === "[") { - let tok = parser.gullet.popToken(); - tok = parser.gullet.popToken(); - if (!/^[0-9]$/.test(tok.text)) { - throw new ParseError(`Invalid number of arguments: "${tok.text}"`); - } - numArgs = parseInt(tok.text); - tok = parser.gullet.popToken(); - if (tok.text !== "]") { - throw new ParseError(`Invalid argument "${tok.text}"`); - } - } - - // replacement text, enclosed in '{' and '}' and properly nested - const { tokens } = parser.gullet.consumeArg(); - - parser.gullet.macros.set(name, { tokens, numArgs }); - - return { type: "internal", mode: parser.mode }; - - } -}); - -// Extra data needed for the delimiter handler down below -const delimiterSizes = { - "\\bigl": { mclass: "mopen", size: 1 }, - "\\Bigl": { mclass: "mopen", size: 2 }, - "\\biggl": { mclass: "mopen", size: 3 }, - "\\Biggl": { mclass: "mopen", size: 4 }, - "\\bigr": { mclass: "mclose", size: 1 }, - "\\Bigr": { mclass: "mclose", size: 2 }, - "\\biggr": { mclass: "mclose", size: 3 }, - "\\Biggr": { mclass: "mclose", size: 4 }, - "\\bigm": { mclass: "mrel", size: 1 }, - "\\Bigm": { mclass: "mrel", size: 2 }, - "\\biggm": { mclass: "mrel", size: 3 }, - "\\Biggm": { mclass: "mrel", size: 4 }, - "\\big": { mclass: "mord", size: 1 }, - "\\Big": { mclass: "mord", size: 2 }, - "\\bigg": { mclass: "mord", size: 3 }, - "\\Bigg": { mclass: "mord", size: 4 } -}; - -const delimiters = [ - "(", - "\\lparen", - ")", - "\\rparen", - "[", - "\\lbrack", - "]", - "\\rbrack", - "\\{", - "\\lbrace", - "\\}", - "\\rbrace", - "\\lfloor", - "\\rfloor", - "\u230a", - "\u230b", - "\\lceil", - "\\rceil", - "\u2308", - "\u2309", - "<", - ">", - "\\langle", - "\u27e8", - "\\rangle", - "\u27e9", - "\\lt", - "\\gt", - "\\lvert", - "\\rvert", - "\\lVert", - "\\rVert", - "\\lgroup", - "\\rgroup", - "\u27ee", - "\u27ef", - "\\lmoustache", - "\\rmoustache", - "\u23b0", - "\u23b1", - "\\llbracket", - "\\rrbracket", - "\u27e6", - "\u27e6", - "\\lBrace", - "\\rBrace", - "\u2983", - "\u2984", - "/", - "\\backslash", - "|", - "\\vert", - "\\|", - "\\Vert", - "\\uparrow", - "\\Uparrow", - "\\downarrow", - "\\Downarrow", - "\\updownarrow", - "\\Updownarrow", - "." -]; - -// Metrics of the different sizes. Found by looking at TeX's output of -// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$ -// Used to create stacked delimiters of appropriate sizes in makeSizedDelim. -const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0]; - -// Delimiter functions -function checkDelimiter(delim, context) { - if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") { - // Recover "/" from the zero spacing group. (See macros.js) - delim = { type: "textord", text: "/", mode: "math" }; - } - const symDelim = checkSymbolNodeType(delim); - if (symDelim && utils.contains(delimiters, symDelim.text)) { - // If a character is not in the MathML operator dictionary, it will not stretch. - // Replace such characters w/characters that will stretch. - if (utils.contains(["<", "\\lt"], symDelim.text)) { symDelim.text = "⟨"; } - if (utils.contains([">", "\\gt"], symDelim.text)) { symDelim.text = "⟩"; } - if (symDelim.text === "/") { symDelim.text = "\u2215"; } - if (symDelim.text === "\\backslash") { symDelim.text = "\u2216"; } - return symDelim; - } else if (symDelim) { - throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim); - } else { - throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim); - } -} - -defineFunction({ - type: "delimsizing", - names: [ - "\\bigl", - "\\Bigl", - "\\biggl", - "\\Biggl", - "\\bigr", - "\\Bigr", - "\\biggr", - "\\Biggr", - "\\bigm", - "\\Bigm", - "\\biggm", - "\\Biggm", - "\\big", - "\\Big", - "\\bigg", - "\\Bigg" - ], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - return { - type: "delimsizing", - mode: context.parser.mode, - size: delimiterSizes[context.funcName].size, - mclass: delimiterSizes[context.funcName].mclass, - delim: delim.text - }; - }, - mathmlBuilder: (group) => { - const children = []; - - if (group.delim === ".") { group.delim = ""; } - children.push(makeText(group.delim, group.mode)); - - const node = new mathMLTree.MathNode("mo", children); - - if (group.mclass === "mopen" || group.mclass === "mclose") { - // Only some of the delimsizing functions act as fences, and they - // return "mopen" or "mclose" mclass. - node.setAttribute("fence", "true"); - } else { - // Explicitly disable fencing if it's not a fence, to override the - // defaults. - node.setAttribute("fence", "false"); - } - if (group.delim === "\u2216") { - // \backslash is not in the operator dictionary, - // so we have to explicitly set stretchy to true. - node.setAttribute("stretchy", "true"); - } - - node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox. - node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em"); - node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em"); - - return node; - } -}); - -function assertParsed(group) { - if (!group.body) { - throw new Error("Bug: The leftright ParseNode wasn't fully parsed."); - } -} - -defineFunction({ - type: "leftright-right", - names: ["\\right"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - // \left case below triggers parsing of \right in - // `const right = parser.parseFunction();` - // uses this return value. - const color = context.parser.gullet.macros.get("\\current@color"); - if (color && typeof color !== "string") { - throw new ParseError("\\current@color set to non-string in \\right"); - } - return { - type: "leftright-right", - mode: context.parser.mode, - delim: checkDelimiter(args[0], context).text, - color // undefined if not set via \color - }; - } -}); - -defineFunction({ - type: "leftright", - names: ["\\left"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - - const parser = context.parser; - // Parse out the implicit body - ++parser.leftrightDepth; - // parseExpression stops before '\\right' - const body = parser.parseExpression(false); - --parser.leftrightDepth; - // Check the next token - parser.expect("\\right", false); - const right = assertNodeType(parser.parseFunction(), "leftright-right"); - return { - type: "leftright", - mode: parser.mode, - body, - left: delim.text, - right: right.delim, - rightColor: right.color - }; - }, - mathmlBuilder: (group, style) => { - assertParsed(group); - const inner = buildExpression(group.body, style); - - if (group.left === ".") { group.left = ""; } - const leftNode = new mathMLTree.MathNode("mo", [makeText(group.left, group.mode)]); - leftNode.setAttribute("fence", "true"); - leftNode.setAttribute("form", "prefix"); - if (group.left === "\u2216") { leftNode.setAttribute("stretchy", "true"); } - inner.unshift(leftNode); - - if (group.right === ".") { group.right = ""; } - const rightNode = new mathMLTree.MathNode("mo", [makeText(group.right, group.mode)]); - rightNode.setAttribute("fence", "true"); - rightNode.setAttribute("form", "postfix"); - if (group.right === "\u2216") { rightNode.setAttribute("stretchy", "true"); } - if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor); } - inner.push(rightNode); - - return makeRow(inner); - } -}); - -defineFunction({ - type: "middle", - names: ["\\middle"], - props: { - numArgs: 1, - argTypes: ["primitive"] - }, - handler: (context, args) => { - const delim = checkDelimiter(args[0], context); - if (!context.parser.leftrightDepth) { - throw new ParseError("\\middle without preceding \\left", delim); - } - - return { - type: "middle", - mode: context.parser.mode, - delim: delim.text - }; - }, - mathmlBuilder: (group, style) => { - const textNode = makeText(group.delim, group.mode); - const middleNode = new mathMLTree.MathNode("mo", [textNode]); - middleNode.setAttribute("fence", "true"); - // MathML gives 5/18em spacing to each element. - // \middle should get delimiter spacing instead. - middleNode.setAttribute("lspace", "0.05em"); - middleNode.setAttribute("rspace", "0.05em"); - return middleNode; - } -}); - -const mathmlBuilder$2 = (group, style) => { - const node = new mathMLTree.MathNode( - group.label.indexOf("colorbox") > -1 ? "mpadded" : "menclose", - [buildGroup(group.body, style)] - ); - switch (group.label) { - case "\\cancel": - node.setAttribute("notation", "updiagonalstrike"); - break; - case "\\bcancel": - node.setAttribute("notation", "downdiagonalstrike"); - break; - case "\\longdiv": - node.setAttribute("notation", "longdiv"); - break; - case "\\phase": - node.setAttribute("notation", "phasorangle"); - break; - case "\\sout": - node.setAttribute("notation", "horizontalstrike"); - break; - case "\\fbox": - node.setAttribute("notation", "box"); - break; - case "\\angl": - node.setAttribute("notation", "actuarial"); - break; - case "\\fcolorbox": - case "\\colorbox": { - // doesn't have a good notation option for \colorbox. - // So use instead. Set some attributes that come - // included with . - const fboxsep = 3; // 3 pt from LaTeX source2e - node.setAttribute("width", `+${2 * fboxsep}pt`); - node.setAttribute("height", `+${2 * fboxsep}pt`); - node.setAttribute("lspace", `${fboxsep}pt`); // - node.setAttribute("voffset", `${fboxsep}pt`); - if (group.label === "\\fcolorbox") { - node.setAttribute("style", "border: 0.06em solid " + String(group.borderColor)); - } - break; - } - case "\\xcancel": - node.setAttribute("notation", "updiagonalstrike downdiagonalstrike"); - break; - } - if (group.backgroundColor) { - node.setAttribute("mathbackground", group.backgroundColor); - } - return node; -}; - -defineFunction({ - type: "enclose", - names: ["\\colorbox"], - props: { - numArgs: 2, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let color = ""; - if (model) { - const spec = assertNodeType(args[0], "raw").string; - color = colorFromSpec(model, spec); - } else { - color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - } - const body = args[1]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor: color, - body - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -defineFunction({ - type: "enclose", - names: ["\\fcolorbox"], - props: { - numArgs: 3, - numOptionalArgs: 1, - allowedInText: true, - argTypes: ["raw", "raw", "raw", "text"] - }, - handler({ parser, funcName }, args, optArgs) { - const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string; - let borderColor = ""; - let backgroundColor; - if (model) { - const borderSpec = assertNodeType(args[0], "raw").string; - const backgroundSpec = assertNodeType(args[0], "raw").string; - borderColor = colorFromSpec(model, borderSpec); - backgroundColor = colorFromSpec(model, backgroundSpec); - } else { - borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros); - backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros); - } - const body = args[2]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - backgroundColor, - borderColor, - body - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -defineFunction({ - type: "enclose", - names: ["\\fbox"], - props: { - numArgs: 1, - argTypes: ["hbox"], - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "enclose", - mode: parser.mode, - label: "\\fbox", - body: args[0] - }; - } -}); - -defineFunction({ - type: "enclose", - names: ["\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\angl", "\\phase", "\\longdiv"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "enclose", - mode: parser.mode, - label: funcName, - body - }; - }, - mathmlBuilder: mathmlBuilder$2 -}); - -/** - * All registered environments. - * `environments.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `environments.js`. - */ -const _environments = {}; - -function defineEnvironment({ type, names, props, handler, mathmlBuilder }) { - // Set default values of environments. - const data = { - type, - numArgs: props.numArgs || 0, - allowedInText: false, - numOptionalArgs: 0, - handler - }; - for (let i = 0; i < names.length; ++i) { - _environments[names[i]] = data; - } - if (mathmlBuilder) { - _mathmlGroupBuilders[type] = mathmlBuilder; - } -} - -// In TeX, there are actually three sets of dimensions, one for each of - -// Math style is not quite the same thing as script level. -const StyleLevel = { - DISPLAY: 0, - TEXT: 1, - SCRIPT: 2, - SCRIPTSCRIPT: 3 -}; - -// Helper functions -function getHLines(parser) { - // Return an array. The array length = number of hlines. - // Each element in the array tells if the line is dashed. - const hlineInfo = []; - parser.consumeSpaces(); - let nxt = parser.fetch().text; - while (nxt === "\\hline" || nxt === "\\hdashline") { - parser.consume(); - hlineInfo.push(nxt === "\\hdashline"); - parser.consumeSpaces(); - nxt = parser.fetch().text; - } - return hlineInfo; -} - -const validateAmsEnvironmentContext = context => { - const settings = context.parser.settings; - if (!settings.displayMode) { - throw new ParseError(`{${context.envName}} can be used only in` + - ` display mode.`); - } -}; - -const getTag = (group, style, rowNum) => { - let tag; - const tagContents = group.tags.shift(); - if (tagContents) { - // The author has written a \tag or a \notag in this row. - if (tagContents.body) { - tag = buildExpressionRow(tagContents.body, style); - tag.classes = ["tml-tag"]; - } else { - // \notag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } - } else if (group.colSeparationType === "multline" && - ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) { - // A multiline that does not receive a tag. Return an empty cell. - tag = new mathMLTree.MathNode("mtd", []); - tag.setAttribute("style", "padding: 0; min-width:0"); - return tag - } else { - // AMS automatcally numbered equaton. - // Insert a class so the element can be populated by a post-processor. - tag = new mathMLTree.MathNode("mtext", [], ["tml-eqn"]); - } - if (!group.preventTagLap) { - tag = new mathMLTree.MathNode("mpadded", [tag]); - tag.setAttribute("style", "width:0;"); - tag.setAttribute("width", "0"); - if (!group.leqno) { tag.setAttribute("lspace", "-1width"); } - } - tag = new mathMLTree.MathNode("mtd", [tag]); - if (!group.preventTagLap) { tag.setAttribute("style", "padding: 0; min-width:0"); } - return tag -}; - -/** - * Parse the body of the environment, with rows delimited by \\ and - * columns delimited by &, and create a nested list in row-major order - * with one group per cell. If given an optional argument scriptLevel - * ("text", "display", etc.), then each cell is cast into that scriptLevel. - */ -function parseArray( - parser, - { - hskipBeforeAndAfter, // boolean - addJot, // boolean - cols, // [{ type: string , align: l|c|r|null }] - arraystretch, // number - colSeparationType, // "align" | "alignat" | "gather" | "small" | "CD" | "multline" - addEqnNum, // boolean - singleRow, // boolean - emptySingleRow, // boolean - maxNumCols, // number - leqno // boolean - }, - scriptLevel -) { - parser.gullet.beginGroup(); - if (!singleRow) { - // \cr is equivalent to \\ without the optional size argument (see below) - // TODO: provide helpful error when \cr is used outside array environment - parser.gullet.macros.set("\\cr", "\\\\\\relax"); - } - if (addEqnNum) { - parser.gullet.macros.set("\\tag", "\\env@tag{\\text{#1}}"); - parser.gullet.macros.set("\\notag", "\\env@notag"); - parser.gullet.macros.set("\\nonumber", "\\env@notag"); - } - - // Get current arraystretch if it's not set by the environment - if (arraystretch === undefined || Number.isNaN(arraystretch)) { - const stretch = parser.gullet.expandMacroAsText("\\arraystretch"); - if (stretch == null) { - // Default \arraystretch from lttab.dtx - arraystretch = 1; - } else { - arraystretch = parseFloat(stretch); - if (!arraystretch || arraystretch < 0) { - throw new ParseError(`Invalid \\arraystretch: ${stretch}`); - } - } - } - - // Start group for first cell - parser.gullet.beginGroup(); - - let row = []; - const body = [row]; - const rowGaps = []; - const tags = []; - let rowTag; - const hLinesBeforeRow = []; - - // Test for \hline at the top of the array. - hLinesBeforeRow.push(getHLines(parser)); - - // eslint-disable-next-line no-constant-condition - while (true) { - // Parse each cell in its own group (namespace) - let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\"); - - if (addEqnNum && !rowTag) { - // Check if the author wrote a \tag{} inside this cell. - for (let i = 0; i < cell.length; i++) { - if (cell[i].type === "envTag" || cell[i].type === "noTag") { - // Get the contents of the \text{} nested inside the \env@Tag{} - rowTag = cell[i].type === "envTag" - ? cell.splice(i, 1)[0].body.body[0] - : { body: null }; - break - } - } - } - parser.gullet.endGroup(); - parser.gullet.beginGroup(); - - cell = { - type: "ordgroup", - mode: parser.mode, - body: cell - }; - row.push(cell); - const next = parser.fetch().text; - if (next === "&") { - if (maxNumCols && row.length === maxNumCols) { - if (singleRow || colSeparationType) { - // {equation} or {split} - throw new ParseError("Too many tab characters: &", parser.nextToken); - } else { - // {array} environment - parser.settings.reportNonstrict( - "textEnv", - "Too few columns " + "specified in the {array} column argument." - ); - } - } - parser.consume(); - } else if (next === "\\end") { - // Arrays terminate newlines with `\crcr` which consumes a `\cr` if - // the last line is empty. However, AMS environments keep the - // empty row if it's the only one. - // NOTE: Currently, `cell` is the last item added into `row`. - if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) { - body.pop(); - } - if (hLinesBeforeRow.length < body.length + 1) { - hLinesBeforeRow.push([]); - } - break; - } else if (next === "\\\\") { - parser.consume(); - let size; - // \def\Let@{\let\\\math@cr} - // \def\math@cr{...\math@cr@} - // \def\math@cr@{\new@ifnextchar[\math@cr@@{\math@cr@@[\z@]}} - // \def\math@cr@@[#1]{...\math@cr@@@...} - // \def\math@cr@@@{\cr} - if (parser.gullet.future().text !== " ") { - size = parser.parseSizeGroup(true); - } - rowGaps.push(size ? size.value : null); - - tags.push(rowTag); - - // check for \hline(s) following the row separator - hLinesBeforeRow.push(getHLines(parser)); - - row = []; - rowTag = null; - body.push(row); - } else { - throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken); - } - } - - // End cell group - parser.gullet.endGroup(); - // End array group defining \cr - parser.gullet.endGroup(); - - tags.push(rowTag); - - return { - type: "array", - mode: parser.mode, - addJot, - arraystretch, - body, - cols, - rowGaps, - hskipBeforeAndAfter, - hLinesBeforeRow, - colSeparationType, - addEqnNum, - scriptLevel, - tags, - leqno, - preventTagLap: parser.settings.preventTagLap - }; -} - -// Decides on a scriptLevel for cells in an array according to whether the given -// environment name starts with the letter 'd'. -function dCellStyle(envName) { - return envName.substr(0, 1) === "d" ? "display" : "text" -} - -const alignMap = { - c: "center ", - l: "left ", - r: "right " -}; - -const mathmlBuilder$3 = function(group, style) { - const tbl = []; - const numRows = group.body.length; - let glue; - if (group.addEqnNum) { - glue = new mathMLTree.MathNode("mtd", [], []); - const glueStyle = "padding: 0;width: " + - (group.colSeparationType === "multline" ? "7.5%" : "50%"); - glue.setAttribute("style", glueStyle); - } - - for (let i = 0; i < numRows; i++) { - const rw = group.body[i]; - const row = []; - const cellStyle = group.scriptLevel === "text" - ? StyleLevel.TEXT - : group.scriptLevel === "script" - ? StyleLevel.SCRIPT - : StyleLevel.DISPLAY; - - for (let j = 0; j < rw.length; j++) { - const mtd = new mathMLTree.MathNode( - "mtd", - [buildGroup(rw[j], style.withLevel(cellStyle))] - ); - if (group.colSeparationType === "multline") { - const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"; - mtd.setAttribute("columnalign", align); - } - row.push(mtd); - } - if (group.addEqnNum) { - row.unshift(glue); - row.push(glue); - const tag = getTag(group, style.withLevel(cellStyle), i); - if (group.leqno) { - row.unshift(tag); - } else { - row.push(tag); - } - } - // If group.addEqnNum, insert a breadcrumb to be found by temmlPostProcess(). - tbl.push(new mathMLTree.MathNode("mtr", row, group.addEqnNum ? ["tml-tageqn"] : [] )); - } - let table = new mathMLTree.MathNode("mtable", tbl); - if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); } - - // Set column alignment, row spacing, column spacing, and - // array lines by setting attributes on the table element. - - // Set the row spacing. In MathML, we specify a gap distance. - // We do not use rowGap[] because MathML automatically increases - // cell height with the height/depth of the element content. - - // LaTeX \arraystretch multiplies the row baseline-to-baseline distance. - // We simulate this by adding (arraystretch - 1)em to the gap. This - // does a reasonable job of adjusting arrays containing 1 em tall content. - - // The 0.16 and 0.09 values are found emprically. They produce an array - // similar to LaTeX and in which content does not interfere with \hines. - const gap = - group.arraystretch === 0 - ? 0 // {subarray} - : group.arraystretch === 0.5 - ? 0.1 // {smallmatrix} - : 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0); - table.setAttribute("rowspacing", utils.round(gap) + "em"); - - if (group.addEqnNum || group.colSeparationType === "multline") { - table.setAttribute("width", "100%"); - } - - // MathML table lines go only between cells. - // To place a line on an edge we'll use , if necessary. - let menclose = ""; - let align = ""; - - if (group.cols && group.cols.length > 0) { - // Find column alignment, column spacing, and vertical lines. - const cols = group.cols; - let columnLines = ""; - let prevTypeWasAlign = false; - let iStart = 0; - let iEnd = cols.length; - - if (cols[0].type === "separator") { - menclose += "left "; - iStart = 1; - } - if (cols[cols.length - 1].type === "separator") { - menclose += "right "; - iEnd -= 1; - } - - for (let i = iStart; i < iEnd; i++) { - if (cols[i].type === "align") { - align += alignMap[cols[i].align]; - - if (prevTypeWasAlign) { - columnLines += "none "; - } - prevTypeWasAlign = true; - } else if (cols[i].type === "separator") { - // MathML accepts only single lines between cells. - // So we read only the first of consecutive separators. - if (prevTypeWasAlign) { - columnLines += cols[i].separator === "|" ? "solid " : "dashed "; - prevTypeWasAlign = false; - } - } - } - if (group.addEqnNum) { - align = "left " + align + "right "; // allow for glue cells on each side - align = group.leqno ? "left " + align : align += "right"; // eqn num cell - } - - table.setAttribute("columnalign", align.trim()); - - if (/[sd]/.test(columnLines)) { - table.setAttribute("columnlines", columnLines.trim()); - } - } - - // Set column spacing. - switch (group.colSeparationType) { - case "gather": - case "gathered": - case "alignedat": - case "alignat": - case "alignat*": - table.setAttribute("columnspacing", "0em"); - break - case "small": - table.setAttribute("columnspacing", "0.2778em"); - break - case "CD": - table.setAttribute("columnspacing", "0.5em"); - break - case "align": - case "align*": { - const cols = group.cols || []; - let spacing = group.addEqnNum ? "0em " : ""; - for (let i = 1; i < cols.length; i++) { - spacing += i % 2 ? "0em " : "1em "; - } - if (group.addEqnNum) { spacing += "0em"; } - table.setAttribute("columnspacing", spacing.trim()); - break - } - default: - table.setAttribute("columnspacing", "1em"); - } - - // Address \hline and \hdashline - let rowLines = ""; - const hlines = group.hLinesBeforeRow; - - menclose += hlines[0].length > 0 ? "top " : ""; - menclose += hlines[hlines.length - 1].length > 0 ? "bottom " : ""; - - for (let i = 1; i < hlines.length - 1; i++) { - rowLines += - hlines[i].length === 0 - ? "none " - : // MathML accepts only a single line between rows. Read one element. - hlines[i][0] - ? "dashed " - : "solid "; - } - if (/[sd]/.test(rowLines)) { - table.setAttribute("rowlines", rowLines.trim()); - } - - if (menclose !== "") { - table = new mathMLTree.MathNode("menclose", [table]); - table.setAttribute("notation", menclose.trim()); - } - - if (!Number.isNaN(group.arraystretch) && group.arraystretch < 1) { - // A small array. Wrap in scriptstyle so row gap is not too large. - table = new mathMLTree.MathNode("mstyle", [table]); - table.setAttribute("scriptlevel", "1"); - } - - return table; -}; - -// Convenience function for align, align*, aligned, alignat, alignat*, alignedat. -const alignedHandler = function(context, args) { - if (context.envName.indexOf("ed") === -1) { - validateAmsEnvironmentContext(context); - } - const cols = []; - const res = parseArray( - context.parser, - { - cols, - addJot: true, - addEqnNum: context.envName === "align" || context.envName === "alignat", - emptySingleRow: true, - colSeparationType: context.envName, - maxNumCols: context.envName === "split" ? 2 : undefined, - leqno: context.parser.settings.leqno - }, - "display" - ); - - // Determining number of columns. - // 1. If the first argument is given, we use it as a number of columns, - // and makes sure that each row doesn't exceed that number. - // 2. Otherwise, just count number of columns = maximum number - // of cells in each row ("aligned" mode -- isAligned will be true). - // - // At the same time, prepend empty group {} at beginning of every second - // cell in each row (starting with second cell) so that operators become - // binary. This behavior is implemented in amsmath's \start@aligned. - let numMaths; - let numCols = 0; - if (args[0] && args[0].type === "ordgroup") { - let arg0 = ""; - for (let i = 0; i < args[0].body.length; i++) { - const textord = assertNodeType(args[0].body[i], "textord"); - arg0 += textord.text; - } - numMaths = Number(arg0); - numCols = numMaths * 2; - } - const isAligned = !numCols; - res.body.forEach(function(row) { - if (!isAligned) { - // Case 1 - const curMaths = row.length / 2; - if (numMaths < curMaths) { - throw new ParseError( - "Too many math in a row: " + `expected ${numMaths}, but got ${curMaths}`, - row[0] - ); - } - } else if (numCols < row.length) { - // Case 2 - numCols = row.length; - } - }); - - // Adjusting alignment. - // In aligned mode, we add one \qquad between columns; - // otherwise we add nothing. - for (let i = 0; i < numCols; ++i) { - let align = "r"; - if (i % 2 === 1) { - align = "l"; - } - cols[i] = { - type: "align", - align: align - }; - } - res.colSeparationType = isAligned ? "align" : "alignat"; - return res; -}; - -// Arrays are part of LaTeX, defined in lttab.dtx so its documentation -// is part of the source2e.pdf file of LaTeX2e source documentation. -// {darray} is an {array} environment where cells are set in \displaystyle, -// as defined in nccmath.sty. -defineEnvironment({ - type: "array", - names: ["array", "darray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Since no types are specified above, the two possibilities are - // - The argument is wrapped in {} or [], in which case Parser's - // parseGroup() returns an "ordgroup" wrapping some symbol node. - // - The argument is a bare symbol node. - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - if ("lcr".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } else if (ca === "|") { - return { - type: "separator", - separator: "|" - }; - } else if (ca === ":") { - return { - type: "separator", - separator: ":" - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - const res = { - cols, - colSeparationType: "array", - hskipBeforeAndAfter: true, // \@preamble in lttab.dtx - maxNumCols: cols.length - }; - return parseArray(context.parser, res, dCellStyle(context.envName)); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// The matrix environments of amsmath builds on the array environment -// of LaTeX, which is discussed above. -// The mathtools package adds starred versions of the same environments. -// These have an optional argument to choose left|center|right justification. -defineEnvironment({ - type: "array", - names: [ - "matrix", - "pmatrix", - "bmatrix", - "Bmatrix", - "vmatrix", - "Vmatrix", - "matrix*", - "pmatrix*", - "bmatrix*", - "Bmatrix*", - "vmatrix*", - "Vmatrix*" - ], - props: { - numArgs: 0 - }, - handler(context) { - const delimiters = { - matrix: null, - pmatrix: ["(", ")"], - bmatrix: ["[", "]"], - Bmatrix: ["\\{", "\\}"], - vmatrix: ["|", "|"], - Vmatrix: ["\\Vert", "\\Vert"] - }[context.envName.replace("*", "")]; - // \hskip -\arraycolsep in amsmath - let colAlign = "c"; - const payload = { - hskipBeforeAndAfter: false, - colSeparationType: "matrix", - cols: [{ type: "align", align: colAlign }] - }; - if (context.envName.charAt(context.envName.length - 1) === "*") { - // It's one of the mathtools starred functions. - // Parse the optional alignment argument. - const parser = context.parser; - parser.consumeSpaces(); - if (parser.fetch().text === "[") { - parser.consume(); - parser.consumeSpaces(); - colAlign = parser.fetch().text; - if ("lcr".indexOf(colAlign) === -1) { - throw new ParseError("Expected l or c or r", parser.nextToken); - } - parser.consume(); - parser.consumeSpaces(); - parser.expect("]"); - parser.consume(); - payload.cols = [{ type: "align", align: colAlign }]; - } - } - const res = parseArray(context.parser, payload, "text"); - // Populate cols with the correct number of column alignment specs. - const numCols = Math.max(0, ...res.body.map((row) => row.length)); - res.cols = new Array(numCols).fill({ type: "align", align: colAlign }); - return delimiters - ? { - type: "leftright", - mode: context.mode, - body: [res], - left: delimiters[0], - right: delimiters[1], - rightColor: undefined // \right uninfluenced by \color in array - } - : res; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["smallmatrix"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { arraystretch: 0.5 }; - const res = parseArray(context.parser, payload, "script"); - res.colSeparationType = "small"; - return res; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["subarray"], - props: { - numArgs: 1 - }, - handler(context, args) { - // Parsing of {subarray} is similar to {array} - const symNode = checkSymbolNodeType(args[0]); - const colalign = symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body; - const cols = colalign.map(function(nde) { - const node = assertSymbolNodeType(nde); - const ca = node.text; - // {subarray} only recognizes "l" & "c" - if ("lc".indexOf(ca) !== -1) { - return { - type: "align", - align: ca - }; - } - throw new ParseError("Unknown column alignment: " + ca, nde); - }); - if (cols.length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - let res = { - cols, - hskipBeforeAndAfter: false, - colSeparationType: "array", - arraystretch: 0 - }; - res = parseArray(context.parser, res, "script"); - if (res.body.length > 0 && res.body[0].length > 1) { - throw new ParseError("{subarray} can contain only one column"); - } - return res; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// A cases environment (in amsmath.sty) is almost equivalent to -// \def -// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right. -// {dcases} is a {cases} environment where cells are set in \displaystyle, -// as defined in mathtools.sty. -// {rcases} is another mathtools environment. It's brace is on the right side. -defineEnvironment({ - type: "array", - names: ["cases", "dcases", "rcases", "drcases"], - props: { - numArgs: 0 - }, - handler(context) { - const payload = { - cols: [ - { - type: "align", - align: "l" - }, - { - type: "align", - align: "l" - } - ], - colSeparationType: "cases" - }; - const res = parseArray(context.parser, payload, dCellStyle(context.envName)); - return { - type: "leftright", - mode: context.mode, - body: [res], - left: context.envName.indexOf("r") > -1 ? "." : "\\{", - right: context.envName.indexOf("r") > -1 ? "\\}" : ".", - rightColor: undefined - }; - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// In the align environment, one uses ampersands, &, to specify number of -// columns in each row, and to locate spacing between each column. -// align gets automatic numbering. align* and aligned do not. -// The alignedat environment can be used in math mode. -// Note that we assume \nomallineskiplimit to be zero, -// so that \strut@ is the same as \strut. -defineEnvironment({ - type: "array", - names: ["align", "align*", "aligned", "split"], - props: { - numArgs: 0 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$3 -}); - -// A gathered environment is like an array environment with one centered -// column, but where rows are considered lines so get \jot line spacing -// and contents are set in \displaystyle. -defineEnvironment({ - type: "array", - names: ["gathered", "gather", "gather*"], - props: { - numArgs: 0 - }, - handler(context) { - if (utils.contains(["gather", "gather*"], context.envName)) { - validateAmsEnvironmentContext(context); - } - const res = { - cols: [ - { - type: "align", - align: "c" - } - ], - addJot: true, - colSeparationType: "gather", - addEqnNum: context.envName === "gather", - emptySingleRow: true, - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// alignat environment is like an align environment, but one must explicitly -// specify maximum number of columns in each row, and can adjust spacing between -// each columns. -defineEnvironment({ - type: "array", - names: ["alignat", "alignat*", "alignedat"], - props: { - numArgs: 1 - }, - handler: alignedHandler, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["equation", "equation*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "equation", - emptySingleRow: true, - singleRow: true, - maxNumCols: 1, - colSeparationType: "gather", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["multline", "multline*"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - const res = { - addEqnNum: context.envName === "multline", - maxNumCols: 1, - colSeparationType: "multline", - leqno: context.parser.settings.leqno - }; - return parseArray(context.parser, res, "display"); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -defineEnvironment({ - type: "array", - names: ["CD"], - props: { - numArgs: 0 - }, - handler(context) { - validateAmsEnvironmentContext(context); - return parseCD(context.parser); - }, - mathmlBuilder: mathmlBuilder$3 -}); - -// Catch \hline outside array environment -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\hline", "\\hdashline"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: true - }, - handler(context, args) { - throw new ParseError(`${context.funcName} valid only within array environment`); - } -}); - -const environments = _environments; - -// Environment delimiters. HTML/MathML rendering is defined in the corresponding -// defineEnvironment definitions. -defineFunction({ - type: "environment", - names: ["\\begin", "\\end"], - props: { - numArgs: 1, - argTypes: ["text"] - }, - handler({ parser, funcName }, args) { - const nameGroup = args[0]; - if (nameGroup.type !== "ordgroup") { - throw new ParseError("Invalid environment name", nameGroup); - } - let envName = ""; - for (let i = 0; i < nameGroup.body.length; ++i) { - envName += assertNodeType(nameGroup.body[i], "textord").text; - } - - if (funcName === "\\begin") { - // begin...end is similar to left...right - if (!Object.prototype.hasOwnProperty.call(environments, envName )) { - throw new ParseError("No such environment: " + envName, nameGroup); - } - // Build the environment object. Arguments and other information will - // be made available to the begin and end methods using properties. - const env = environments[envName]; - const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env); - const context = { - mode: parser.mode, - envName, - parser - }; - const result = env.handler(context, args, optArgs); - parser.expect("\\end", false); - const endNameToken = parser.nextToken; - const end = assertNodeType(parser.parseFunction(), "environment"); - if (end.name !== envName) { - throw new ParseError( - `Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`, - endNameToken - ); - } - return result; - } - - return { - type: "environment", - mode: parser.mode, - name: envName, - nameGroup - }; - } -}); - -defineFunction({ - type: "envTag", - names: ["\\env@tag"], - props: { - numArgs: 1, - argTypes: ["math"] - }, - handler({ parser }, args) { - return { - type: "envTag", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -defineFunction({ - type: "noTag", - names: ["\\env@notag"], - props: { - numArgs: 0 - }, - handler({ parser }) { - return { - type: "noTag", - mode: parser.mode - }; - }, - mathmlBuilder(group, style) { - return new mathMLTree.MathNode("mrow"); - } -}); - -const mathmlBuilder$4 = (group, style) => { - const font = group.font; - const newStyle = style.withFont(font); - const mathGroup = buildGroup(group.body, newStyle); - - if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{} - if (mathGroup.type === "mo" && font === "boldsymbol") { - mathGroup.style.fontWeight = "bold"; - return mathGroup - } - // Check if it is possible to consolidate elements into a single element. - let canConsolidate = mathGroup.children[0].type === "mo"; - for (let i = 1; i < mathGroup.children.length; i++) { - if (mathGroup.children[i].type === "mo" && font === "boldsymbol") { - mathGroup.children[i].style.fontWeight = "bold"; - } - if (mathGroup.children[i].type !== "mi") { canConsolidate = false; } - const localVariant = mathGroup.children[i].attributes && - mathGroup.children[i].attributes.mathvariant || ""; - if (localVariant !== "normal") { canConsolidate = false; } - } - if (!canConsolidate) { return mathGroup } - // Consolidate the elements. - const mi = mathGroup.children[0]; - for (let i = 1; i < mathGroup.children.length; i++) { - mi.children.push(mathGroup.children[i].children[0]); - } - if (mathGroup.attributes.mathcolor) { mi.attributes.mathcolor = mathGroup.attributes.mathcolor; } - if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") { - // Workaround for a Firefox bug that renders spurious space around - // a - // Ref: https://bugs.webkit.org/show_bug.cgi?id=129097 - // We insert a text node that contains a zero-width space and wrap in an mrow. - // TODO: Get rid of this workaround when the Firefox bug is fixed. - const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b")); - return new mathMLTree.MathNode("mrow", [bogus, mi]) - } - return mi -}; - -const fontAliases = { - "\\Bbb": "\\mathbb", - "\\bold": "\\mathbf", - "\\frak": "\\mathfrak", - "\\bm": "\\boldsymbol" -}; - -defineFunction({ - type: "font", - names: [ - // styles - "\\mathrm", - "\\mathit", - "\\mathbf", - "\\mathnormal", - "\\up@greek", - "\\pmb", - "\\boldsymbol", - - // families - "\\mathbb", - "\\mathcal", - "\\mathfrak", - "\\mathscr", - "\\mathsf", - "\\mathtt", - "\\oldstylenums", - - // aliases - "\\Bbb", - "\\bm", - "\\bold", - "\\frak" - ], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = normalizeArgument(args[0]); - let func = funcName; - if (func in fontAliases) { - func = fontAliases[func]; - } - return { - type: "font", - mode: parser.mode, - font: func.slice(1), - body - }; - }, - mathmlBuilder: mathmlBuilder$4 -}); - -// Old font changing functions -defineFunction({ - type: "font", - names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ parser, funcName, breakOnTokenText }, args) => { - const { mode } = parser; - const body = parser.parseExpression(true, breakOnTokenText); - const fontStyle = `math${funcName.slice(1)}`; - - return { - type: "font", - mode: mode, - font: fontStyle, - body: { - type: "ordgroup", - mode: parser.mode, - body - } - }; - }, - mathmlBuilder: mathmlBuilder$4 -}); - -const stylArray = ["display", "text", "script", "scriptscript"]; -const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 }; - -const mathmlBuilder$5 = (group, style) => { - // Track the scriptLevel of the numerator and denominator. - // We may need that info for \mathchoice or for adjusting em dimensions. - const childOptions = group.scriptLevel === "auto" - ? style.incrementLevel() - : group.scriptLevel === "display" - ? style.withLevel(StyleLevel.TEXT) - : group.scriptLevel === "text" - ? style.withLevel(StyleLevel.SCRIPT) - : style.withLevel(StyleLevel.SCRIPTSCRIPT); - - let node = new mathMLTree.MathNode("mfrac", [ - buildGroup(group.numer, childOptions), - buildGroup(group.denom, childOptions) - ]); - - if (!group.hasBarLine) { - node.setAttribute("linethickness", "0px"); - } else if (group.barSize) { - const ruleWidth = calculateSize(group.barSize, style); - node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit); - } - - if (group.leftDelim != null || group.rightDelim != null) { - const withDelims = []; - - if (group.leftDelim != null) { - const leftOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.leftDelim.replace("\\", "")) - ]); - leftOp.setAttribute("fence", "true"); - withDelims.push(leftOp); - } - - withDelims.push(node); - - if (group.rightDelim != null) { - const rightOp = new mathMLTree.MathNode("mo", [ - new mathMLTree.TextNode(group.rightDelim.replace("\\", "")) - ]); - rightOp.setAttribute("fence", "true"); - withDelims.push(rightOp); - } - - node = makeRow(withDelims); - } - - if (group.scriptLevel !== "auto") { - node = new mathMLTree.MathNode("mstyle", [node]); - node.setAttribute("displaystyle", String(group.scriptLevel === "display")); - node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]); - } - - return node; -}; - -defineFunction({ - type: "genfrac", - names: [ - "\\dfrac", - "\\frac", - "\\tfrac", - "\\dbinom", - "\\binom", - "\\tbinom", - "\\\\atopfrac", // can’t be entered directly - "\\\\bracefrac", - "\\\\brackfrac" // ditto - ], - props: { - numArgs: 2, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - let hasBarLine = false; - let leftDelim = null; - let rightDelim = null; - let scriptLevel = "auto"; - - switch (funcName) { - case "\\dfrac": - case "\\frac": - case "\\tfrac": - hasBarLine = true; - break; - case "\\\\atopfrac": - hasBarLine = false; - break; - case "\\dbinom": - case "\\binom": - case "\\tbinom": - leftDelim = "("; - rightDelim = ")"; - break; - case "\\\\bracefrac": - leftDelim = "\\{"; - rightDelim = "\\}"; - break; - case "\\\\brackfrac": - leftDelim = "["; - rightDelim = "]"; - break; - default: - throw new Error("Unrecognized genfrac command"); - } - - switch (funcName) { - case "\\dfrac": - case "\\dbinom": - scriptLevel = "display"; - break; - case "\\tfrac": - case "\\tbinom": - scriptLevel = "text"; - break; - } - - return { - type: "genfrac", - mode: parser.mode, - continued: false, - numer, - denom, - hasBarLine, - leftDelim, - rightDelim, - scriptLevel, - barSize: null - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -defineFunction({ - type: "genfrac", - names: ["\\cfrac"], - props: { - numArgs: 2 - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const denom = args[1]; - - return { - type: "genfrac", - mode: parser.mode, - continued: true, - numer, - denom, - hasBarLine: true, - leftDelim: null, - rightDelim: null, - scriptLevel: "display", - barSize: null - }; - } -}); - -// Infix generalized fractions -- these are not rendered directly, but replaced -// immediately by one of the variants above. -defineFunction({ - type: "infix", - names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"], - props: { - numArgs: 0, - infix: true - }, - handler({ parser, funcName, token }) { - let replaceWith; - switch (funcName) { - case "\\over": - replaceWith = "\\frac"; - break; - case "\\choose": - replaceWith = "\\binom"; - break; - case "\\atop": - replaceWith = "\\\\atopfrac"; - break; - case "\\brace": - replaceWith = "\\\\bracefrac"; - break; - case "\\brack": - replaceWith = "\\\\brackfrac"; - break; - default: - throw new Error("Unrecognized infix genfrac command"); - } - return { - type: "infix", - mode: parser.mode, - replaceWith, - token - }; - } -}); - -const delimFromValue = function(delimString) { - let delim = null; - if (delimString.length > 0) { - delim = delimString; - delim = delim === "." ? null : delim; - } - return delim; -}; - -defineFunction({ - type: "genfrac", - names: ["\\genfrac"], - props: { - numArgs: 6, - allowedInArgument: true, - argTypes: ["math", "math", "size", "text", "math", "math"] - }, - handler({ parser }, args) { - const numer = args[4]; - const denom = args[5]; - - // Look into the parse nodes to get the desired delimiters. - const leftNode = normalizeArgument(args[0]); - const leftDelim = leftNode.type === "atom" && leftNode.family === "open" - ? delimFromValue(leftNode.text) - : null; - const rightNode = normalizeArgument(args[1]); - const rightDelim = - rightNode.type === "atom" && rightNode.family === "close" - ? delimFromValue(rightNode.text) - : null; - - const barNode = assertNodeType(args[2], "size"); - let hasBarLine; - let barSize = null; - if (barNode.isBlank) { - // \genfrac acts differently than \above. - // \genfrac treats an empty size group as a signal to use a - // standard bar size. \above would see size = 0 and omit the bar. - hasBarLine = true; - } else { - barSize = barNode.value; - hasBarLine = barSize.number > 0; - } - - // Find out if we want displaystyle, textstyle, etc. - let scriptLevel = "auto"; - let styl = args[3]; - if (styl.type === "ordgroup") { - if (styl.body.length > 0) { - const textOrd = assertNodeType(styl.body[0], "textord"); - scriptLevel = stylArray[Number(textOrd.text)]; - } - } else { - styl = assertNodeType(styl, "textord"); - scriptLevel = stylArray[Number(styl.text)]; - } - - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim, - rightDelim, - scriptLevel - }; - }, - mathmlBuilder: mathmlBuilder$5 -}); - -// \above is an infix fraction that also defines a fraction bar size. -defineFunction({ - type: "infix", - names: ["\\above"], - props: { - numArgs: 1, - argTypes: ["size"], - infix: true - }, - handler({ parser, funcName, token }, args) { - return { - type: "infix", - mode: parser.mode, - replaceWith: "\\\\abovefrac", - barSize: assertNodeType(args[0], "size").value, - token - }; - } -}); - -defineFunction({ - type: "genfrac", - names: ["\\\\abovefrac"], - props: { - numArgs: 3, - argTypes: ["math", "size", "math"] - }, - handler: ({ parser, funcName }, args) => { - const numer = args[0]; - const barSize = assert(assertNodeType(args[1], "infix").barSize); - const denom = args[2]; - - const hasBarLine = barSize.number > 0; - return { - type: "genfrac", - mode: parser.mode, - numer, - denom, - continued: false, - hasBarLine, - barSize, - leftDelim: null, - rightDelim: null, - scriptLevel: "auto" - }; - }, - - mathmlBuilder: mathmlBuilder$5 -}); - -const mathmlBuilder$6 = (group, style) => { - const accentNode = stretchy.mathMLnode(group.label); - return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [ - buildGroup(group.base, style), - accentNode - ]); -}; - -// Horizontal stretchy braces -defineFunction({ - type: "horizBrace", - names: ["\\overbrace", "\\underbrace"], - props: { - numArgs: 1 - }, - handler({ parser, funcName }, args) { - return { - type: "horizBrace", - mode: parser.mode, - label: funcName, - isOver: /^\\over/.test(funcName), - base: args[0] - }; - }, - mathmlBuilder: mathmlBuilder$6 -}); - -defineFunction({ - type: "href", - names: ["\\href"], - props: { - numArgs: 2, - argTypes: ["url", "original"], - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[1]; - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\href", - url: href - }) - ) { - return parser.formatUnsupportedCmd("\\href"); - } - - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - let math = buildExpressionRow(group.body, style); - if (!(math instanceof MathNode)) { - math = new MathNode("mrow", [math]); - } - math.setAttribute("href", group.href); - return math; - } -}); - -defineFunction({ - type: "href", - names: ["\\url"], - props: { - numArgs: 1, - argTypes: ["url"], - allowedInText: true - }, - handler: ({ parser }, args) => { - const href = assertNodeType(args[0], "url").url; - - if ( - !parser.settings.isTrusted({ - command: "\\url", - url: href - }) - ) { - return parser.formatUnsupportedCmd("\\url"); - } - - const chars = []; - for (let i = 0; i < href.length; i++) { - let c = href[i]; - if (c === "~") { - c = "\\textasciitilde"; - } - chars.push({ - type: "textord", - mode: "text", - text: c - }); - } - const body = { - type: "text", - mode: parser.mode, - font: "\\texttt", - body: chars - }; - return { - type: "href", - mode: parser.mode, - href, - body: ordargument(body) - }; - } -}); - -defineFunction({ - type: "html", - names: ["\\class", "\\id", "\\style", "\\data"], - props: { - numArgs: 2, - argTypes: ["raw", "original"], - allowedInText: true - }, - handler: ({ parser, funcName, token }, args) => { - const value = assertNodeType(args[0], "raw").string; - const body = args[1]; - - if (parser.settings.strict) { - parser.settings.reportNonstrict( - "htmlExtension", "HTML extension is disabled on strict mode" - ); - } - - let trustContext; - const attributes = {}; - - switch (funcName) { - case "\\class": - attributes.class = value; - trustContext = { - command: "\\class", - class: value - }; - break; - case "\\id": - attributes.id = value; - trustContext = { - command: "\\id", - id: value - }; - break; - case "\\style": - attributes.style = value; - trustContext = { - command: "\\style", - style: value - }; - break; - case "\\data": { - const data = value.split(","); - for (let i = 0; i < data.length; i++) { - const keyVal = data[i].split("="); - if (keyVal.length !== 2) { - throw new ParseError("Error parsing key-value for \\data"); - } - attributes["data-" + keyVal[0].trim()] = keyVal[1].trim(); - } - - trustContext = { - command: "\\data", - attributes - }; - break; - } - default: - throw new Error("Unrecognized html command"); - } - - if (!parser.settings.isTrusted(trustContext)) { - return parser.formatUnsupportedCmd(funcName); - } - return { - type: "html", - mode: parser.mode, - attributes, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const element = buildExpressionRow(group.body, style); - - const classes = []; - if (group.attributes.class) { - classes.push(...group.attributes.class.trim().split(/\s+/)); - } - element.classes = classes; - - for (const attr in group.attributes) { - if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) { - element.setAttribute(attr, group.attributes[attr]); - } - } - - return element; - } -}); - -const sizeData = function(str) { - if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) { - // str is a number with no unit specified. - // default unit is bp, per graphix package. - return { number: +str, unit: "bp" } - } else { - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(str); - if (!match) { - throw new ParseError("Invalid size: '" + str + "' in \\includegraphics"); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "' in \\includegraphics."); - } - return data - } -}; - -defineFunction({ - type: "includegraphics", - names: ["\\includegraphics"], - props: { - numArgs: 1, - numOptionalArgs: 1, - argTypes: ["raw", "url"], - allowedInText: false - }, - handler: ({ parser }, args, optArgs) => { - let width = { number: 0, unit: "em" }; - let height = { number: 0.9, unit: "em" }; // sorta character sized. - let totalheight = { number: 0, unit: "em" }; - let alt = ""; - - if (optArgs[0]) { - const attributeStr = assertNodeType(optArgs[0], "raw").string; - - // Parser.js does not parse key/value pairs. We get a string. - const attributes = attributeStr.split(","); - for (let i = 0; i < attributes.length; i++) { - const keyVal = attributes[i].split("="); - if (keyVal.length === 2) { - const str = keyVal[1].trim(); - switch (keyVal[0].trim()) { - case "alt": - alt = str; - break - case "width": - width = sizeData(str); - break - case "height": - height = sizeData(str); - break - case "totalheight": - totalheight = sizeData(str); - break - default: - throw new ParseError("Invalid key: '" + keyVal[0] + "' in \\includegraphics.") - } - } - } - } - - const src = assertNodeType(args[0], "url").url; - - if (alt === "") { - // No alt given. Use the file name. Strip away the path. - alt = src; - alt = alt.replace(/^.*[\\/]/, ""); - alt = alt.substring(0, alt.lastIndexOf(".")); - } - - if ( - !parser.settings.isTrusted({ - command: "\\includegraphics", - url: src - }) - ) { - return parser.formatUnsupportedCmd("\\includegraphics") - } - - return { - type: "includegraphics", - mode: parser.mode, - alt: alt, - width: width, - height: height, - totalheight: totalheight, - src: src - } - }, - mathmlBuilder: (group, style) => { - const height = calculateSize(group.height, style); - const depth = { number: 0, unit: "em" }; - - if (group.totalheight.number > 0) { - if (group.totalheight.unit === height.unit && - group.totalheight.number > height.number) { - depth.number = group.totalheight.number - height.number; - depth.unit = height.unit; - } - } - - let width = 0; - if (group.width.number > 0) { - width = calculateSize(group.width, style); - } - - const graphicStyle = { height: height.number + depth.number + "em" }; - if (width.number > 0) { - graphicStyle.width = width.number + width.unit; - } - if (depth.number > 0) { - graphicStyle.verticalAlign = -depth.number + depth.unit; - } - - const node = new Img(group.src, group.alt, graphicStyle); - node.height = height; - node.depth = depth; - return new mathMLTree.MathNode("mtext", [node]) - } -}); - -// Horizontal spacing commands - -// TODO: \hskip and \mskip should support plus and minus in lengths - -defineFunction({ - type: "kern", - names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"], - props: { - numArgs: 1, - argTypes: ["size"], - primitive: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const size = assertNodeType(args[0], "size"); - if (parser.settings.strict) { - const mathFunction = funcName[1] === "m"; // \mkern, \mskip - const muUnit = size.value.unit === "mu"; - if (mathFunction) { - if (!muUnit) { - parser.settings.reportNonstrict( - "mathVsTextUnits", - `LaTeX's ${funcName} supports only mu units, ` + `not ${size.value.unit} units` - ); - } - if (parser.mode !== "math") { - parser.settings.reportNonstrict( - "mathVsTextUnits", - `LaTeX's ${funcName} works only in math mode` - ); - } - } else { - // !mathFunction - if (muUnit) { - parser.settings.reportNonstrict( - "mathVsTextUnits", - `LaTeX's ${funcName} doesn't support mu units` - ); - } - } - } - return { - type: "kern", - mode: parser.mode, - dimension: size.value - }; - }, - mathmlBuilder(group, style) { - const dimension = calculateSize(group.dimension, style); - const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : ""; - if (group.mode === "text" && ch.length > 0) { - const character = new mathMLTree.TextNode(ch); - return new mathMLTree.MathNode("mtext", [character]); - } else { - const node = new mathMLTree.MathNode("mspace"); - node.setAttribute("width", dimension.number + dimension.unit); - return node; - } - } -}); - -const spaceCharacter = function(width) { - if (width >= 0.05555 && width <= 0.05556) { - return "\u200a"; //   - } else if (width >= 0.1666 && width <= 0.1667) { - return "\u2009"; //   - } else if (width >= 0.2222 && width <= 0.2223) { - return "\u2005"; //   - } else if (width >= 0.2777 && width <= 0.2778) { - return "\u2005\u200a"; //    - } else { - return ""; - } -}; - -// Limit valid characters to a small set, for safety. -const invalidIdRegEx = /[^A-Za-z_0-9-]/g; - -defineFunction({ - type: "label", - names: ["\\label"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser }, args) { - return { - type: "label", - mode: parser.mode, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Return a no-width, no-ink element with an HTML id. - const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]); - if (group.string.length > 0) { - node.setAttribute("id", group.string); - } - return node - } -}); - -// Horizontal overlap functions - -const textModeLap = ["\\clap", "\\llap", "\\rlap"]; - -defineFunction({ - type: "lap", - names: ["\\mathllap", "\\mathrlap", "\\mathclap", "\\clap", "\\llap", "\\rlap"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser, funcName }, args) => { - if (textModeLap.includes(funcName)) { - if (parser.settings.strict && parser.mode !== "text") { - throw new ParseError(`{${funcName}} can be used only in text mode.`) - } - funcName = funcName.slice(1); - } else { - funcName = funcName.slice(5); - } - const body = args[0]; - return { - type: "lap", - mode: parser.mode, - alignment: funcName, - body - } - }, - mathmlBuilder: (group, style) => { - // mathllap, mathrlap, mathclap - const node = new mathMLTree.MathNode("mpadded", [buildGroup(group.body, style)]); - - if (group.alignment === "rlap") { - if (group.body.body.length > 0 && group.body.body[0].type === "genfrac") { - // In Firefox, a squashes the 3/18em padding of a child \frac. Put it back. - node.setAttribute("lspace", "0.16667em"); - } - } else { - const offset = group.alignment === "llap" ? "-1" : "-0.5"; - node.setAttribute("lspace", offset + "width"); - } - node.setAttribute("width", "0px"); - return node - } -}); - -// Switching from text mode back to math mode -defineFunction({ - type: "ordgroup", - names: ["\\(", "$"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler({ funcName, parser }, args) { - const outerMode = parser.mode; - parser.switchMode("math"); - const close = funcName === "\\(" ? "\\)" : "$"; - const body = parser.parseExpression(false, close); - parser.expect(close); - parser.switchMode(outerMode); - return { - type: "ordgroup", - mode: parser.mode, - body - }; - } -}); - -// Check for extra closing math delimiters -defineFunction({ - type: "text", // Doesn't matter what this is. - names: ["\\)", "\\]"], - props: { - numArgs: 0, - allowedInText: true, - allowedInMath: false - }, - handler(context, args) { - throw new ParseError(`Mismatched ${context.funcName}`); - } -}); - -const chooseStyle = (group, style) => { - switch (style.level) { - case StyleLevel.DISPLAY: // 0 - return group.display; - case StyleLevel.TEXT: // 1 - return group.text; - case StyleLevel.SCRIPT: // 2 - return group.script; - case StyleLevel.SCRIPTSCRIPT: // 3 - return group.scriptscript; - default: - return group.text; - } -}; - -defineFunction({ - type: "mathchoice", - names: ["\\mathchoice"], - props: { - numArgs: 4, - primitive: true - }, - handler: ({ parser }, args) => { - return { - type: "mathchoice", - mode: parser.mode, - display: ordargument(args[0]), - text: ordargument(args[1]), - script: ordargument(args[2]), - scriptscript: ordargument(args[3]) - }; - }, - mathmlBuilder: (group, style) => { - const body = chooseStyle(group, style); - return buildExpressionRow(body, style); - } -}); - -const textAtomTypes = ["text", "textord", "mathord", "atom"]; - -function mathmlBuilder$7(group, style) { - let node; - const inner = buildExpression(group.body, style); - - if (group.mclass === "minner") { - return mathMLTree.newDocumentFragment(inner); - } else if (group.mclass === "mord") { - if (group.isCharacterBox || inner[0].type === "mathord") { - node = inner[0]; - node.type = "mi"; - } else { - node = new mathMLTree.MathNode("mi", inner); - } - } else { - if (group.mustPromote) { - node = inner[0]; - node.type = "mo"; - if (group.isCharacterBox && group.body[0].text && /[A-Za-z]/.test(group.body[0].text)) { - node.setAttribute("mathvariant", "italic"); - } - } else { - node = new mathMLTree.MathNode("mo", inner); - } - - // Set spacing based on what is the most likely adjacent atom type. - // See TeXbook p170. - const doSpacing = style.level < 2; // Operator spacing is zero inside a (sub|super)script. - if (group.mclass === "mbin") { - // medium space - node.attributes.lspace = (doSpacing ? "0.2222em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2222em" : "0"); - } else if (group.mclass === "mrel") { - // thickspace - node.attributes.lspace = (doSpacing ? "0.2778em" : "0"); - node.attributes.rspace = (doSpacing ? "0.2778em" : "0"); - } else if (group.mclass === "mpunct") { - node.attributes.lspace = "0em"; - node.attributes.rspace = (doSpacing ? "0.1667em" : "0"); - } else if (group.mclass === "mopen" || group.mclass === "mclose") { - node.attributes.lspace = "0em"; - node.attributes.rspace = "0em"; - } - if (!(group.mclass === "mopen" || group.mclass === "mclose")) { - delete node.attributes.stretchy; - delete node.attributes.form; - } - } - return node; -} - -// Math class commands except \mathop -defineFunction({ - type: "mclass", - names: [ - "\\mathord", - "\\mathbin", - "\\mathrel", - "\\mathopen", - "\\mathclose", - "\\mathpunct", - "\\mathinner" - ], - props: { - numArgs: 1, - primitive: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - const isCharacterBox = utils.isCharacterBox(body); - // We should not wrap a around a or . That would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - let mustPromote = true; - const mord = { type: "mathord", text: "", mode: parser.mode }; - const arr = (body.body) ? body.body : [body]; - for (const arg of arr) { - if (textAtomTypes.includes(arg.type)) { - if (arg.text) { - mord.text += arg.text; - } else if (arg.body) { - arg.body.map(e => { mord.text += e.text; }); - } - } else { - mustPromote = false; - break - } - } - return { - type: "mclass", - mode: parser.mode, - mclass: "m" + funcName.substr(5), - body: ordargument(mustPromote ? mord : body), - isCharacterBox, - mustPromote - }; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -const binrelClass = (arg) => { - // \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument. - // (by rendering separately and with {}s before and after, and measuring - // the change in spacing). We'll do roughly the same by detecting the - // atom type directly. - const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg; - if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) { - return "m" + atom.family; - } else { - return "mord"; - } -}; - -// \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord. -// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX. -defineFunction({ - type: "mclass", - names: ["\\@binrel"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "mclass", - mode: parser.mode, - mclass: binrelClass(args[0]), - body: ordargument(args[1]), - isCharacterBox: utils.isCharacterBox(args[1]) - }; - } -}); - -// Build a relation or stacked op by placing one symbol on top of another -defineFunction({ - type: "mclass", - names: ["\\stackrel", "\\overset", "\\underset"], - props: { - numArgs: 2 - }, - handler({ parser, funcName }, args) { - const baseArg = args[1]; - const shiftedArg = args[0]; - - const baseOp = { - type: "op", - mode: baseArg.mode, - limits: true, - alwaysHandleSupSub: true, - parentIsSupSub: false, - symbol: false, - stack: true, - suppressBaseShift: funcName !== "\\stackrel", - body: ordargument(baseArg) - }; - - return { - type: "supsub", - mode: shiftedArg.mode, - base: baseOp, - sup: funcName === "\\underset" ? null : shiftedArg, - sub: funcName === "\\underset" ? shiftedArg : null - }; - }, - mathmlBuilder: mathmlBuilder$7 -}); - -// Helper function -const buildGroup$1 = (el, style, noneNode) => { - if (!el) { return noneNode } - const node = buildGroup(el, style); - if (node.type === "mrow" && node.children.length === 0) { return noneNode } - return node -}; - -defineFunction({ - type: "multiscript", - names: ["\\sideset", "\\pres@cript"], // See macros.js for \prescript - props: { - numArgs: 3 - }, - handler({ parser, funcName }, args) { - if (args[2].body.length === 0) { - throw new ParseError(funcName + `cannot parse an empty base.`) - } - const base = args[2].body[0]; - if (parser.settings.strict && funcName === "\\sideset" && !base.symbol) { - throw new ParseError(`The base of \\sideset must be a big operator.`) - } - - if ((args[0].body.length > 0 && args[0].body[0].type !== "supsub") || - (args[1].body.length > 0 && args[1].body[0].type !== "supsub")) { - throw new ParseError("\\sideset can parse only subscripts and " + - "superscripts in its first two arguments") - } - - // The prescripts and postscripts come wrapped in a supsub. - const prescripts = args[0].body.length > 0 ? args[0].body[0] : null; - const postscripts = args[1].body.length > 0 ? args[1].body[0] : null; - - if (!prescripts && !postscripts) { - return base - } else if (!prescripts) { - // It's not a multi-script. Get a \textstyle supsub. - return { - type: "styling", - mode: parser.mode, - scriptLevel: "text", - body: [{ - type: "supsub", - mode: parser.mode, - base, - sup: postscripts.sup, - sub: postscripts.sub - }] - } - } else { - return { - type: "multiscript", - mode: parser.mode, - isSideset: funcName === "\\sideset", - prescripts, - postscripts, - base - } - } - }, - mathmlBuilder(group, style) { - const base = buildGroup(group.base, style); - - const prescriptsNode = new mathMLTree.MathNode("mprescripts"); - const noneNode = new mathMLTree.MathNode("none"); - let children = []; - - const preSub = buildGroup$1(group.prescripts.sub, style, noneNode); - const preSup = buildGroup$1(group.prescripts.sup, style, noneNode); - if (group.isSideset) { - // This seems silly, but LaTeX does this. Firefox ignores it, which does not make me sad. - preSub.setAttribute("style", "text-align: left;"); - preSup.setAttribute("style", "text-align: left;"); - } - - if (group.postscripts) { - const postSub = buildGroup$1(group.postscripts.sub, style, noneNode); - const postSup = buildGroup$1(group.postscripts.sup, style, noneNode); - children = [base, postSub, postSup, prescriptsNode, preSub, preSup]; - } else { - children = [base, prescriptsNode, preSub, preSup]; - } - - return new mathMLTree.MathNode("mmultiscripts", children); - } -}); - -defineFunction({ - type: "not", - names: ["\\not"], - props: { - numArgs: 1, - primitive: true, - allowedInText: false - }, - handler({ parser }, args) { - const isCharacterBox = utils.isCharacterBox(args[0]); - let body; - if (isCharacterBox) { - body = ordargument(args[0]); - if (body[0].text.charAt(0) === "\\") { - body[0].text = symbols.math[body[0].text].replace; - } - // \u0338 is the Unicode Combining Long Solidus Overlay - body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1); - } else { - // When the argument is not a character box, TeX does an awkward, poorly placed overlay. - // We'll do the same. - const notNode = { type: "textord", mode: "math", text: "\u0338" }; - const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } }; - body = [notNode, kernNode, args[0]]; - } - return { - type: "not", - mode: parser.mode, - body, - isCharacterBox - }; - }, - mathmlBuilder(group, style) { - if (group.isCharacterBox) { - const inner = buildExpression(group.body, style); - return inner[0] - } else { - return buildExpressionRow(group.body, style, true) - } - } -}); - -// Limits, symbols - -const ordAtomTypes = ["textord", "mathord", "atom"]; - -// Most operators have a large successor symbol, but these don't. -const noSuccessor = ["\\smallint"]; - -// Math operators (e.g. \sin) need a space between these types and themselves: -const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"]; - -// NOTE: Unlike most `builders`s, this one handles not only "op", but also -// "supsub" since some of them (like \int) can affect super/subscripting. - -const mathmlBuilder$8 = (group, style) => { - let node; - - if (group.symbol) { - // This is a symbol. Just add the symbol. - node = new MathNode("mo", [makeText(group.name, group.mode)]); - if (utils.contains(noSuccessor, group.name)) { - node.setAttribute("largeop", "false"); - } else { - node.setAttribute("movablelimits", "false"); - } - } else if (group.body) { - // This is an operator with children. Add them. - node = new MathNode("mo", buildExpression(group.body, style)); - } else { - // This is a text operator. Add all of the characters from the operator's name. - node = new MathNode("mi", [new TextNode$1(group.name.slice(1))]); - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new MathNode("mo", [makeText("\u2061", "text")]); - if (group.needsLeadingSpace) { - const space = new MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node = newDocumentFragment([space, node, operator]); - } else { - node = newDocumentFragment([node, operator]); - } - } - } - - return node; -}; - -const singleCharBigOps = { - "\u220F": "\\prod", - "\u2210": "\\coprod", - "\u2211": "\\sum", - "\u22c0": "\\bigwedge", - "\u22c1": "\\bigvee", - "\u22c2": "\\bigcap", - "\u22c3": "\\bigcup", - "\u2a00": "\\bigodot", - "\u2a01": "\\bigoplus", - "\u2a02": "\\bigotimes", - "\u2a04": "\\biguplus", - "\u2a05": "\\bigsqcap", - "\u2a06": "\\bigsqcup" -}; - -defineFunction({ - type: "op", - names: [ - "\\coprod", - "\\bigvee", - "\\bigwedge", - "\\biguplus", - "\\bigcap", - "\\bigcup", - "\\intop", - "\\prod", - "\\sum", - "\\bigotimes", - "\\bigoplus", - "\\bigodot", - "\\bigsqcap", - "\\bigsqcup", - "\\smallint", - "\u220F", - "\u2210", - "\u2211", - "\u22c0", - "\u22c1", - "\u22c2", - "\u22c3", - "\u2a00", - "\u2a01", - "\u2a02", - "\u2a04", - "\u2a06" - ], - props: { - numArgs: 0 - }, - handler: ({ parser, funcName }, args) => { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharBigOps[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: true, - stack: false, // This is true for \stackrel{}, not here. - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// Note: calling defineFunction with a type that's already been defined only -// works because the same mathmlBuilder is being used. -defineFunction({ - type: "op", - names: ["\\mathop"], - props: { - numArgs: 1, - primitive: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - // It would be convienient to just wrap a around the argument. - // But if the argument is a or , that would be invalid MathML. - // In that case, we instead promote the text contents of the body to the parent. - const arr = (body.body) ? body.body : [body]; - const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type); - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: isSymbol, - stack: false, - name: isSymbol ? arr[0].text : null, - body: isSymbol ? null : ordargument(body) - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// There are 2 flags for operators; whether they produce limits in -// displaystyle, and whether they are symbols and should grow in -// displaystyle. These four groups cover the four possible choices. - -const singleCharIntegrals = { - "\u222b": "\\int", - "\u222c": "\\iint", - "\u222d": "\\iiint", - "\u222e": "\\oint", - "\u222f": "\\oiint", - "\u2230": "\\oiiint", - "\u2231": "\\intclockwise", - "\u2232": "\\varointclockwise", - "\u2a0c": "\\iiiint", - "\u2a0d": "\\intbar", - "\u2a0e": "\\intBar", - "\u2a0f": "\\fint", - "\u2a12": "\\rppolint", - "\u2a13": "\\scpolint", - "\u2a15": "\\pointint", - "\u2a16": "\\sqint", - "\u2a17": "\\intlarhk", - "\u2a18": "\\intx", - "\u2a19": "\\intcap", - "\u2a1a": "\\intcup" -}; - -// No limits, not symbols -defineFunction({ - type: "op", - names: [ - "\\arcsin", - "\\arccos", - "\\arctan", - "\\arctg", - "\\arcctg", - "\\arg", - "\\ch", - "\\cos", - "\\cosec", - "\\cosh", - "\\cot", - "\\cotg", - "\\coth", - "\\csc", - "\\ctg", - "\\cth", - "\\deg", - "\\dim", - "\\exp", - "\\hom", - "\\ker", - "\\lg", - "\\ln", - "\\log", - "\\sec", - "\\sin", - "\\sinh", - "\\sh", - "\\sgn", - "\\tan", - "\\tanh", - "\\tg", - "\\th" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: false, - stack: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// Limits, not symbols -defineFunction({ - type: "op", - names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - const prevAtomType = parser.prevAtomType; - return { - type: "op", - mode: parser.mode, - limits: true, - parentIsSupSub: false, - symbol: false, - stack: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType), - name: funcName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -// No limits, symbols -defineFunction({ - type: "op", - names: [ - "\\int", - "\\iint", - "\\iiint", - "\\iiiint", - "\\oint", - "\\oiint", - "\\oiiint", - "\\intclockwise", - "\\varointclockwise", - "\\intbar", - "\\intBar", - "\\fint", - "\\rppolint", - "\\scpolint", - "\\pointint", - "\\sqint", - "\\intlarhk", - "\\intx", - "\\intcap", - "\\intcup", - "\u222b", - "\u222c", - "\u222d", - "\u222e", - "\u222f", - "\u2230", - "\u2231", - "\u2232", - "\u2a0c", - "\u2a0d", - "\u2a0e", - "\u2a0f", - "\u2a12", - "\u2a13", - "\u2a15", - "\u2a16", - "\u2a17", - "\u2a18", - "\u2a19", - "\u2a1a" - ], - props: { - numArgs: 0 - }, - handler({ parser, funcName }) { - let fName = funcName; - if (fName.length === 1) { - fName = singleCharIntegrals[fName]; - } - return { - type: "op", - mode: parser.mode, - limits: false, - parentIsSupSub: false, - symbol: true, - stack: false, - name: fName - }; - }, - mathmlBuilder: mathmlBuilder$8 -}); - -/** - * All registered global/built-in macros. - * `macros.js` exports this same dictionary again and makes it public. - * `Parser.js` requires this dictionary via `macros.js`. - */ -const _macros = {}; - -// This function might one day accept an additional argument and do more things. -function defineMacro(name, body) { - _macros[name] = body; -} - -// NOTE: Unlike most builders, this one handles not only -// "operatorname", but also "supsub" since \operatorname* can -// affect super/subscripting. - -const mathmlBuilder$9 = (group, style) => { - let expression = buildExpression(group.body, style.withFont("mathrm")); - - // Is expression a string or has it something like a fraction? - let isAllString = true; // default - for (let i = 0; i < expression.length; i++) { - const node = expression[i]; - if (node instanceof mathMLTree.MathNode) { - switch (node.type) { - case "mi": - case "mn": - case "ms": - case "mtext": - break; // Do nothing yet. - case "mspace": - { - if (node.attributes.width) { - const width = node.attributes.width.replace("em", ""); - const ch = spaceCharacter(Number(width)); - if (ch === "") { - isAllString = false; - } else { - expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)]); - } - } - } - break - case "mo": { - const child = node.children[0]; - if (node.children.length === 1 && child instanceof mathMLTree.TextNode) { - child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*"); - } else { - isAllString = false; - } - break - } - default: - isAllString = false; - } - } else { - isAllString = false; - } - } - - if (isAllString) { - // Write a single TextNode instead of multiple nested tags. - const word = expression.map((node) => node.toText()).join(""); - expression = [new mathMLTree.TextNode(word)]; - } else if ( - expression.length === 1 - && utils.contains(["mover", "munder"], expression[0].type) && - (expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext") - ) { - expression[0].children[0].type = "mi"; - if (group.parentIsSupSub) { - return new mathMLTree.MathNode("mrow", expression) - } else { - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - return mathMLTree.newDocumentFragment([expression[0], operator]) - } - } - - let wrapper; - if (isAllString) { - wrapper = new mathMLTree.MathNode("mi", expression); - wrapper.setAttribute("mathvariant", "normal"); - } else { - wrapper = new mathMLTree.MathNode("mrow", expression); - } - - if (!group.parentIsSupSub) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (group.needsLeadingSpace) { - // LaTeX gives operator spacing, but a gets ord spacing. - // So add a leading space. - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - return mathMLTree.newDocumentFragment([space, wrapper, operator]) - } else { - return mathMLTree.newDocumentFragment([wrapper, operator]) - } - } - - return wrapper -}; - -// \operatorname -// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@ -defineFunction({ - type: "operatorname", - names: ["\\operatorname@", "\\operatornamewithlimits"], - props: { - numArgs: 1, - allowedInArgument: true - }, - handler: ({ parser, funcName }, args) => { - const body = args[0]; - const prevAtomType = parser.prevAtomType; - return { - type: "operatorname", - mode: parser.mode, - body: ordargument(body), - alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"), - limits: false, - parentIsSupSub: false, - needsLeadingSpace: prevAtomType.length > 0 && utils.contains(ordTypes, prevAtomType) - }; - }, - mathmlBuilder: mathmlBuilder$9 -}); - -defineMacro("\\operatorname", - "\\@ifstar\\operatornamewithlimits\\operatorname@"); - -defineFunctionBuilders({ - type: "ordgroup", - mathmlBuilder(group, style) { - return buildExpressionRow(group.body, style, true); - } -}); - -defineFunction({ - type: "overline", - names: ["\\overline"], - props: { - numArgs: 1 - }, - handler({ parser }, args) { - const body = args[0]; - return { - type: "overline", - mode: parser.mode, - body - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005F")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode( - "mover", - [buildGroup(group.body, style), operator] - ); - node.setAttribute("accent", "true"); - - return node; - } -}); - -defineFunction({ - type: "phantom", - names: ["\\phantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "phantom", - mode: parser.mode, - body: ordargument(body) - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(group.body, style); - return new mathMLTree.MathNode("mphantom", inner); - } -}); - -defineFunction({ - type: "hphantom", - names: ["\\hphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "hphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("height", "0px"); - node.setAttribute("depth", "0px"); - return node; - } -}); - -defineFunction({ - type: "vphantom", - names: ["\\vphantom"], - props: { - numArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args) => { - const body = args[0]; - return { - type: "vphantom", - mode: parser.mode, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(ordargument(group.body), style); - const phantom = new mathMLTree.MathNode("mphantom", inner); - const node = new mathMLTree.MathNode("mpadded", [phantom]); - node.setAttribute("width", "0px"); - return node; - } -}); - -// \pmb is a simulation of bold font. -// The version of \pmb in ambsy.sty works by typesetting three copies of the argument -// with small offsets. We use CSS text-shadow. -// It's a hack. Not as good as a real bold font. Better than nothing. - -defineFunction({ - type: "pmb", - names: ["\\pmb"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "pmb", - mode: parser.mode, - body: ordargument(args[0]) - } - }, - mathmlBuilder(group, style) { - const inner = buildExpression(group.body, style); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px"); - return node - } -}); - -const sign = num => num >= 0 ? "+" : "-"; - -// \raise, \lower, and \raisebox - -const mathmlBuilder$a = (group, style) => { - const newStyle = style.withLevel(StyleLevel.TEXT); - const node = new mathMLTree.MathNode("mpadded", [buildGroup(group.body, newStyle)]); - const dy = calculateSize(group.dy, style); - node.setAttribute("voffset", dy.number + dy.unit); - const dyAbs = Math.abs(dy.number); - node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit); - node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit); - return node -}; - -defineFunction({ - type: "raise", - names: ["\\raise", "\\lower"], - props: { - numArgs: 2, - argTypes: ["size", "primitive"], - primitive: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - if (funcName === "\\lower") { amount.number *= -1; } - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - - -defineFunction({ - type: "raise", - names: ["\\raisebox"], - props: { - numArgs: 2, - argTypes: ["size", "hbox"], - allowedInText: true - }, - handler({ parser, funcName }, args) { - const amount = assertNodeType(args[0], "size").value; - const body = args[1]; - return { - type: "raise", - mode: parser.mode, - dy: amount, - body - }; - }, - mathmlBuilder: mathmlBuilder$a -}); - -defineFunction({ - type: "ref", - names: ["\\ref", "\\eqref"], - props: { - numArgs: 1, - argTypes: ["raw"] - }, - handler({ parser, funcName }, args) { - return { - type: "ref", - mode: parser.mode, - funcName, - string: args[0].string.replace(invalidIdRegEx, "") - }; - }, - mathmlBuilder(group, style) { - // Create an empty text node. Set a class and an href. - // The post-processor will populate with the target's tag or equation number. - const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"]; - const node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("")], classes); - node.setAttribute("href", "#" + group.string); - return node - } -}); - -defineFunction({ - type: "internal", - names: ["\\relax"], - props: { - numArgs: 0, - allowedInText: true - }, - handler({ parser }) { - return { - type: "internal", - mode: parser.mode - }; - } -}); - -defineFunction({ - type: "rule", - names: ["\\rule"], - props: { - numArgs: 2, - numOptionalArgs: 1, - argTypes: ["size", "size", "size"] - }, - handler({ parser }, args, optArgs) { - const shift = optArgs[0]; - const width = assertNodeType(args[0], "size"); - const height = assertNodeType(args[1], "size"); - return { - type: "rule", - mode: parser.mode, - shift: shift && assertNodeType(shift, "size").value, - width: width.value, - height: height.value - }; - }, - mathmlBuilder(group, style) { - const width = calculateSize(group.width, style); - const height = calculateSize(group.height, style); - const shift = group.shift - ? calculateSize(group.shift, style) - : { number: 0, unit: "em" }; - const color = (style.color && style.getColor()) || "black"; - - const rule = new mathMLTree.MathNode("mspace"); - rule.setAttribute("mathbackground", color); - rule.setAttribute("width", width.number + width.unit); - rule.setAttribute("height", height.number + height.unit); - - const wrapper = new mathMLTree.MathNode("mpadded", [rule]); - if (shift.number >= 0) { - wrapper.setAttribute("height", "+" + shift.number + shift.unit); - } else { - wrapper.setAttribute("height", shift.number + shift.unit); - wrapper.setAttribute("depth", "+" + -shift.number + shift.unit); - } - wrapper.setAttribute("voffset", shift.number + shift.unit); - return wrapper; - } -}); - -// The size mappings are taken from TeX with \normalsize=10pt. -// We don't have to track script level. MathML does that. -const sizeMap = { - "\\tiny": 0.5, - "\\sixptsize": 0.6, - "\\Tiny": 0.6, - "\\scriptsize": 0.7, - "\\footnotesize": 0.8, - "\\small": 0.9, - "\\normalsize": 1.0, - "\\large": 1.2, - "\\Large": 1.44, - "\\LARGE": 1.728, - "\\huge": 2.074, - "\\Huge": 2.488 -}; - -defineFunction({ - type: "sizing", - names: [ - "\\tiny", - "\\sixptsize", - "\\Tiny", - "\\scriptsize", - "\\footnotesize", - "\\small", - "\\normalsize", - "\\large", - "\\Large", - "\\LARGE", - "\\huge", - "\\Huge" - ], - props: { - numArgs: 0, - allowedInText: true - }, - handler: ({ breakOnTokenText, funcName, parser }, args) => { - const body = parser.parseExpression(false, breakOnTokenText); - return { - type: "sizing", - mode: parser.mode, - funcName, - body - }; - }, - mathmlBuilder: (group, style) => { - const inner = buildExpression(group.body, style); - // Wrap with an element. - const node = wrapWithMstyle(inner); - node.setAttribute("mathsize", sizeMap[group.funcName] + "em"); - return node; - } -}); - -// smash, with optional [tb], as in AMS - -defineFunction({ - type: "smash", - names: ["\\smash"], - props: { - numArgs: 1, - numOptionalArgs: 1, - allowedInText: true - }, - handler: ({ parser }, args, optArgs) => { - let smashHeight = false; - let smashDepth = false; - const tbArg = optArgs[0] && assertNodeType(optArgs[0], "ordgroup"); - if (tbArg) { - // Optional [tb] argument is engaged. - // ref: amsmath: \renewcommand{\smash}[1][tb]{% - // def\mb@t{\ht}\def\mb@b{\dp}\def\mb@tb{\ht\z@\z@\dp}% - let letter = ""; - for (let i = 0; i < tbArg.body.length; ++i) { - const node = tbArg.body[i]; - // TODO: Write an AssertSymbolNode - letter = node.text; - if (letter === "t") { - smashHeight = true; - } else if (letter === "b") { - smashDepth = true; - } else { - smashHeight = false; - smashDepth = false; - break; - } - } - } else { - smashHeight = true; - smashDepth = true; - } - - const body = args[0]; - return { - type: "smash", - mode: parser.mode, - body, - smashHeight, - smashDepth - }; - }, - mathmlBuilder: (group, style) => { - const node = new mathMLTree.MathNode("mpadded", [buildGroup(group.body, style)]); - - if (group.smashHeight) { - node.setAttribute("height", "0px"); - } - - if (group.smashDepth) { - node.setAttribute("depth", "0px"); - } - - return node; - } -}); - -defineFunction({ - type: "sqrt", - names: ["\\sqrt"], - props: { - numArgs: 1, - numOptionalArgs: 1 - }, - handler({ parser }, args, optArgs) { - const index = optArgs[0]; - const body = args[0]; - return { - type: "sqrt", - mode: parser.mode, - body, - index - }; - }, - mathmlBuilder(group, style) { - const { body, index } = group; - return index - ? new mathMLTree.MathNode("mroot", [ - buildGroup(body, style), - buildGroup(index, style.incrementLevel()) - ]) - : new mathMLTree.MathNode("msqrt", [buildGroup(body, style)]); - } -}); - -const styleMap = { - display: 0, - text: 1, - script: 2, - scriptscript: 3 -}; - -const styleAttributes = { - display: ["0", "true"], - text: ["0", "false"], - script: ["1", "false"], - scriptscript: ["2", "false"] -}; - -defineFunction({ - type: "styling", - names: ["\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"], - props: { - numArgs: 0, - allowedInText: true, - primitive: true - }, - handler({ breakOnTokenText, funcName, parser }, args) { - // parse out the implicit body - const body = parser.parseExpression(true, breakOnTokenText); - - const scriptLevel = funcName.slice(1, funcName.length - 5); - return { - type: "styling", - mode: parser.mode, - // Figure out what scriptLevel to use by pulling out the scriptLevel from - // the function name - scriptLevel, - body - }; - }, - mathmlBuilder(group, style) { - // Figure out what scriptLevel we're changing to. - const newStyle = style.withLevel(styleMap[group.scriptLevel]); - // The style argument in the next line does NOT directly set a MathML script level. - // It just tracks the style level, in case we need to know it for supsub or mathchoice. - const inner = buildExpression(group.body, newStyle); - // Wrap with an element. - const node = wrapWithMstyle(inner); - - const attr = styleAttributes[group.scriptLevel]; - - // Here is where we set the MathML script level. - node.setAttribute("scriptlevel", attr[0]); - node.setAttribute("displaystyle", attr[1]); - - return node; - } -}); - -/** - * Sometimes, groups perform special rules when they have superscripts or - * subscripts attached to them. This function lets the `supsub` group know that - * Sometimes, groups perform special rules when they have superscripts or - * its inner element should handle the superscripts and subscripts instead of - * handling them itself. - */ - -// Helpers -const symbolRegEx = /^m(over|under|underover)$/; - -// Super scripts and subscripts, whose precise placement can depend on other -// functions that precede them. -defineFunctionBuilders({ - type: "supsub", - mathmlBuilder(group, style) { - // Is the inner group a relevant horizonal brace? - let isBrace = false; - let isOver; - let isSup; - let appendApplyFunction = false; - let needsLeadingSpace = false; - - if (group.base && group.base.type === "horizBrace") { - isSup = !!group.sup; - if (isSup === group.base.isOver) { - isBrace = true; - isOver = group.base.isOver; - } - } - - if (group.base && !group.base.stack && - (group.base.type === "op" || group.base.type === "operatorname")) { - group.base.parentIsSupSub = true; - appendApplyFunction = !group.base.symbol; - needsLeadingSpace = group.base.needsLeadingSpace; - } - - const children = group.base && group.base.stack - ? [buildGroup(group.base.body[0], style)] - : [buildGroup(group.base, style)]; - - const childStyle = style.inSubOrSup(); - if (group.sub) { - children.push(buildGroup(group.sub, childStyle)); - } - - if (group.sup) { - children.push(buildGroup(group.sup, childStyle)); - } - - let nodeType; - if (isBrace) { - nodeType = isOver ? "mover" : "munder"; - } else if (!group.sub) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "mover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "mover"; - } else { - nodeType = "msup"; - } - } else if (!group.sup) { - const base = group.base; - if ( - base && - base.type === "op" && - base.limits && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munder"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (base.limits || style.level === StyleLevel.DISPLAY) - ) { - nodeType = "munder"; - } else { - nodeType = "msub"; - } - } else { - const base = group.base; - if (base && ((base.type === "op" && base.limits) || base.type === "multiscript") && - (style.level === StyleLevel.DISPLAY || base.alwaysHandleSupSub) - ) { - nodeType = "munderover"; - } else if ( - base && - base.type === "operatorname" && - base.alwaysHandleSupSub && - (style.level === StyleLevel.DISPLAY || base.limits) - ) { - nodeType = "munderover"; - } else { - nodeType = "msubsup"; - } - } - - let node = new mathMLTree.MathNode(nodeType, children); - if (appendApplyFunction) { - // Append an . - // ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4 - const operator = new mathMLTree.MathNode("mo", [makeText("\u2061", "text")]); - if (needsLeadingSpace) { - const space = new mathMLTree.MathNode("mspace"); - space.setAttribute("width", "0.1667em"); // thin space. - node = mathMLTree.newDocumentFragment([space, node, operator]); - } else { - node = mathMLTree.newDocumentFragment([node, operator]); - } - } else if (symbolRegEx.test(nodeType)) { - // Wrap in a . Otherwise Firefox stretchy parens will not stretch to include limits. - node = new mathMLTree.MathNode("mrow", [node]); - } - - return node - } -}); - -// Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js. - -const short = ["\\shortmid", "\\nshortmid", "\\shortparallel", - "\\nshortparallel", "\\smallsetminus"]; - -defineFunctionBuilders({ - type: "atom", - mathmlBuilder(group, style) { - const node = new mathMLTree.MathNode("mo", [makeText(group.text, group.mode)]); - if (group.family === "punct") { - node.setAttribute("separator", "true"); - } else if (group.family === "open" || group.family === "close") { - // Delims built here should not stretch vertically. - // See delimsizing.js for stretchy delims. - if (group.family === "open") { - node.setAttribute("form", "prefix"); - // Set an explicit attribute for stretch. Otherwise Firefox may do it wrong. - node.setAttribute("stretchy", "false"); - } else if (group.family === "close") { - node.setAttribute("form", "postfix"); - node.setAttribute("stretchy", "false"); - } - } else if (group.text === "\\mid") { - // Firefox messes up this spacing if at the end of an . See it explicitly. - node.setAttribute("lspace", "0.22em"); // medium space - node.setAttribute("rspace", "0.22em"); - node.setAttribute("stretchy", "false"); - } else if (short.includes(group.text)) { - node.setAttribute("mathsize", "70%"); - } else if (group.text === ":") { - // ":" is not in the MathML operator dictionary. Give it BIN spacing. - node.attributes.lspace = "0.2222em"; - node.attributes.rspace = "0.2222em"; - } - return node; - } -}); - -/** - * Maps TeX font commands to "mathvariant" attribute in buildMathML.js - */ -const fontMap = { - // styles - mathbf: "bold", - mathrm: "normal", - textit: "italic", - mathit: "italic", - mathnormal: "italic", - - // families - mathbb: "double-struck", - mathcal: "script", - mathfrak: "fraktur", - mathscr: "script", - mathsf: "sans-serif", - mathtt: "monospace", - oldstylenums: "oldstylenums" -}; - -/** - * Returns the math variant as a string or null if none is required. - */ -const getVariant = function(group, style) { - // Handle font specifiers as best we can. - // Chromium does not support the MathML mathvariant attribute. - // So we'll use Unicode replacement characters instead. - // But first, determine the math variant. - - // Deal with the \textit, \textbf, etc., functions. - if (style.fontFamily === "texttt") { - return "monospace" - } else if (style.fontFamily === "textsc") { - return "normal"; // handled via character substitution in symbolsOrd.js. - } else if (style.fontFamily === "textsf") { - if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "sans-serif-bold-italic" - } else if (style.fontShape === "textit") { - return "sans-serif-italic" - } else if (style.fontWeight === "textbf") { - return "sans-serif-bold" - } else { - return "sans-serif" - } - } else if (style.fontShape === "textit" && style.fontWeight === "textbf") { - return "bold-italic" - } else if (style.fontShape === "textit") { - return "italic" - } else if (style.fontWeight === "textbf") { - return "bold" - } - - // Deal with the \mathit, mathbf, etc, functions. - const font = style.font; - if (!font || font === "mathnormal") { - return null - } - - const mode = group.mode; - switch (font) { - case "mathit": - return "italic" - case "mathrm": { - const codePoint = group.text.codePointAt(0); - // LaTeX \mathrm returns italic for Greek characters. - return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal" - } - case "greekItalic": - return "italic" - case "up@greek": - return "normal" - case "boldsymbol": - case "mathboldsymbol": - return "bold-italic" - case "mathbf": - return "bold" - case "mathbb": - return "double-struck" - case "mathfrak": - return "fraktur" - case "mathscr": - case "mathcal": - return "script" - case "mathsf": - return "sans-serif" - case "mathtt": - return "monospace" - case "oldstylenums": - return "oldstylenums" - } - - let text = group.text; - if (symbols[mode][text] && symbols[mode][text].replace) { - text = symbols[mode][text].replace; - } - - return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null -}; - -// Chromium does not support the MathML `mathvariant` attribute. -// Instead, we replace ASCII characters with Unicode characters that -// are defined in the font as bold, italic, double-struck, etc. -// This module identifies those Unicode code points. - -// First, a few helpers. -const script = Object.freeze({ - B: 0x20EA, // Offset from ASCII B to Unicode script B - E: 0x20EB, - F: 0x20EB, - H: 0x20C3, - I: 0x20C7, - L: 0x20C6, - M: 0x20E6, - R: 0x20C9, - e: 0x20CA, - g: 0x20A3, - o: 0x20C5 -}); - -const frak = Object.freeze({ - C: 0x20EA, - H: 0x20C4, - I: 0x20C8, - R: 0x20CA, - Z: 0x20CE -}); - -const bbb = Object.freeze({ - C: 0x20BF, // blackboard bold - H: 0x20C5, - N: 0x20C7, - P: 0x20C9, - Q: 0x20C9, - R: 0x20CB, - Z: 0x20CA -}); - -const bold = Object.freeze({ - "\u03f5": 0x1D2E7, // lunate epsilon - "\u03d1": 0x1D30C, // vartheta - "\u03f0": 0x1D2EE, // varkappa - "\u03c6": 0x1D319, // varphi - "\u03f1": 0x1D2EF, // varrho - "\u03d6": 0x1D30B // varpi -}); - -const boldItalic = Object.freeze({ - "\u03f5": 0x1D35B, // lunate epsilon - "\u03d1": 0x1D380, // vartheta - "\u03f0": 0x1D362, // varkappa - "\u03c6": 0x1D38D, // varphi - "\u03f1": 0x1D363, // varrho - "\u03d6": 0x1D37F // varpi -}); - -const boldsf = Object.freeze({ - "\u03f5": 0x1D395, // lunate epsilon - "\u03d1": 0x1D3BA, // vartheta - "\u03f0": 0x1D39C, // varkappa - "\u03c6": 0x1D3C7, // varphi - "\u03f1": 0x1D39D, // varrho - "\u03d6": 0x1D3B9 // varpi -}); - -const bisf = Object.freeze({ - "\u03f5": 0x1D3CF, // lunate epsilon - "\u03d1": 0x1D3F4, // vartheta - "\u03f0": 0x1D3D6, // varkappa - "\u03c6": 0x1D401, // varphi - "\u03f1": 0x1D3D7, // varrho - "\u03d6": 0x1D3F3 // varpi -}); - -// Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf -const offset = Object.freeze({ - upperCaseLatin: { // A-Z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3BF }, - "italic": ch => { return 0x1D3F3 }, - "bold-italic": ch => { return 0x1D427 }, - "script": ch => { return script[ch] || 0x1D45B }, - "script-bold": ch => { return 0x1D48F }, - "fraktur": ch => { return frak[ch] || 0x1D4C3 }, - "fraktur-bold": ch => { return 0x1D52B }, - "double-struck": ch => { return bbb[ch] || 0x1D4F7 }, - "sans-serif": ch => { return 0x1D55F }, - "sans-serif-bold": ch => { return 0x1D593 }, - "sans-serif-italic": ch => { return 0x1D5C7 }, - "sans-serif-bold-italic": ch => { return 0x1D63C }, - "monospace": ch => { return 0x1D62F } - }, - lowerCaseLatin: { // a-z - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D3B9 }, - "italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED }, - "bold-italic": ch => { return 0x1D421 }, - "script": ch => { return script[ch] || 0x1D455 }, - "script-bold": ch => { return 0x1D489 }, - "fraktur": ch => { return 0x1D4BD }, - "fraktur-bold": ch => { return 0x1D525 }, - "double-struck": ch => { return 0x1D4F1 }, - "sans-serif": ch => { return 0x1D559 }, - "sans-serif-bold": ch => { return 0x1D58D }, - "sans-serif-italic": ch => { return 0x1D5C1 }, - "sans-serif-bold-italic": ch => { return 0x1D5F5 }, - "monospace": ch => { return 0x1D629 } - }, - upperCaseGreek: { // A-Ω ∇ - "normal": ch => { return 0 }, - "bold": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "italic": ch => { return ch === "∇" ? 0x1B4F4 : 0x1D351 }, - // \boldsymbol actually returns upright bold for upperCaseGreek - "bold-italic": ch => { return ch === "∇" ? 0x1B4BA : 0x1D317 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-bold": ch => { return ch === "∇" ? 0x1B568 : 0x1D3C5 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return ch === "∇" ? 0x1B5A2 : 0x1D3FF }, - "monospace": ch => { return 0 } - }, - lowerCaseGreek: { // α-ω - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D311 }, - "italic": ch => { return 0x1D34B }, - "bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - // Unicode has no code points for regular-weight san-serif Greek. Use bold. - "sans-serif": ch => { return 0x1D3BF }, - "sans-serif-bold": ch => { return 0x1D3BF }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0x1D3F9 }, - "monospace": ch => { return 0 } - }, - varGreek: { // \varGamma, etc - "normal": ch => { return 0 }, - "bold": ch => { return bold[ch] || -51 }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return boldItalic[ch] || 0x3A }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0 }, - "sans-serif": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-bold": ch => { return boldsf[ch] || 0x74 }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE }, - "monospace": ch => { return 0 } - }, - numeral: { // 0-9 - "normal": ch => { return 0 }, - "bold": ch => { return 0x1D79E }, - "italic": ch => { return 0 }, - "bold-italic": ch => { return 0 }, - "script": ch => { return 0 }, - "script-bold": ch => { return 0 }, - "fraktur": ch => { return 0 }, - "fraktur-bold": ch => { return 0 }, - "double-struck": ch => { return 0x1D7A8 }, - "sans-serif": ch => { return 0x1D7B2 }, - "sans-serif-bold": ch => { return 0x1D7BC }, - "sans-serif-italic": ch => { return 0 }, - "sans-serif-bold-italic": ch => { return 0 }, - "monospace": ch => { return 0x1D7C6 } - } -}); - -const variantChar = (ch, variant) => { - const codePoint = ch.codePointAt(0); - const block = 0x40 < codePoint && codePoint < 0x5b - ? "upperCaseLatin" - : 0x60 < codePoint && codePoint < 0x7b - ? "lowerCaseLatin" - : (0x390 < codePoint && codePoint < 0x3AA) || ch === "∇" - ? "upperCaseGreek" - : 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5" - ? "lowerCaseGreek" - : 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch] - ? "varGreek" - : (0x2F < codePoint && codePoint < 0x3A) - ? "numeral" - : "other"; - return block === "other" - ? ch - : String.fromCodePoint(codePoint + offset[block][variant](ch)) -}; - -const smallCaps = Object.freeze({ - a: "ᴀ", - b: "ʙ", - c: "ᴄ", - d: "ᴅ", - e: "ᴇ", - f: "ꜰ", - g: "ɢ", - h: "ʜ", - i: "ɪ", - j: "ᴊ", - k: "ᴋ", - l: "ʟ", - m: "ᴍ", - n: "ɴ", - o: "ᴏ", - p: "ᴘ", - q: "ǫ", - r: "ʀ", - s: "s", - t: "ᴛ", - u: "ᴜ", - v: "ᴠ", - w: "ᴡ", - x: "x", - y: "ʏ", - z: "ᴢ" -}); - -// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in -// src/symbols.js. - -const numberRegEx = /^\d[\d.]*$/; // Keep in sync with numberRegEx in Parser.js - -const italicNumber = (text, variant) => { - const mn = new mathMLTree.MathNode("mn", [text]); - const wrapper = new mathMLTree.MathNode("mstyle", [mn]); - wrapper.style["font-style"] = "italic"; - wrapper.style["font-family"] = "Cambria, 'Times New Roman', serif"; - if (variant === "bold-italic") { wrapper.style["font-weight"] = "bold"; } - return wrapper -}; - -defineFunctionBuilders({ - type: "mathord", - mathmlBuilder(group, style) { - const text = makeText(group.text, group.mode, style); - const codePoint = text.text.codePointAt(0); - // Test for upper-case Greek - const defaultVariant = (0x0390 < codePoint && codePoint < 0x03aa) ? "normal" : "italic"; - const variant = getVariant(group, style) || defaultVariant; - if (variant === "script") { - text.text = variantChar(text.text, variant); - return new mathMLTree.MathNode("mi", [text], [style.font]) - } else if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - const node = new mathMLTree.MathNode("mi", [text]); - // TODO: Handle U+1D49C - U+1D4CF per https://www.unicode.org/charts/PDF/U1D400.pdf - if (variant === "normal") { - node.setAttribute("mathvariant", "normal"); - } - return node - } -}); - -defineFunctionBuilders({ - type: "textord", - mathmlBuilder(group, style) { - let ch = group.text; - const codePoint = ch.codePointAt(0); - if (style.fontFamily === "textsc") { - // Convert small latin letters to small caps. - if (96 < codePoint && codePoint < 123) { - ch = smallCaps[ch]; - } - } - const text = makeText(ch, group.mode, style); - const variant = getVariant(group, style) || "normal"; - - let node; - if (group.mode === "text") { - if (variant === "italic" || variant === "bold-italic") { - if (numberRegEx.test(group.text)) { - return italicNumber(text, variant) - } - } - if (variant !== "normal") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mtext", [text]); - } else if (numberRegEx.test(group.text)) { - if (variant === "oldstylenums") { - const ms = new mathMLTree.MathNode("mstyle", [text], ["oldstylenums"]); - node = new mathMLTree.MathNode("mn", [ms]); - } else if (variant === "italic" || variant === "bold-italic") { - return italicNumber(text, variant) - } else { - if (variant !== "normal") { - text.text = text.text.split("").map(c => variantChar(c, variant)).join(""); - } - node = new mathMLTree.MathNode("mn", [text]); - } - } else if (group.text === "\\prime") { - node = new mathMLTree.MathNode("mo", [text]); - } else { - const origText = text.text; - if (variant !== "italic") { - text.text = variantChar(text.text, variant); - } - node = new mathMLTree.MathNode("mi", [text]); - if (text.text === origText ) { - node.setAttribute("mathvariant", "italic"); - } - } - return node - } -}); - -// A map of CSS-based spacing functions to their CSS class. -const cssSpace = { - "\\nobreak": "nobreak", - "\\allowbreak": "allowbreak" -}; - -// A lookup table to determine whether a spacing function/symbol should be -// treated like a regular space character. If a symbol or command is a key -// in this table, then it should be a regular space character. Furthermore, -// the associated value may have a `className` specifying an extra CSS class -// to add to the created `span`. -const regularSpace = { - " ": {}, - "\\ ": {}, - "~": { - className: "nobreak" - }, - "\\space": {}, - "\\nobreakspace": { - className: "nobreak" - } -}; - -// ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in -// src/symbols.js. -defineFunctionBuilders({ - type: "spacing", - mathmlBuilder(group, style) { - let node; - - if (Object.prototype.hasOwnProperty.call(regularSpace, group.text)) { - // Firefox does not render a space in a . So write a no-break space. - // TODO: If Firefox fixes that bug, uncomment the next line and write ch into the node. - //const ch = (regularSpace[group.text].className === "nobreak") ? "\u00a0" : " " - node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("\u00a0")]); - } else if (Object.prototype.hasOwnProperty.call(cssSpace, group.text)) { - // MathML 3.0 calls for nobreak to occur in an , not an - // Ref: https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs - node = new mathMLTree.MathNode("mo"); - if (group.text === "\\nobreak") { - node.setAttribute("linebreak", "nobreak"); - } - } else { - throw new ParseError(`Unknown type of space "${group.text}"`) - } - - return node - } -}); - -defineFunctionBuilders({ - type: "tag" -}); - -// For a \tag, the work usually done in a mathmlBuilder is instead done in buildMathML.js. -// That way, a \tag can be pulled out of the parse tree and wrapped around the outer node. - -// Non-mathy text, possibly in a font -const textFontFamilies = { - "\\text": undefined, - "\\textrm": "textrm", - "\\textsf": "textsf", - "\\texttt": "texttt", - "\\textnormal": "textrm", - "\\textsc": "textsc" // small caps -}; - -const textFontWeights = { - "\\textbf": "textbf", - "\\textmd": "textmd" -}; - -const textFontShapes = { - "\\textit": "textit", - "\\textup": "textup" -}; - -const styleWithFont = (group, style) => { - const font = group.font; - // Checks if the argument is a font family or a font style. - if (!font) { - return style; - } else if (textFontFamilies[font]) { - return style.withTextFontFamily(textFontFamilies[font]); - } else if (textFontWeights[font]) { - return style.withTextFontWeight(textFontWeights[font]); - } else { - return style.withTextFontShape(textFontShapes[font]); - } -}; - -defineFunction({ - type: "text", - names: [ - // Font families - "\\text", - "\\textrm", - "\\textsf", - "\\texttt", - "\\textnormal", - "\\textsc", - // Font weights - "\\textbf", - "\\textmd", - // Font Shapes - "\\textit", - "\\textup" - ], - props: { - numArgs: 1, - argTypes: ["text"], - allowedInArgument: true, - allowedInText: true - }, - handler({ parser, funcName }, args) { - const body = args[0]; - return { - type: "text", - mode: parser.mode, - body: ordargument(body), - font: funcName - }; - }, - mathmlBuilder(group, style) { - const newStyle = styleWithFont(group, style); - const mrow = buildExpressionRow(group.body, newStyle); - - // If possible, consolidate adjacent elements into a single element. - // First, check if it is possible. If not, return the . - if (mrow.type !== "mrow") { return mrow } - if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{} - const mtext = mrow.children[0]; - if (!mtext.attributes || mtext.type !== "mtext") { return mrow } - const variant = mtext.attributes.mathvariant || ""; - for (let i = 1; i < mrow.children.length; i++) { - const localVariant = mrow.children[i].attributes.mathvariant || ""; - if (localVariant !== variant || mrow.children[i].type !== "mtext") { return mrow } - } - - // Consolidate the elements. - for (let i = 1; i < mrow.children.length; i++) { - mtext.children[0].text += mrow.children[i].children[0].text; - } - mtext.children.splice(1, mtext.children.length - 1); - // Firefox does not render a space at either end of the string. - // To get proper rendering, we replace with no-break spaces. - if (mtext.children[0].text.charAt(0) === " ") { - mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1); - } - const L = mtext.children[0].text.length; - if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") { - mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0"; - } - return mtext - } -}); - -// Two functions included to enable migration from Mathjax. - -defineFunction({ - type: "tip", - names: ["\\mathtip"], - props: { - numArgs: 2 - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup(group.body, style); - const tip = buildGroup(group.tip, style); - // Browsers don't support the tooltip actiontype. - // TODO: Come back and fix \mathtip when it can be done via CSS w/o a JS event. - const node = new mathMLTree.MathNode("maction", [math, tip], ["tml-tip"]); - node.setAttribute("actiontype", "tooltip"); - return node - } -}); - -defineFunction({ - type: "tip", - names: ["\\texttip"], - props: { - numArgs: 2, - argTypes: ["math", "text"] - }, - handler({ parser }, args) { - return { - type: "tip", - mode: parser.mode, - body: args[0], - tip: args[1] - }; - }, - mathmlBuilder: (group, style) => { - const math = buildGroup(group.body, style); - const tip = buildGroup(group.tip, style); - // args[1] only accepted text, so tip is a element or a of them. - let str = ""; - if (tip.type === "mtext") { - str = tip.children[0].text; - } else { - for (const child of tip.children) { - str += child.children[0].text; - } - } - // Implement \texttip via a title attribute. - math.setAttribute("title", str); - return math - } -}); - -defineFunctionBuilders({ - type: "toggle", - mathmlBuilder(group, style) { - const expression = buildExpression(group.body, style); - const node = new mathMLTree.MathNode("maction", expression, [], { cursor: "default" }); - node.setAttribute("actiontype", "toggle"); - return node - } -}); - -defineFunction({ - type: "underline", - names: ["\\underline"], - props: { - numArgs: 1, - allowedInText: true - }, - handler({ parser }, args) { - return { - type: "underline", - mode: parser.mode, - body: args[0] - }; - }, - mathmlBuilder(group, style) { - const operator = new mathMLTree.MathNode("mo", [new mathMLTree.TextNode("\u005f")]); - operator.setAttribute("stretchy", "true"); - - const node = new mathMLTree.MathNode("munder", - [buildGroup(group.body, style), operator] - ); - node.setAttribute("accentunder", "true"); - - return node; - } -}); - -defineFunction({ - type: "verb", - names: ["\\verb"], - props: { - numArgs: 0, - allowedInText: true - }, - handler(context, args, optArgs) { - // \verb and \verb* are dealt with directly in Parser.js. - // If we end up here, it's because of a failure to match the two delimiters - // in the regex in Lexer.js. LaTeX raises the following error when \verb is - // terminated by end of line (or file). - throw new ParseError("\\verb ended by end of line instead of matching delimiter"); - }, - mathmlBuilder(group, style) { - const text = new mathMLTree.TextNode(makeVerb(group)); - const node = new mathMLTree.MathNode("mtext", [text]); - node.setAttribute("mathvariant", "monospace"); - return node; - } -}); - -/** - * Converts verb group into body string. - * - * \verb* replaces each space with an open box \u2423 - * \verb replaces each space with a no-break space \xA0 - */ -const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0"); - -/** Include this to ensure that all functions are defined. */ - -const functions = _functions; - -/** - * Lexing or parsing positional information for error reporting. - * This object is immutable. - */ -class SourceLocation { - constructor(lexer, start, end) { - this.lexer = lexer; // Lexer holding the input string. - this.start = start; // Start offset, zero-based inclusive. - this.end = end; // End offset, zero-based exclusive. - } - - /** - * Merges two `SourceLocation`s from location providers, given they are - * provided in order of appearance. - * - Returns the first one's location if only the first is provided. - * - Returns a merged range of the first and the last if both are provided - * and their lexers match. - * - Otherwise, returns null. - */ - static range(first, second) { - if (!second) { - return first && first.loc; - } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) { - return null; - } else { - return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end); - } - } -} - -/** - * Interface required to break circular dependency between Token, Lexer, and - * ParseError. - */ - -/** - * The resulting token returned from `lex`. - * - * It consists of the token text plus some position information. - * The position information is essentially a range in an input string, - * but instead of referencing the bare input string, we refer to the lexer. - * That way it is possible to attach extra metadata to the input string, - * like for example a file name or similar. - * - * The position information is optional, so it is OK to construct synthetic - * tokens if appropriate. Not providing available position information may - * lead to degraded error reporting, though. - */ -class Token { - constructor( - text, // the text of this token - loc - ) { - this.text = text; - this.loc = loc; - } - - /** - * Given a pair of tokens (this and endToken), compute a `Token` encompassing - * the whole input range enclosed by these two. - */ - range( - endToken, // last token of the range, inclusive - text // the text of the newly constructed token - ) { - return new Token(text, SourceLocation.range(this, endToken)); - } -} - -/** - * The Lexer class handles tokenizing the input in various ways. Since our - * parser expects us to be able to backtrack, the lexer allows lexing from any - * given starting point. - * - * Its main exposed function is the `lex` function, which takes a position to - * lex from and a type of token to lex. It defers to the appropriate `_innerLex` - * function. - * - * The various `_innerLex` functions perform the actual lexing of different - * kinds. - */ - -/* The following tokenRegex - * - matches typical whitespace (but not NBSP etc.) using its first two groups - * - does not match any control character \x00-\x1f except whitespace - * - does not match a bare backslash - * - matches any ASCII character except those just mentioned - * - does not match the BMP private use area \uE000-\uF8FF - * - does not match bare surrogate code units - * - matches any BMP character except for those just described - * - matches any valid Unicode surrogate pair - * - mathches numerals - * - matches a backslash followed by one or more whitespace characters - * - matches a backslash followed by one or more letters then whitespace - * - matches a backslash followed by any BMP character - * Capturing groups: - * [1] regular whitespace - * [2] backslash followed by whitespace - * [3] anything else, which may include: - * [4] left character of \verb* - * [5] left character of \verb - * [6] backslash followed by word, excluding any trailing whitespace - * Just because the Lexer matches something doesn't mean it's valid input: - * If there is no matching function or symbol definition, the Parser will - * still reject the input. - */ -const spaceRegexString = "[ \r\n\t]"; -const controlWordRegexString = "\\\\[a-zA-Z@]+"; -const controlSymbolRegexString = "\\\\[^\uD800-\uDFFF]"; -const controlWordWhitespaceRegexString = `(${controlWordRegexString})${spaceRegexString}*`; -const controlSpaceRegexString = "\\\\(\n|[ \r\t]+\n?)[ \r\t]*"; -const combiningDiacriticalMarkString = "[\u0300-\u036f]"; -const combiningDiacriticalMarksEndRegex = new RegExp(`${combiningDiacriticalMarkString}+$`); -const tokenRegexString = - `(${spaceRegexString}+)|` + // whitespace - `${controlSpaceRegexString}|` + // whitespace - "(\\d[\\d.]*" + // numbers (in non-strict mode) - "|[!-\\[\\]-\u2027\u202A-\uD7FF\uF900-\uFFFF]" + // single codepoint - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|[\uD800-\uDBFF][\uDC00-\uDFFF]" + // surrogate pair - `${combiningDiacriticalMarkString}*` + // ...plus accents - "|\\\\verb\\*([^]).*?\\4" + // \verb* - "|\\\\verb([^*a-zA-Z]).*?\\5" + // \verb unstarred - `|${controlWordWhitespaceRegexString}` + // \macroName + spaces - `|${controlSymbolRegexString})`; // \\, \', etc. - -/** Main Lexer class */ -class Lexer { - constructor(input, settings) { - // Separate accents from characters - this.input = input; - this.settings = settings; - this.tokenRegex = new RegExp( - // Strict Temml, like TeX, lexes one numeral at a time. - // Default Temml lexes contiguous numerals into a single element. - tokenRegexString.replace("\\d[\\d.]*|", settings.strict ? "" : "\\d[\\d.]*|"), - "g" - ); - // Category codes. The lexer only supports comment characters (14) for now. - // MacroExpander additionally distinguishes active (13). - this.catcodes = { - "%": 14, // comment character - "~": 13 // active character - }; - } - - setCatcode(char, code) { - this.catcodes[char] = code; - } - - /** - * This function lexes a single token. - */ - lex() { - const input = this.input; - const pos = this.tokenRegex.lastIndex; - if (pos === input.length) { - return new Token("EOF", new SourceLocation(this, pos, pos)); - } - const match = this.tokenRegex.exec(input); - if (match === null || match.index !== pos) { - throw new ParseError( - `Unexpected character: '${input[pos]}'`, - new Token(input[pos], new SourceLocation(this, pos, pos + 1)) - ); - } - const text = match[6] || match[3] || (match[2] ? "\\ " : " "); - - if (this.catcodes[text] === 14) { - // comment character - const nlIndex = input.indexOf("\n", this.tokenRegex.lastIndex); - if (nlIndex === -1) { - this.tokenRegex.lastIndex = input.length; // EOF - this.settings.reportNonstrict( - "commentAtEnd", - "% comment has no terminating newline; LaTeX would " + - "fail because of commenting the end of math mode (e.g. $)" - ); - } else { - this.tokenRegex.lastIndex = nlIndex + 1; - } - return this.lex(); - } - - return new Token(text, new SourceLocation(this, pos, this.tokenRegex.lastIndex)); - } -} - -/** - * A `Namespace` refers to a space of nameable things like macros or lengths, - * which can be `set` either globally or local to a nested group, using an - * undo stack similar to how TeX implements this functionality. - * Performance-wise, `get` and `set` take constant time. - */ - -class Namespace { - /** - * Both arguments are optional. The first argument is an object of - * built-in mappings which never change. The second argument is an object - * of initial (global-level) mappings, which will constantly change - * according to any global/top-level `set`s done. - */ - constructor(builtins = {}, globalMacros = {}) { - this.current = globalMacros; - this.builtins = builtins; - this.undefStack = []; - } - - /** - * Start a new nested group, affecting future local `set`s. - */ - beginGroup() { - this.undefStack.push({}); - } - - /** - * End current nested group, restoring values before the group began. - */ - endGroup() { - if (this.undefStack.length === 0) { - throw new ParseError( - "Unbalanced namespace destruction: attempt " + - "to pop global namespace; please report this as a bug" - ); - } - const undefs = this.undefStack.pop(); - for (const undef in undefs) { - if (Object.prototype.hasOwnProperty.call(undefs, undef )) { - if (undefs[undef] === undefined) { - delete this.current[undef]; - } else { - this.current[undef] = undefs[undef]; - } - } - } - } - - /** - * Detect whether `name` has a definition. Equivalent to - * `get(name) != null`. - */ - has(name) { - return Object.prototype.hasOwnProperty.call(this.current, name ) || - Object.prototype.hasOwnProperty.call(this.builtins, name ); - } - - /** - * Get the current value of a name, or `undefined` if there is no value. - * - * Note: Do not use `if (namespace.get(...))` to detect whether a macro - * is defined, as the definition may be the empty string which evaluates - * to `false` in JavaScript. Use `if (namespace.get(...) != null)` or - * `if (namespace.has(...))`. - */ - get(name) { - if (Object.prototype.hasOwnProperty.call(this.current, name )) { - return this.current[name]; - } else { - return this.builtins[name]; - } - } - - /** - * Set the current value of a name, and adds an undo - * operation to the undo stack. - */ - set(name, value) { - // Undo this set at end of this group (possibly to `undefined`), - // unless an undo is already in place, in which case that older - // value is the correct one. - const top = this.undefStack[this.undefStack.length - 1]; - if (top && !Object.prototype.hasOwnProperty.call(top, name )) { - top[name] = this.current[name]; - } - this.current[name] = value; - } -} - -/** - * Predefined macros for Temml. - * This can be used to define some commands in terms of others. - */ -const macros = _macros; - -////////////////////////////////////////////////////////////////////// -// macro tools - -defineMacro("\\noexpand", function(context) { - // The expansion is the token itself; but that token is interpreted - // as if its meaning were ‘\relax’ if it is a control sequence that - // would ordinarily be expanded by TeX’s expansion rules. - const t = context.popToken(); - if (context.isExpandable(t.text)) { - t.noexpand = true; - t.treatAsRelax = true; - } - return { tokens: [t], numArgs: 0 }; -}); - -defineMacro("\\expandafter", function(context) { - // TeX first reads the token that comes immediately after \expandafter, - // without expanding it; let’s call this token t. Then TeX reads the - // token that comes after t (and possibly more tokens, if that token - // has an argument), replacing it by its expansion. Finally TeX puts - // t back in front of that expansion. - const t = context.popToken(); - context.expandOnce(true); // expand only an expandable token - return { tokens: [t], numArgs: 0 }; -}); - -// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2 -// TeX source: \long\def\@firstoftwo#1#2{#1} -defineMacro("\\@firstoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[0], numArgs: 0 }; -}); - -// LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1 -// TeX source: \long\def\@secondoftwo#1#2{#2} -defineMacro("\\@secondoftwo", function(context) { - const args = context.consumeArgs(2); - return { tokens: args[1], numArgs: 0 }; -}); - -// LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) -// symbol that isn't a space, consuming any spaces but not consuming the -// first nonspace character. If that nonspace character matches #1, then -// the macro expands to #2; otherwise, it expands to #3. -defineMacro("\\@ifnextchar", function(context) { - const args = context.consumeArgs(3); // symbol, if, else - context.consumeSpaces(); - const nextToken = context.future(); - if (args[0].length === 1 && args[0][0].text === nextToken.text) { - return { tokens: args[1], numArgs: 0 }; - } else { - return { tokens: args[2], numArgs: 0 }; - } -}); - -// LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol. -// If it is `*`, then it consumes the symbol, and the macro expands to #1; -// otherwise, the macro expands to #2 (without consuming the symbol). -// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} -defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}"); - -// LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode -defineMacro("\\TextOrMath", function(context) { - const args = context.consumeArgs(2); - if (context.mode === "text") { - return { tokens: args[0], numArgs: 0 }; - } else { - return { tokens: args[1], numArgs: 0 }; - } -}); - -const stringFromArg = arg => { - // Reverse the order of the arg and return a string. - let str = ""; - for (let i = arg.length - 1; i > -1; i--) { - str += arg[i].text; - } - return str -}; - -// Lookup table for parsing numbers in base 8 through 16 -const digitToNumber = { - 0: 0, - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 5, - 6: 6, - 7: 7, - 8: 8, - 9: 9, - a: 10, - A: 10, - b: 11, - B: 11, - c: 12, - C: 12, - d: 13, - D: 13, - e: 14, - E: 14, - f: 15, - F: 15 -}; - -const nextCharNumber = context => { - const numStr = context.future().text; - if (numStr === "EOF") { return [null, ""] } - return [digitToNumber[numStr.charAt(0)], numStr] -}; - -const appendCharNumbers = (number, numStr, base) => { - for (let i = 1; i < numStr.length; i++) { - const digit = digitToNumber[numStr.charAt(i)]; - number *= base; - number += digit; - } - return number -}; - -// TeX \char makes a literal character (catcode 12) using the following forms: -// (see The TeXBook, p. 43) -// \char123 -- decimal -// \char'123 -- octal -// \char"123 -- hex -// \char`x -- character that can be written (i.e. isn't active) -// \char`\x -- character that cannot be written (e.g. %) -// These all refer to characters from the font, so we turn them into special -// calls to a function \@char dealt with in the Parser. -defineMacro("\\char", function(context) { - let token = context.popToken(); - let base; - let number = ""; - if (token.text === "'") { - base = 8; - token = context.popToken(); - } else if (token.text === '"') { - base = 16; - token = context.popToken(); - } else if (token.text === "`") { - token = context.popToken(); - if (token.text[0] === "\\") { - number = token.text.charCodeAt(1); - } else if (token.text === "EOF") { - throw new ParseError("\\char` missing argument"); - } else { - number = token.text.charCodeAt(0); - } - } else { - base = 10; - } - if (base) { - // Parse a number in the given base, starting with first `token`. - let numStr = token.text; - number = digitToNumber[numStr.charAt(0)]; - if (number == null || number >= base) { - throw new ParseError(`Invalid base-${base} digit ${token.text}`); - } - number = appendCharNumbers(number, numStr, base); - let digit; - [digit, numStr] = nextCharNumber(context); - while (digit != null && digit < base) { - number *= base; - number += digit; - number = appendCharNumbers(number, numStr, base); - context.popToken(); - [digit, numStr] = nextCharNumber(context); - } - } - return `\\@char{${number}}`; -}); - -defineMacro("\\hbox", "\\text{#1}"); - -// Per TeXbook p.122, "/" gets zero operator spacing. -// And MDN recommends using U+2044 instead of / for inline -defineMacro("/", "{\u2044}"); - -// Since Temml has no \par, ignore \long. -defineMacro("\\long", ""); - -////////////////////////////////////////////////////////////////////// -// Grouping -// \let\bgroup={ \let\egroup=} -defineMacro("\\bgroup", "{"); -defineMacro("\\egroup", "}"); - -// Symbols from latex.ltx: -// \def~{\nobreakspace{}} -// \def\lq{`} -// \def\rq{'} -// \def \aa {\r a} -defineMacro("~", "\\nobreakspace"); -defineMacro("\\lq", "`"); -defineMacro("\\rq", "'"); -defineMacro("\\aa", "\\r a"); - -defineMacro("\\Bbbk", "\\Bbb{k}"); - -// \mathstrut from the TeXbook, p 360 -defineMacro("\\mathstrut", "\\vphantom{(}"); - -// \underbar from TeXbook p 353 -defineMacro("\\underbar", "\\underline{\\text{#1}}"); - -////////////////////////////////////////////////////////////////////// -// LaTeX_2ε - -// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@ -// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}} -// We'll call \varvdots, which gets a glyph from symbols.js. -// The zero-width rule gets us an equivalent to the vertical 6pt kern. -defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}"); -defineMacro("\u22ee", "\\vdots"); - -////////////////////////////////////////////////////////////////////// -// amsmath.sty -// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf - -//\newcommand{\substack}[1]{\subarray{c}#1\endsubarray} -defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}"); - -// \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} -defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}"); - -// \def\iff{\DOTSB\;\Longleftrightarrow\;} -// \def\implies{\DOTSB\;\Longrightarrow\;} -// \def\impliedby{\DOTSB\;\Longleftarrow\;} -defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;"); -defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;"); -defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;"); - -// AMSMath's automatic \dots, based on \mdots@@ macro. -const dotsByToken = { - ",": "\\dotsc", - "\\not": "\\dotsb", - // \keybin@ checks for the following: - "+": "\\dotsb", - "=": "\\dotsb", - "<": "\\dotsb", - ">": "\\dotsb", - "-": "\\dotsb", - "*": "\\dotsb", - ":": "\\dotsb", - // Symbols whose definition starts with \DOTSB: - "\\DOTSB": "\\dotsb", - "\\coprod": "\\dotsb", - "\\bigvee": "\\dotsb", - "\\bigwedge": "\\dotsb", - "\\biguplus": "\\dotsb", - "\\bigcap": "\\dotsb", - "\\bigcup": "\\dotsb", - "\\prod": "\\dotsb", - "\\sum": "\\dotsb", - "\\bigotimes": "\\dotsb", - "\\bigoplus": "\\dotsb", - "\\bigodot": "\\dotsb", - "\\bigsqcap": "\\dotsb", - "\\bigsqcup": "\\dotsb", - "\\And": "\\dotsb", - "\\longrightarrow": "\\dotsb", - "\\Longrightarrow": "\\dotsb", - "\\longleftarrow": "\\dotsb", - "\\Longleftarrow": "\\dotsb", - "\\longleftrightarrow": "\\dotsb", - "\\Longleftrightarrow": "\\dotsb", - "\\mapsto": "\\dotsb", - "\\longmapsto": "\\dotsb", - "\\hookrightarrow": "\\dotsb", - "\\doteq": "\\dotsb", - // Symbols whose definition starts with \mathbin: - "\\mathbin": "\\dotsb", - // Symbols whose definition starts with \mathrel: - "\\mathrel": "\\dotsb", - "\\relbar": "\\dotsb", - "\\Relbar": "\\dotsb", - "\\xrightarrow": "\\dotsb", - "\\xleftarrow": "\\dotsb", - // Symbols whose definition starts with \DOTSI: - "\\DOTSI": "\\dotsi", - "\\int": "\\dotsi", - "\\oint": "\\dotsi", - "\\iint": "\\dotsi", - "\\iiint": "\\dotsi", - "\\iiiint": "\\dotsi", - "\\idotsint": "\\dotsi", - // Symbols whose definition starts with \DOTSX: - "\\DOTSX": "\\dotsx" -}; - -defineMacro("\\dots", function(context) { - // TODO: If used in text mode, should expand to \textellipsis. - // However, in Temml, \textellipsis and \ldots behave the same - // (in text mode), and it's unlikely we'd see any of the math commands - // that affect the behavior of \dots when in text mode. So fine for now - // (until we support \ifmmode ... \else ... \fi). - let thedots = "\\dotso"; - const next = context.expandAfterFuture().text; - if (next in dotsByToken) { - thedots = dotsByToken[next]; - } else if (next.substr(0, 4) === "\\not") { - thedots = "\\dotsb"; - } else if (next in symbols.math) { - if (utils.contains(["bin", "rel"], symbols.math[next].group)) { - thedots = "\\dotsb"; - } - } - return thedots; -}); - -const spaceAfterDots = { - // \rightdelim@ checks for the following: - ")": true, - "]": true, - "\\rbrack": true, - "\\}": true, - "\\rbrace": true, - "\\rangle": true, - "\\rceil": true, - "\\rfloor": true, - "\\rgroup": true, - "\\rmoustache": true, - "\\right": true, - "\\bigr": true, - "\\biggr": true, - "\\Bigr": true, - "\\Biggr": true, - // \extra@ also tests for the following: - $: true, - // \extrap@ checks for the following: - ";": true, - ".": true, - ",": true -}; - -defineMacro("\\dotso", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\dotsc", function(context) { - const next = context.future().text; - // \dotsc uses \extra@ but not \extrap@, instead specially checking for - // ';' and '.', but doesn't check for ','. - if (next in spaceAfterDots && next !== ",") { - return "\\ldots\\,"; - } else { - return "\\ldots"; - } -}); - -defineMacro("\\cdots", function(context) { - const next = context.future().text; - if (next in spaceAfterDots) { - return "\\@cdots\\,"; - } else { - return "\\@cdots"; - } -}); - -defineMacro("\\dotsb", "\\cdots"); -defineMacro("\\dotsm", "\\cdots"); -defineMacro("\\dotsi", "\\!\\cdots"); -defineMacro("\\idotsint", "\\dotsi"); -// amsmath doesn't actually define \dotsx, but \dots followed by a macro -// starting with \DOTSX implies \dotso, and then \extra@ detects this case -// and forces the added `\,`. -defineMacro("\\dotsx", "\\ldots\\,"); - -// \let\DOTSI\relax -// \let\DOTSB\relax -// \let\DOTSX\relax -defineMacro("\\DOTSI", "\\relax"); -defineMacro("\\DOTSB", "\\relax"); -defineMacro("\\DOTSX", "\\relax"); - -// Spacing, based on amsmath.sty's override of LaTeX defaults -// \DeclareRobustCommand{\tmspace}[3]{% -// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax} -defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax"); -// \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\,", "\\tmspace+{3mu}{.1667em}"); -// \let\thinspace\, -defineMacro("\\thinspace", "\\,"); -// \def\>{\mskip\medmuskip} -// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}} -// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\>", "\\mskip{4mu}"); -defineMacro("\\:", "\\tmspace+{4mu}{.2222em}"); -// \let\medspace\: -defineMacro("\\medspace", "\\:"); -// \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip = 5mu plus 5mu -defineMacro("\\;", "\\tmspace+{5mu}{.2777em}"); -// \let\thickspace\; -defineMacro("\\thickspace", "\\;"); -// \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}} -// TODO: math mode should use \thinmuskip -defineMacro("\\!", "\\tmspace-{3mu}{.1667em}"); -// \let\negthinspace\! -defineMacro("\\negthinspace", "\\!"); -// \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}} -// TODO: math mode should use \medmuskip -defineMacro("\\negmedspace", "\\tmspace-{4mu}{.2222em}"); -// \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}} -// TODO: math mode should use \thickmuskip -defineMacro("\\negthickspace", "\\tmspace-{5mu}{.277em}"); -// \def\enspace{\kern.5em } -defineMacro("\\enspace", "\\kern.5em "); -// \def\enskip{\hskip.5em\relax} -defineMacro("\\enskip", "\\hskip.5em\\relax"); -// \def\quad{\hskip1em\relax} -defineMacro("\\quad", "\\hskip1em\\relax"); -// \def\qquad{\hskip2em\relax} -defineMacro("\\qquad", "\\hskip2em\\relax"); - -// \tag@in@display form of \tag -defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren"); -defineMacro("\\tag@paren", "\\tag@literal{({#1})}"); -defineMacro("\\tag@literal", (context) => { - if (context.macros.get("\\df@tag")) { - throw new ParseError("Multiple \\tag"); - } - return "\\def\\df@tag{\\text{#1}}"; -}); - -// \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin -// {\operator@font mod}\penalty900 -// \mkern5mu\nonscript\mskip-\medmuskip} -// \newcommand{\pod}[1]{\allowbreak -// \if@display\mkern18mu\else\mkern8mu\fi(#1)} -// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}} -// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu -// \else\mkern12mu\fi{\operator@font mod}\,\,#1} -// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu -defineMacro("\\bmod", "\\mathbin{\\text{mod}}"); -defineMacro( - "\\pod", - "\\allowbreak" + "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)" -); -defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}"); -defineMacro( - "\\mod", - "\\allowbreak" + - "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" + - "{\\rm mod}\\,\\,#1" -); - -////////////////////////////////////////////////////////////////////// -// LaTeX source2e - -// \expandafter\let\expandafter\@normalcr -// \csname\expandafter\@gobble\string\\ \endcsname -// \DeclareRobustCommand\newline{\@normalcr\relax} -defineMacro("\\newline", "\\\\\\relax"); - -// \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} -// TODO: Doesn't normally work in math mode because \@ fails. -defineMacro("\\TeX", "\\textrm{T}\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125em\\textrm{X}"); - -defineMacro( - "\\LaTeX", - "\\textrm{L}\\kern-.35em\\raisebox{0.2em}{\\scriptstyle A}\\kern-.15em\\TeX" -); - -defineMacro( - "\\Temml", - // eslint-disable-next-line max-len - "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}" -); - -// \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace} -// \def\@hspace#1{\hskip #1\relax} -// \def\@hspacer#1{\vrule \@width\z@\nobreak -// \hskip #1\hskip \z@skip} -defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace"); -defineMacro("\\@hspace", "\\hskip #1\\relax"); -defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax"); - -////////////////////////////////////////////////////////////////////// -// mathtools.sty - -defineMacro("\\prescript", "\\pres@cript{_{#1}^{#2}}{}{#3}"); - -//\providecommand\ordinarycolon{:} -defineMacro("\\ordinarycolon", ":"); -//\def\vcentcolon{\mathrel{\mathop\ordinarycolon}} -//TODO(edemaine): Not yet centered. Fix via \raisebox or #726 -defineMacro("\\vcentcolon", "\\mathrel{\\mathrel\\ordinarycolon}"); -// \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\coloneq", '\\mathrel{\\char"3a\\char"2212}'); -// \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}} -defineMacro("\\Coloneq", '\\mathrel{\\char"2237\\char"2212}'); -// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqqcolon", '\\mathrel{\\char"3d\\char"2237}'); -// \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon} -defineMacro("\\Eqcolon", '\\mathrel{\\char"2212\\char"2237}'); -// \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\colonapprox", '\\mathrel{\\char"3a\\char"2248}'); -// \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx} -defineMacro("\\Colonapprox", '\\mathrel{\\char"2237\\char"2248}'); -// \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\colonsim", '\\mathrel{\\char"3a\\char"223c}'); -// \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim} -defineMacro("\\Colonsim", '\\mathrel{\\char"2237\\char"223c}'); - -////////////////////////////////////////////////////////////////////// -// colonequals.sty - -// Alternate names for mathtools's macros: -defineMacro("\\ratio", "\\vcentcolon"); -defineMacro("\\coloncolon", "\\dblcolon"); -defineMacro("\\colonequals", "\\coloneqq"); -defineMacro("\\coloncolonequals", "\\Coloneqq"); -defineMacro("\\equalscolon", "\\eqqcolon"); -defineMacro("\\equalscoloncolon", "\\Eqqcolon"); -defineMacro("\\colonminus", "\\coloneq"); -defineMacro("\\coloncolonminus", "\\Coloneq"); -defineMacro("\\minuscolon", "\\eqcolon"); -defineMacro("\\minuscoloncolon", "\\Eqcolon"); -// \colonapprox name is same in mathtools and colonequals. -defineMacro("\\coloncolonapprox", "\\Colonapprox"); -// \colonsim name is same in mathtools and colonequals. -defineMacro("\\coloncolonsim", "\\Colonsim"); - -// Present in newtxmath, pxfonts and txfonts -defineMacro("\\notni", "\\mathrel{\\char`\u220C}"); -defineMacro("\\limsup", "\\DOTSB\\operatorname*{lim\\,sup}"); -defineMacro("\\liminf", "\\DOTSB\\operatorname*{lim\\,inf}"); - -////////////////////////////////////////////////////////////////////// -// From amsopn.sty -defineMacro("\\injlim", "\\DOTSB\\operatorname*{inj\\,lim}"); -defineMacro("\\projlim", "\\DOTSB\\operatorname*{proj\\,lim}"); -defineMacro("\\varlimsup", "\\DOTSB\\operatorname*{\\overline{\\text{lim}}}"); -defineMacro("\\varliminf", "\\DOTSB\\operatorname*{\\underline{\\text{lim}}}"); -defineMacro("\\varinjlim", "\\DOTSB\\operatorname*{\\underrightarrow{\\text{lim}}}"); -defineMacro("\\varprojlim", "\\DOTSB\\operatorname*{\\underleftarrow{\\text{lim}}}"); - - -////////////////////////////////////////////////////////////////////// -// statmath.sty -// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf - -defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}"); -defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}"); -defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}"); - -////////////////////////////////////////////////////////////////////// -// braket.sty -// http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf - -defineMacro("\\bra", "\\mathinner{\\langle{#1}|}"); -defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}"); -defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}"); -defineMacro("\\Bra", "\\left\\langle#1\\right|"); -defineMacro("\\Ket", "\\left|#1\\right\\rangle"); -const braketHelper = (one) => (context) => { - const left = context.consumeArg().tokens; - const middle = context.consumeArg().tokens; - const middleDouble = context.consumeArg().tokens; - const right = context.consumeArg().tokens; - const oldMiddle = context.macros.get("|"); - const oldMiddleDouble = context.macros.get("\\|"); - context.macros.beginGroup(); - const midMacro = (double) => (context) => { - if (one) { - // Only modify the first instance of | or \| - context.macros.set("|", oldMiddle); - if (middleDouble.length) { - context.macros.set("\\|", oldMiddleDouble); - } - } - let doubled = double; - if (!double && middleDouble.length) { - // Mimic \@ifnextchar - const nextToken = context.future(); - if (nextToken.text === "|") { - context.popToken(); - doubled = true; - } - } - return { - tokens: doubled ? middleDouble : middle, - numArgs: 0 - }; - }; - context.macros.set("|", midMacro(false)); - if (middleDouble.length) { - context.macros.set("\\|", midMacro(true)); - } - const arg = context.consumeArg().tokens; - const expanded = context.expandTokens([...right, ...arg, ...left]); // reversed - context.macros.endGroup(); - return { - tokens: expanded.reverse(), - numArgs: 0 - }; -}; -defineMacro("\\bra@ket", braketHelper(false)); -defineMacro("\\bra@set", braketHelper(true)); -defineMacro("\\Braket", "\\bra@ket{\\left\\langle}" + - "{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}"); -defineMacro("\\Set", "\\bra@set{\\left\\{\\:}" + - "{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}"); -defineMacro("\\set", "\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}"); - // has no support for special || or \| - -////////////////////////////////////////////////////////////////////// -// actuarialangle.dtx -defineMacro("\\angln", "{\\angl n}"); - -////////////////////////////////////////////////////////////////////// -// derivative.sty -defineMacro("\\odv", "\\@ifstar\\odv@next\\odv@numerator"); -defineMacro("\\odv@numerator", "\\frac{\\mathrm{d}#1}{\\mathrm{d}#2}"); -defineMacro("\\odv@next", "\\frac{\\mathrm{d}}{\\mathrm{d}#2}#1"); -defineMacro("\\pdv", "\\@ifstar\\pdv@next\\pdv@numerator"); - -const pdvHelper = args => { - const numerator = args[0][0].text; - const denoms = stringFromArg(args[1]).split(","); - const power = String(denoms.length); - const numOp = power === "1" ? "\\partial" : `\\partial^${power}`; - let denominator = ""; - denoms.map(e => { denominator += "\\partial " + e.trim() + "\\,";}); - return [numerator, numOp, denominator.replace(/\\,$/, "")] -}; -defineMacro("\\pdv@numerator", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp} ${numerator}}{${denominator}}` -}); -defineMacro("\\pdv@next", function(context) { - const [numerator, numOp, denominator] = pdvHelper(context.consumeArgs(2)); - return `\\frac{${numOp}}{${denominator}} ${numerator}` -}); - -////////////////////////////////////////////////////////////////////// -// upgreek.dtx -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\upbeta", "\\up@greek{\\beta}"); -defineMacro("\\upgamma", "\\up@greek{\\gamma}"); -defineMacro("\\updelta", "\\up@greek{\\delta}"); -defineMacro("\\upepsilon", "\\up@greek{\\epsilon}"); -defineMacro("\\upzeta", "\\up@greek{\\zeta}"); -defineMacro("\\upeta", "\\up@greek{\\eta}"); -defineMacro("\\uptheta", "\\up@greek{\\theta}"); -defineMacro("\\upiota", "\\up@greek{\\iota}"); -defineMacro("\\upkappa", "\\up@greek{\\kappa}"); -defineMacro("\\uplambda", "\\up@greek{\\lambda}"); -defineMacro("\\upmu", "\\up@greek{\\mu}"); -defineMacro("\\upnu", "\\up@greek{\\nu}"); -defineMacro("\\upxi", "\\up@greek{\\xi}"); -defineMacro("\\upomicron", "\\up@greek{\\omicron}"); -defineMacro("\\uppi", "\\up@greek{\\pi}"); -defineMacro("\\upalpha", "\\up@greek{\\alpha}"); -defineMacro("\\uprho", "\\up@greek{\\rho}"); -defineMacro("\\upsigma", "\\up@greek{\\sigma}"); -defineMacro("\\uptau", "\\up@greek{\\tau}"); -defineMacro("\\upupsilon", "\\up@greek{\\upsilon}"); -defineMacro("\\upphi", "\\up@greek{\\phi}"); -defineMacro("\\upchi", "\\up@greek{\\chi}"); -defineMacro("\\uppsi", "\\up@greek{\\psi}"); -defineMacro("\\upomega", "\\up@greek{\\omega}"); - -////////////////////////////////////////////////////////////////////// -// chemstyle package -defineMacro("\\standardstate", "{\\tiny\\char`⦵}"); - -/* eslint-disable */ -/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ - -/************************************************************* - * - * Temml mhchem.js - * - * This file implements a Temml version of mhchem version 3.3.0. - * It is adapted from MathJax/extensions/TeX/mhchem.js - * It differs from the MathJax version as follows: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \rlap and \llap are replaced with \mathrlap and \mathllap. - * 3. The reaction arrow code is simplified. All reaction arrows are rendered - * using Temml extensible arrows instead of building non-extensible arrows. - * 4. SVG path geometry is supplied for \equilibriumRight & \equilibriumLeft. - * 5. \tripledash uses Unicode character U+2504, ┄. - * 6. Two dashes in _getBond are wrapped in braces to suppress spacing. i.e., {-} - * 7. The electron dot uses \textbullet instead of \bullet. - * - * This code, as other Temml code, is released under the MIT license. - * - * /************************************************************* - * - * MathJax/extensions/TeX/mhchem.js - * - * Implements the \ce command for handling chemical formulas - * from the mhchem LaTeX package. - * - * --------------------------------------------------------------------- - * - * Copyright (c) 2011-2015 The MathJax Consortium - * Copyright (c) 2015-2018 Martin Hensel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// Coding Style -// - use '' for identifiers that can by minified/uglified -// - use "" for strings that need to stay untouched - -// version: "3.3.0" for MathJax and Temml - - -// Add \ce, \pu, and \tripledash to the Temml macros. - -defineMacro("\\ce", function(context) { - return chemParse(context.consumeArgs(1)[0], "ce") -}); - -defineMacro("\\pu", function(context) { - return chemParse(context.consumeArgs(1)[0], "pu"); -}); - -// Needed for \bond for the ~ forms -// Raise by 2.56mu, not 2mu. We're raising a hyphen-minus, U+002D, not -// a mathematical minus, U+2212. So we need that extra 0.56. -defineMacro("\\tripledash", '\\mathord{\\kern2mu\\raise{0.5mu}{\\char"2504}\\kern2mu}'); - -// Use the Temml macro system to send SVG path geometry for equilibrium arrows. -defineMacro("longRightleftharpoonsLeft", `M507,435c-4,4,-6.3,8.7,-7,14 -c0,5.3,0.7,9,2,11c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 -c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 -c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 -c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z -M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`) -defineMacro("longRightleftharpoonsRight", `M0,241 l0,40c399126,0,399993,0,399993,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`) -defineMacro("longLeftrightharpoonsLeft", `M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 -c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, -1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, --152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z -M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`) -defineMacro("longLeftrightharpoonsRight", `M53,241l0,40c398570,0,399437,0,399437,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`) - - -const path = { - "\\equilibriumRight" : { - left: `M507,435c-4,4,-6.3,8.7,-7,14 -c0,5.3,0.7,9,2,11c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 -c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 -c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 -c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z -M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`, - right: `M0,241 l0,40c399126,0,399993,0,399993,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z` - }, - "\\equilibriumLeft": { - left: `M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 -c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, -1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, --152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z -M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`, - right: `M53,241l0,40c398570,0,399437,0,399437,0 -c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, --231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 -c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z -M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z` - } -} - -const svg = (name, end) => { - const svg = { - type: "svg", - attributes: { - xmlns: "http://www.w3.org/2000/svg", - width: "400em", - height: "0.716em", - viewBox: "0 0 400000 716", - preserveAspectRatio: `x${end === "left" ? "Min" : "Max"}yMin slice`, - fill: "currrentColor", - "fill-rule": "non-zero", - "fill-opacity" : 1 - }, - style: { position: "absolute" }, - children: [{ - type: "path", - attributes: { d: path[name][end], stroke: "none" }, - children: [] - }] - } - if (end === "left") { svg.style.left = 0 } else { svg.style.right = 0 } - return svg -} - -const endSpan = (name, end) => { - const span = { - type: "span", - attributes: {}, - style: { position: "absolute", width: "50.2%", height: "0.716em", overflow: "hidden" }, - children: [svg(name, end)] - } - if (end === "left") { span.style.left = 0 } else { span.style.right = 0 } - return span -} - -const arrowNode = name => { - return JSON.stringify({ - type: "span", - attributes: {}, - style: { display: "block", position: "relative", width: "100%", height: "0.716em", "min-width": "1.75em" }, - children: [endSpan(name, "left"), endSpan(name, "right")] - }) -} - -defineMacro("\\@equilibriumRight", arrowNode("\\equilibriumRight")) -defineMacro("\\@equilibriumLeft", arrowNode("\\equilibriumLeft")) - - // - // This is the main function for handing the \ce and \pu commands. - // It takes the argument to \ce or \pu and returns the corresponding TeX string. - // - - var chemParse = function (tokens, stateMachine) { - // Recreate the argument string from Temml's array of tokens. - var str = ""; - var expectedLoc = tokens[tokens.length - 1].loc.start - for (var i = tokens.length - 1; i >= 0; i--) { - if(tokens[i].loc.start > expectedLoc) { - // context.consumeArgs has eaten a space. - str += " "; - expectedLoc = tokens[i].loc.start; - } - str += tokens[i].text; - expectedLoc += tokens[i].text.length; - } - // Call the mhchem core parser. - var tex = texify.go(mhchemParser.go(str, stateMachine)); - return tex; - }; - - // - // Core parser for mhchem syntax (recursive) - // - /** @type {MhchemParser} */ - var mhchemParser = { - // - // Parses mchem \ce syntax - // - // Call like - // go("H2O"); - // - go: function (input, stateMachine) { - if (!input) { return []; } - if (stateMachine === undefined) { stateMachine = 'ce'; } - var state = '0'; - - // - // String buffers for parsing: - // - // buffer.a == amount - // buffer.o == element - // buffer.b == left-side superscript - // buffer.p == left-side subscript - // buffer.q == right-side subscript - // buffer.d == right-side superscript - // - // buffer.r == arrow - // buffer.rdt == arrow, script above, type - // buffer.rd == arrow, script above, content - // buffer.rqt == arrow, script below, type - // buffer.rq == arrow, script below, content - // - // buffer.text_ - // buffer.rm - // etc. - // - // buffer.parenthesisLevel == int, starting at 0 - // buffer.sb == bool, space before - // buffer.beginsWithBond == bool - // - // These letters are also used as state names. - // - // Other states: - // 0 == begin of main part (arrow/operator unlikely) - // 1 == next entity - // 2 == next entity (arrow/operator unlikely) - // 3 == next atom - // c == macro - // - /** @type {Buffer} */ - var buffer = {}; - buffer['parenthesisLevel'] = 0; - - input = input.replace(/\n/g, " "); - input = input.replace(/[\u2212\u2013\u2014\u2010]/g, "-"); - input = input.replace(/[\u2026]/g, "..."); - - // - // Looks through mhchemParser.transitions, to execute a matching action - // (recursive) - // - var lastInput; - var watchdog = 10; - /** @type {ParserOutput[]} */ - var output = []; - while (true) { - if (lastInput !== input) { - watchdog = 10; - lastInput = input; - } else { - watchdog--; - } - // - // Find actions in transition table - // - var machine = mhchemParser.stateMachines[stateMachine]; - var t = machine.transitions[state] || machine.transitions['*']; - iterateTransitions: - for (var i=0; i 0) { - if (!task.revisit) { - input = matches.remainder; - } - if (!task.toContinue) { - break iterateTransitions; - } - } else { - return output; - } - } - } - // - // Prevent infinite loop - // - if (watchdog <= 0) { - throw ["MhchemBugU", "mhchem bug U. Please report."]; // Unexpected character - } - } - }, - concatArray: function (a, b) { - if (b) { - if (Array.isArray(b)) { - for (var iB=0; iB': /^[=<>]/, - '#': /^[#\u2261]/, - '+': /^\+/, - '-$': /^-(?=[\s_},;\]/]|$|\([a-z]+\))/, // -space -, -; -] -/ -$ -state-of-aggregation - '-9': /^-(?=[0-9])/, - '- orbital overlap': /^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/, - '-': /^-/, - 'pm-operator': /^(?:\\pm|\$\\pm\$|\+-|\+\/-)/, - 'operator': /^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/, - 'arrowUpDown': /^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/, - '\\bond{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\bond{", "", "", "}"); }, - '->': /^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/, - 'CMT': /^[CMT](?=\[)/, - '[(...)]': function (input) { return mhchemParser.patterns.findObserveGroups(input, "[", "", "", "]"); }, - '1st-level escape': /^(&|\\\\|\\hline)\s*/, - '\\,': /^(?:\\[,\ ;:])/, // \\x - but output no space before - '\\x{}{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", "", "", "{", "}", "", true); }, - '\\x{}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "", /^\\[a-zA-Z]+\{/, "}", ""); }, - '\\ca': /^\\ca(?:\s+|(?![a-zA-Z]))/, - '\\x': /^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/, - 'orbital': /^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/, // only those with numbers in front, because the others will be formatted correctly anyway - 'others': /^[\/~|]/, - '\\frac{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\frac{", "", "", "}", "{", "", "", "}"); }, - '\\overset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\overset{", "", "", "}", "{", "", "", "}"); }, - '\\underset{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underset{", "", "", "}", "{", "", "", "}"); }, - '\\underbrace{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\underbrace{", "", "", "}_", "{", "", "", "}"); }, - '\\color{(...)}0': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}"); }, - '\\color{(...)}{(...)}1': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color{", "", "", "}", "{", "", "", "}"); }, - '\\color(...){(...)}2': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\color", "\\", "", /^(?=\{)/, "{", "", "", "}"); }, - '\\ce{(...)}': function (input) { return mhchemParser.patterns.findObserveGroups(input, "\\ce{", "", "", "}"); }, - 'oxidation$': /^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, - 'd-oxidation$': /^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/, // 0 could be oxidation or charge - 'roman numeral': /^[IVX]+/, - '1/2$': /^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/, - 'amount': function (input) { - var match; - // e.g. 2, 0.5, 1/2, -2, n/2, +; $a$ could be added later in parsing - match = input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - var a = mhchemParser.patterns.findObserveGroups(input, "", "$", "$", ""); - if (a) { // e.g. $2n-1$, $-$ - match = a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - } - return null; - }, - 'amount2': function (input) { return this['amount'](input); }, - '(KV letters),': /^(?:[A-Z][a-z]{0,2}|i)(?=,)/, - 'formula$': function (input) { - if (input.match(/^\([a-z]+\)$/)) { return null; } // state of aggregation = no formula - var match = input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/); - if (match) { - return { match_: match[0], remainder: input.substr(match[0].length) }; - } - return null; - }, - 'uprightEntities': /^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/, - '/': /^\s*(\/)\s*/, - '//': /^\s*(\/\/)\s*/, - '*': /^\s*[*.]\s*/ - }, - findObserveGroups: function (input, begExcl, begIncl, endIncl, endExcl, beg2Excl, beg2Incl, end2Incl, end2Excl, combine) { - /** @type {{(input: string, pattern: string | RegExp): string | string[] | null;}} */ - var _match = function (input, pattern) { - if (typeof pattern === "string") { - if (input.indexOf(pattern) !== 0) { return null; } - return pattern; - } else { - var match = input.match(pattern); - if (!match) { return null; } - return match[0]; - } - }; - /** @type {{(input: string, i: number, endChars: string | RegExp): {endMatchBegin: number, endMatchEnd: number} | null;}} */ - var _findObserveGroups = function (input, i, endChars) { - var braces = 0; - while (i < input.length) { - var a = input.charAt(i); - var match = _match(input.substr(i), endChars); - if (match !== null && braces === 0) { - return { endMatchBegin: i, endMatchEnd: i + match.length }; - } else if (a === "{") { - braces++; - } else if (a === "}") { - if (braces === 0) { - throw ["ExtraCloseMissingOpen", "Extra close brace or missing open brace"]; - } else { - braces--; - } - } - i++; - } - if (braces > 0) { - return null; - } - return null; - }; - var match = _match(input, begExcl); - if (match === null) { return null; } - input = input.substr(match.length); - match = _match(input, begIncl); - if (match === null) { return null; } - var e = _findObserveGroups(input, match.length, endIncl || endExcl); - if (e === null) { return null; } - var match1 = input.substring(0, (endIncl ? e.endMatchEnd : e.endMatchBegin)); - if (!(beg2Excl || beg2Incl)) { - return { - match_: match1, - remainder: input.substr(e.endMatchEnd) - }; - } else { - var group2 = this.findObserveGroups(input.substr(e.endMatchEnd), beg2Excl, beg2Incl, end2Incl, end2Excl); - if (group2 === null) { return null; } - /** @type {string[]} */ - var matchRet = [match1, group2.match_]; - return { - match_: (combine ? matchRet.join("") : matchRet), - remainder: group2.remainder - }; - } - }, - - // - // Matching function - // e.g. match("a", input) will look for the regexp called "a" and see if it matches - // returns null or {match_:"a", remainder:"bc"} - // - match_: function (m, input) { - var pattern = mhchemParser.patterns.patterns[m]; - if (pattern === undefined) { - throw ["MhchemBugP", "mhchem bug P. Please report. (" + m + ")"]; // Trying to use non-existing pattern - } else if (typeof pattern === "function") { - return mhchemParser.patterns.patterns[m](input); // cannot use cached var pattern here, because some pattern functions need this===mhchemParser - } else { // RegExp - var match = input.match(pattern); - if (match) { - var mm; - if (match[2]) { - mm = [ match[1], match[2] ]; - } else if (match[1]) { - mm = match[1]; - } else { - mm = match[0]; - } - return { match_: mm, remainder: input.substr(match[0].length) }; - } - return null; - } - } - }, - - // - // Generic state machine actions - // - actions: { - 'a=': function (buffer, m) { buffer.a = (buffer.a || "") + m; }, - 'b=': function (buffer, m) { buffer.b = (buffer.b || "") + m; }, - 'p=': function (buffer, m) { buffer.p = (buffer.p || "") + m; }, - 'o=': function (buffer, m) { buffer.o = (buffer.o || "") + m; }, - 'q=': function (buffer, m) { buffer.q = (buffer.q || "") + m; }, - 'd=': function (buffer, m) { buffer.d = (buffer.d || "") + m; }, - 'rm=': function (buffer, m) { buffer.rm = (buffer.rm || "") + m; }, - 'text=': function (buffer, m) { buffer.text_ = (buffer.text_ || "") + m; }, - 'insert': function (buffer, m, a) { return { type_: a }; }, - 'insert+p1': function (buffer, m, a) { return { type_: a, p1: m }; }, - 'insert+p1+p2': function (buffer, m, a) { return { type_: a, p1: m[0], p2: m[1] }; }, - 'copy': function (buffer, m) { return m; }, - 'rm': function (buffer, m) { return { type_: 'rm', p1: m || ""}; }, - 'text': function (buffer, m) { return mhchemParser.go(m, 'text'); }, - '{text}': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'text')); - ret.push("}"); - return ret; - }, - 'tex-math': function (buffer, m) { return mhchemParser.go(m, 'tex-math'); }, - 'tex-math tight': function (buffer, m) { return mhchemParser.go(m, 'tex-math tight'); }, - 'bond': function (buffer, m, k) { return { type_: 'bond', kind_: k || m }; }, - 'color0-output': function (buffer, m) { return { type_: 'color0', color: m[0] }; }, - 'ce': function (buffer, m) { return mhchemParser.go(m); }, - '1/2': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m.match(/^[+\-]/)) { - ret.push(m.substr(0, 1)); - m = m.substr(1); - } - var n = m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/); - n[1] = n[1].replace(/\$/g, ""); - ret.push({ type_: 'frac', p1: n[1], p2: n[2] }); - if (n[3]) { - n[3] = n[3].replace(/\$/g, ""); - ret.push({ type_: 'tex-math', p1: n[3] }); - } - return ret; - }, - '9,9': function (buffer, m) { return mhchemParser.go(m, '9,9'); } - }, - // - // createTransitions - // convert { 'letter': { 'state': { action_: 'output' } } } to { 'state' => [ { pattern: 'letter', task: { action_: [{type_: 'output'}] } } ] } - // with expansion of 'a|b' to 'a' and 'b' (at 2 places) - // - createTransitions: function (o) { - var pattern, state; - /** @type {string[]} */ - var stateArray; - var i; - // - // 1. Collect all states - // - /** @type {Transitions} */ - var transitions = {}; - for (pattern in o) { - for (state in o[pattern]) { - stateArray = state.split("|"); - o[pattern][state].stateArray = stateArray; - for (i=0; i': { - '0|1|2|3': { action_: 'r=', nextState: 'r' }, - 'a|as': { action_: [ 'output', 'r=' ], nextState: 'r' }, - '*': { action_: [ 'output', 'r=' ], nextState: 'r' } }, - '+': { - 'o': { action_: 'd= kv', nextState: 'd' }, - 'd|D': { action_: 'd=', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd|qD': { action_: 'd=', nextState: 'qd' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' }, - '3': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - 'amount': { - '0|2': { action_: 'a=', nextState: 'a' } }, - 'pm-operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', { type_: 'operator', option: '\\pm' } ], nextState: '0' } }, - 'operator': { - '0|1|2|a|as': { action_: [ 'sb=false', 'output', 'operator' ], nextState: '0' } }, - '-$': { - 'o|q': { action_: [ 'charge or bond', 'output' ], nextState: 'qd' }, - 'd': { action_: 'd=', nextState: 'd' }, - 'D': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'qd': { action_: 'd=', nextState: 'qd' }, - 'qD|dq': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - '-9': { - '3|o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '3' } }, - '- orbital overlap': { - 'o': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'd': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' } }, - '-': { - '0|1|2': { action_: [ { type_: 'output', option: 1 }, 'beginsWithBond=true', { type_: 'bond', option: "-" } ], nextState: '3' }, - '3': { action_: { type_: 'bond', option: "-" } }, - 'a': { action_: [ 'output', { type_: 'insert', option: 'hyphen' } ], nextState: '2' }, - 'as': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "-" } ], nextState: '3' }, - 'b': { action_: 'b=' }, - 'o': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'q': { action_: { type_: '- after o/d', option: false }, nextState: '2' }, - 'd|qd|dq': { action_: { type_: '- after o/d', option: true }, nextState: '2' }, - 'D|qD|p': { action_: [ 'output', { type_: 'bond', option: "-" } ], nextState: '3' } }, - 'amount2': { - '1|3': { action_: 'a=', nextState: 'a' } }, - 'letters': { - '0|1|2|3|a|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, - 'q|dq': { action_: ['output', 'o='], nextState: 'o' }, - 'd|D|qd|qD': { action_: 'o after d', nextState: 'o' } }, - 'digits': { - 'o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q': { action_: [ 'output', 'o=' ], nextState: 'o' }, - 'a': { action_: 'o=', nextState: 'o' } }, - 'space A': { - 'b|p|bp': {} }, - 'space': { - 'a': { nextState: 'as' }, - '0': { action_: 'sb=false' }, - '1|2': { action_: 'sb=true' }, - 'r|rt|rd|rdt|rdq': { action_: 'output', nextState: '0' }, - '*': { action_: [ 'output', 'sb=true' ], nextState: '1'} }, - '1st-level escape': { - '1|2': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ] }, - '*': { action_: [ 'output', { type_: 'insert+p1', option: '1st-level escape' } ], nextState: '0' } }, - '[(...)]': { - 'r|rt': { action_: 'rd=', nextState: 'rd' }, - 'rd|rdt': { action_: 'rq=', nextState: 'rdq' } }, - '...': { - 'o|d|D|dq|qd|qD': { action_: [ 'output', { type_: 'bond', option: "..." } ], nextState: '3' }, - '*': { action_: [ { type_: 'output', option: 1 }, { type_: 'insert', option: 'ellipsis' } ], nextState: '1' } }, - '. |* ': { - '*': { action_: [ 'output', { type_: 'insert', option: 'addition compound' } ], nextState: '1' } }, - 'state of aggregation $': { - '*': { action_: [ 'output', 'state of aggregation' ], nextState: '1' } }, - '{[(': { - 'a|as|o': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '0|1|2|3': { action_: [ 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' }, - '*': { action_: [ 'output', 'o=', 'output', 'parenthesisLevel++' ], nextState: '2' } }, - ')]}': { - '0|1|2|3|b|p|bp|o': { action_: [ 'o=', 'parenthesisLevel--' ], nextState: 'o' }, - 'a|as|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=', 'parenthesisLevel--' ], nextState: 'o' } }, - ', ': { - '*': { action_: [ 'output', 'comma' ], nextState: '0' } }, - '^_': { // ^ and _ without a sensible argument - '*': { } }, - '^{(...)}|^($...$)': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'D' }, - 'q': { action_: 'd=', nextState: 'qD' }, - 'd|D|qd|qD|dq': { action_: [ 'output', 'd=' ], nextState: 'D' } }, - '^a|^\\x{}{}|^\\x{}|^\\x|\'': { - '0|1|2|as': { action_: 'b=', nextState: 'b' }, - 'p': { action_: 'b=', nextState: 'bp' }, - '3|o': { action_: 'd= kv', nextState: 'd' }, - 'q': { action_: 'd=', nextState: 'qd' }, - 'd|qd|D|qD': { action_: 'd=' }, - 'dq': { action_: [ 'output', 'd=' ], nextState: 'd' } }, - '_{(state of aggregation)}$': { - 'd|D|q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x': { - '0|1|2|as': { action_: 'p=', nextState: 'p' }, - 'b': { action_: 'p=', nextState: 'bp' }, - '3|o': { action_: 'q=', nextState: 'q' }, - 'd|D': { action_: 'q=', nextState: 'dq' }, - 'q|qd|qD|dq': { action_: [ 'output', 'q=' ], nextState: 'q' } }, - '=<>': { - '0|1|2|3|a|as|o|q|d|D|qd|qD|dq': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: '3' } }, - '#': { - '0|1|2|3|a|as|o': { action_: [ { type_: 'output', option: 2 }, { type_: 'bond', option: "#" } ], nextState: '3' } }, - '{}': { - '*': { action_: { type_: 'output', option: 1 }, nextState: '1' } }, - '{...}': { - '0|1|2|3|a|as|b|p|bp': { action_: 'o=', nextState: 'o' }, - 'o|d|D|q|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '$...$': { - 'a': { action_: 'a=' }, // 2$n$ - '0|1|2|3|as|b|p|bp|o': { action_: 'o=', nextState: 'o' }, // not 'amount' - 'as|o': { action_: 'o=' }, - 'q|d|D|qd|qD|dq': { action_: [ 'output', 'o=' ], nextState: 'o' } }, - '\\bond{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'bond' ], nextState: "3" } }, - '\\frac{(...)}': { - '*': { action_: [ { type_: 'output', option: 1 }, 'frac-output' ], nextState: '3' } }, - '\\overset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'overset-output' ], nextState: '3' } }, - '\\underset{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underset-output' ], nextState: '3' } }, - '\\underbrace{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'underbrace-output' ], nextState: '3' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color-output' ], nextState: '3' } }, - '\\color{(...)}0': { - '*': { action_: [ { type_: 'output', option: 2 }, 'color0-output' ] } }, - '\\ce{(...)}': { - '*': { action_: [ { type_: 'output', option: 2 }, 'ce' ], nextState: '3' } }, - '\\,': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '1' } }, - '\\x{}{}|\\x{}|\\x': { - '0|1|2|3|a|as|b|p|bp|o|c0': { action_: [ 'o=', 'output' ], nextState: '3' }, - '*': { action_: ['output', 'o=', 'output' ], nextState: '3' } }, - 'others': { - '*': { action_: [ { type_: 'output', option: 1 }, 'copy' ], nextState: '3' } }, - 'else2': { - 'a': { action_: 'a to o', nextState: 'o', revisit: true }, - 'as': { action_: [ 'output', 'sb=true' ], nextState: '1', revisit: true }, - 'r|rt|rd|rdt|rdq': { action_: [ 'output' ], nextState: '0', revisit: true }, - '*': { action_: [ 'output', 'copy' ], nextState: '3' } } - }), - actions: { - 'o after d': function (buffer, m) { - var ret; - if ((buffer.d || "").match(/^[0-9]+$/)) { - var tmp = buffer.d; - buffer.d = undefined; - ret = this['output'](buffer); - buffer.b = tmp; - } else { - ret = this['output'](buffer); - } - mhchemParser.actions['o='](buffer, m); - return ret; - }, - 'd= kv': function (buffer, m) { - buffer.d = m; - buffer.dType = 'kv'; - }, - 'charge or bond': function (buffer, m) { - if (buffer['beginsWithBond']) { - /** @type {ParserOutput[]} */ - var ret = []; - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - return ret; - } else { - buffer.d = m; - } - }, - '- after o/d': function (buffer, m, isAfterD) { - var c1 = mhchemParser.patterns.match_('orbital', buffer.o || ""); - var c2 = mhchemParser.patterns.match_('one lowercase greek letter $', buffer.o || ""); - var c3 = mhchemParser.patterns.match_('one lowercase latin letter $', buffer.o || ""); - var c4 = mhchemParser.patterns.match_('$one lowercase latin letter$ $', buffer.o || ""); - var hyphenFollows = m==="-" && ( c1 && c1.remainder==="" || c2 || c3 || c4 ); - if (hyphenFollows && !buffer.a && !buffer.b && !buffer.p && !buffer.d && !buffer.q && !c1 && c3) { - buffer.o = '$' + buffer.o + '$'; - } - /** @type {ParserOutput[]} */ - var ret = []; - if (hyphenFollows) { - mhchemParser.concatArray(ret, this['output'](buffer)); - ret.push({ type_: 'hyphen' }); - } else { - c1 = mhchemParser.patterns.match_('digits', buffer.d || ""); - if (isAfterD && c1 && c1.remainder==='') { - mhchemParser.concatArray(ret, mhchemParser.actions['d='](buffer, m)); - mhchemParser.concatArray(ret, this['output'](buffer)); - } else { - mhchemParser.concatArray(ret, this['output'](buffer)); - mhchemParser.concatArray(ret, mhchemParser.actions['bond'](buffer, m, "-")); - } - } - return ret; - }, - 'a to o': function (buffer) { - buffer.o = buffer.a; - buffer.a = undefined; - }, - 'sb=true': function (buffer) { buffer.sb = true; }, - 'sb=false': function (buffer) { buffer.sb = false; }, - 'beginsWithBond=true': function (buffer) { buffer['beginsWithBond'] = true; }, - 'beginsWithBond=false': function (buffer) { buffer['beginsWithBond'] = false; }, - 'parenthesisLevel++': function (buffer) { buffer['parenthesisLevel']++; }, - 'parenthesisLevel--': function (buffer) { buffer['parenthesisLevel']--; }, - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation', p1: mhchemParser.go(m, 'o') }; - }, - 'comma': function (buffer, m) { - var a = m.replace(/\s*$/, ''); - var withSpace = (a !== m); - if (withSpace && buffer['parenthesisLevel'] === 0) { - return { type_: 'comma enumeration L', p1: a }; - } else { - return { type_: 'comma enumeration M', p1: a }; - } - }, - 'output': function (buffer, m, entityFollows) { - // entityFollows: - // undefined = if we have nothing else to output, also ignore the just read space (buffer.sb) - // 1 = an entity follows, never omit the space if there was one just read before (can only apply to state 1) - // 2 = 1 + the entity can have an amount, so output a\, instead of converting it to o (can only apply to states a|as) - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - if (!buffer.r) { - ret = []; - if (!buffer.a && !buffer.b && !buffer.p && !buffer.o && !buffer.q && !buffer.d && !entityFollows) { - //ret = []; - } else { - if (buffer.sb) { - ret.push({ type_: 'entitySkip' }); - } - if (!buffer.o && !buffer.q && !buffer.d && !buffer.b && !buffer.p && entityFollows!==2) { - buffer.o = buffer.a; - buffer.a = undefined; - } else if (!buffer.o && !buffer.q && !buffer.d && (buffer.b || buffer.p)) { - buffer.o = buffer.a; - buffer.d = buffer.b; - buffer.q = buffer.p; - buffer.a = buffer.b = buffer.p = undefined; - } else { - if (buffer.o && buffer.dType==='kv' && mhchemParser.patterns.match_('d-oxidation$', buffer.d || "")) { - buffer.dType = 'oxidation'; - } else if (buffer.o && buffer.dType==='kv' && !buffer.q) { - buffer.dType = undefined; - } - } - ret.push({ - type_: 'chemfive', - a: mhchemParser.go(buffer.a, 'a'), - b: mhchemParser.go(buffer.b, 'bd'), - p: mhchemParser.go(buffer.p, 'pq'), - o: mhchemParser.go(buffer.o, 'o'), - q: mhchemParser.go(buffer.q, 'pq'), - d: mhchemParser.go(buffer.d, (buffer.dType === 'oxidation' ? 'oxidation' : 'bd')), - dType: buffer.dType - }); - } - } else { // r - /** @type {ParserOutput[]} */ - var rd; - if (buffer.rdt === 'M') { - rd = mhchemParser.go(buffer.rd, 'tex-math'); - } else if (buffer.rdt === 'T') { - rd = [ { type_: 'text', p1: buffer.rd || "" } ]; - } else { - rd = mhchemParser.go(buffer.rd); - } - /** @type {ParserOutput[]} */ - var rq; - if (buffer.rqt === 'M') { - rq = mhchemParser.go(buffer.rq, 'tex-math'); - } else if (buffer.rqt === 'T') { - rq = [ { type_: 'text', p1: buffer.rq || ""} ]; - } else { - rq = mhchemParser.go(buffer.rq); - } - ret = { - type_: 'arrow', - r: buffer.r, - rd: rd, - rq: rq - }; - } - for (var p in buffer) { - if (p !== 'parenthesisLevel' && p !== 'beginsWithBond') { - delete buffer[p]; - } - } - return ret; - }, - 'oxidation-output': function (buffer, m) { - var ret = [ "{" ]; - mhchemParser.concatArray(ret, mhchemParser.go(m, 'oxidation')); - ret.push("}"); - return ret; - }, - 'frac-output': function (buffer, m) { - return { type_: 'frac-ce', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'overset-output': function (buffer, m) { - return { type_: 'overset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underset-output': function (buffer, m) { - return { type_: 'underset', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'underbrace-output': function (buffer, m) { - return { type_: 'underbrace', p1: mhchemParser.go(m[0]), p2: mhchemParser.go(m[1]) }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1]) }; - }, - 'r=': function (buffer, m) { buffer.r = m; }, - 'rdt=': function (buffer, m) { buffer.rdt = m; }, - 'rd=': function (buffer, m) { buffer.rd = m; }, - 'rqt=': function (buffer, m) { buffer.rqt = m; }, - 'rq=': function (buffer, m) { buffer.rq = m; }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; } - } - }, - 'a': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - '$(...)$': { - '*': { action_: 'tex-math tight', nextState: '1' } }, - ',': { - '*': { action_: { type_: 'insert', option: 'commaDecimal' } } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'o': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '1', revisit: true } }, - 'letters': { - '*': { action_: 'rm' } }, - '\\ca': { - '*': { action_: { type_: 'insert', option: 'circa' } } }, - '\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: '{text}' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: {} - }, - 'text': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '{...}': { - '*': { action_: 'text=' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '\\greek': { - '*': { action_: [ 'output', 'rm' ] } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: [ 'output', 'copy' ] } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.text_) { - /** @type {ParserOutput} */ - var ret = { type_: 'text', p1: buffer.text_ }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'pq': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'state of aggregation $': { - '*': { action_: 'state of aggregation' } }, - 'i$': { - '0': { nextState: '!f', revisit: true } }, - '(KV letters),': { - '0': { action_: 'rm', nextState: '0' } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - '1/2$': { - '0': { action_: '1/2' } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'letters': { - '*': { action_: 'rm' } }, - '-9.,9': { - '*': { action_: '9,9' } }, - ',': { - '*': { action_: { type_: 'insert+p1', option: 'comma enumeration S' } } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'state of aggregation': function (buffer, m) { - return { type_: 'state of aggregation subscript', p1: mhchemParser.go(m, 'o') }; - }, - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'pq') }; - } - } - }, - 'bd': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'x$': { - '0': { nextState: '!f', revisit: true } }, - 'formula$': { - '0': { nextState: 'f', revisit: true } }, - 'else': { - '0': { nextState: '!f', revisit: true } }, - '-9.,9 no missing 0': { - '*': { action_: '9,9' } }, - '.': { - '*': { action_: { type_: 'insert', option: 'electron dot' } } }, - 'a-z': { - 'f': { action_: 'tex-math' } }, - 'x': { - '*': { action_: { type_: 'insert', option: 'KV x' } } }, - 'letters': { - '*': { action_: 'rm' } }, - '\'': { - '*': { action_: { type_: 'insert', option: 'prime' } } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - '{(...)}': { - '*': { action_: 'text' } }, - '\\color{(...)}{(...)}1|\\color(...){(...)}2': { - '*': { action_: 'color-output' } }, - '\\color{(...)}0': { - '*': { action_: 'color0-output' } }, - '\\ce{(...)}': { - '*': { action_: 'ce' } }, - '\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'copy' } }, - 'else2': { - '*': { action_: 'copy' } } - }), - actions: { - 'color-output': function (buffer, m) { - return { type_: 'color', color1: m[0], color2: mhchemParser.go(m[1], 'bd') }; - } - } - }, - 'oxidation': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - 'roman numeral': { - '*': { action_: 'roman-numeral' } }, - '${(...)}$|$(...)$': { - '*': { action_: 'tex-math' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'roman-numeral': function (buffer, m) { return { type_: 'roman numeral', p1: m || "" }; } - } - }, - 'tex-math': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - 'tex-math tight': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '\\ce{(...)}': { - '*': { action_: [ 'output', 'ce' ] } }, - '{...}|\\,|\\x{}{}|\\x{}|\\x': { - '*': { action_: 'o=' } }, - '-|+': { - '*': { action_: 'tight operator' } }, - 'else': { - '*': { action_: 'o=' } } - }), - actions: { - 'tight operator': function (buffer, m) { buffer.o = (buffer.o || "") + "{"+m+"}"; }, - 'output': function (buffer) { - if (buffer.o) { - /** @type {ParserOutput} */ - var ret = { type_: 'tex-math', p1: buffer.o }; - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - } - }, - '9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': {} }, - ',': { - '*': { action_: 'comma' } }, - 'else': { - '*': { action_: 'copy' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; } - } - }, - //#endregion - // - // \pu state machines - // - //#region pu - 'pu': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - 'space$': { - '*': { action_: [ 'output', 'space' ] } }, - '{[(|)]}': { - '0|a': { action_: 'copy' } }, - '(-)(9)^(-9)': { - '0': { action_: 'number^', nextState: 'a' } }, - '(-)(9.,9)(e)(99)': { - '0': { action_: 'enumber', nextState: 'a' } }, - 'space': { - '0|a': {} }, - 'pm-operator': { - '0|a': { action_: { type_: 'operator', option: '\\pm' }, nextState: '0' } }, - 'operator': { - '0|a': { action_: 'copy', nextState: '0' } }, - '//': { - 'd': { action_: 'o=', nextState: '/' } }, - '/': { - 'd': { action_: 'o=', nextState: '/' } }, - '{...}|else': { - '0|d': { action_: 'd=', nextState: 'd' }, - 'a': { action_: [ 'space', 'd=' ], nextState: 'd' }, - '/|q': { action_: 'q=', nextState: 'q' } } - }), - actions: { - 'enumber': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - if (m[1]) { - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - if (m[2]) { - if (m[2].match(/[,.]/)) { - mhchemParser.concatArray(ret, mhchemParser.go(m[2], 'pu-9,9')); - } else { - ret.push(m[2]); - } - } - m[3] = m[4] || m[3]; - if (m[3]) { - m[3] = m[3].trim(); - if (m[3] === "e" || m[3].substr(0, 1) === "*") { - ret.push({ type_: 'cdot' }); - } else { - ret.push({ type_: 'times' }); - } - } - } - if (m[3]) { - ret.push("10^{"+m[5]+"}"); - } - return ret; - }, - 'number^': function (buffer, m) { - /** @type {ParserOutput[]} */ - var ret = []; - if (m[0] === "+-" || m[0] === "+/-") { - ret.push("\\pm "); - } else if (m[0]) { - ret.push(m[0]); - } - mhchemParser.concatArray(ret, mhchemParser.go(m[1], 'pu-9,9')); - ret.push("^{"+m[2]+"}"); - return ret; - }, - 'operator': function (buffer, m, p1) { return { type_: 'operator', kind_: (p1 || m) }; }, - 'space': function () { return { type_: 'pu-space-1' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret; - var md = mhchemParser.patterns.match_('{(...)}', buffer.d || ""); - if (md && md.remainder === '') { buffer.d = md.match_; } - var mq = mhchemParser.patterns.match_('{(...)}', buffer.q || ""); - if (mq && mq.remainder === '') { buffer.q = mq.match_; } - if (buffer.d) { - buffer.d = buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.d = buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - } - if (buffer.q) { // fraction - buffer.q = buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g, "{}^{\\circ}C"); - buffer.q = buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g, "{}^{\\circ}F"); - var b5 = { - d: mhchemParser.go(buffer.d, 'pu'), - q: mhchemParser.go(buffer.q, 'pu') - }; - if (buffer.o === '//') { - ret = { type_: 'pu-frac', p1: b5.d, p2: b5.q }; - } else { - ret = b5.d; - if (b5.d.length > 1 || b5.q.length > 1) { - ret.push({ type_: ' / ' }); - } else { - ret.push({ type_: '/' }); - } - mhchemParser.concatArray(ret, b5.q); - } - } else { // no fraction - ret = mhchemParser.go(buffer.d, 'pu-2'); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-2': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '*': { action_: 'output' } }, - '*': { - '*': { action_: [ 'output', 'cdot' ], nextState: '0' } }, - '\\x': { - '*': { action_: 'rm=' } }, - 'space': { - '*': { action_: [ 'output', 'space' ], nextState: '0' } }, - '^{(...)}|^(-1)': { - '1': { action_: '^(-1)' } }, - '-9.,9': { - '0': { action_: 'rm=', nextState: '0' }, - '1': { action_: '^(-1)', nextState: '0' } }, - '{...}|else': { - '*': { action_: 'rm=', nextState: '1' } } - }), - actions: { - 'cdot': function () { return { type_: 'tight cdot' }; }, - '^(-1)': function (buffer, m) { buffer.rm += "^{"+m+"}"; }, - 'space': function () { return { type_: 'pu-space-2' }; }, - 'output': function (buffer) { - /** @type {ParserOutput | ParserOutput[]} */ - var ret = []; - if (buffer.rm) { - var mrm = mhchemParser.patterns.match_('{(...)}', buffer.rm || ""); - if (mrm && mrm.remainder === '') { - ret = mhchemParser.go(mrm.match_, 'pu'); - } else { - ret = { type_: 'rm', p1: buffer.rm }; - } - } - for (var p in buffer) { delete buffer[p]; } - return ret; - } - } - }, - 'pu-9,9': { - transitions: mhchemParser.createTransitions({ - 'empty': { - '0': { action_: 'output-0' }, - 'o': { action_: 'output-o' } }, - ',': { - '0': { action_: [ 'output-0', 'comma' ], nextState: 'o' } }, - '.': { - '0': { action_: [ 'output-0', 'copy' ], nextState: 'o' } }, - 'else': { - '*': { action_: 'text=' } } - }), - actions: { - 'comma': function () { return { type_: 'commaDecimal' }; }, - 'output-0': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length % 3; - if (a === 0) { a = 3; } - for (var i=buffer.text_.length-3; i>0; i-=3) { - ret.push(buffer.text_.substr(i, 3)); - ret.push({ type_: '1000 separator' }); - } - ret.push(buffer.text_.substr(0, a)); - ret.reverse(); - } else { - ret.push(buffer.text_); - } - for (var p in buffer) { delete buffer[p]; } - return ret; - }, - 'output-o': function (buffer) { - /** @type {ParserOutput[]} */ - var ret = []; - buffer.text_ = buffer.text_ || ""; - if (buffer.text_.length > 4) { - var a = buffer.text_.length - 3; - for (var i=0; i, so we change \vphantom{X} to {} - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - } else { - if (b5.q) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "_{\\smash[t]{"+b5.q+"}}"; - } - if (b5.d) { - // TODO: Reinstate \vphantom{X} when the Firefox bug is fixed. -// res += "{\\vphantom{X}}"; - res += "{{}}"; - res += "^{"+b5.d+"}"; - } - } - break; - case 'rm': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'text': - if (buf.p1.match(/[\^_]/)) { - buf.p1 = buf.p1.replace(" ", "~").replace("-", "\\text{-}"); - res = "\\mathrm{"+buf.p1+"}"; - } else { - res = "\\text{"+buf.p1+"}"; - } - break; - case 'roman numeral': - res = "\\mathrm{"+buf.p1+"}"; - break; - case 'state of aggregation': - res = "\\mskip2mu "+texify._goInner(buf.p1); - break; - case 'state of aggregation subscript': - res = "\\mskip1mu "+texify._goInner(buf.p1); - break; - case 'bond': - res = texify._getBond(buf.kind_); - if (!res) { - throw ["MhchemErrorBond", "mhchem Error. Unknown bond type (" + buf.kind_ + ")"]; - } - break; - case 'frac': - var c = "\\frac{" + buf.p1 + "}{" + buf.p2 + "}"; - res = "\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}"; - break; - case 'pu-frac': - var d = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - res = "\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}"; - break; - case 'tex-math': - res = buf.p1 + " "; - break; - case 'frac-ce': - res = "\\frac{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'overset': - res = "\\overset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underset': - res = "\\underset{" + texify._goInner(buf.p1) + "}{" + texify._goInner(buf.p2) + "}"; - break; - case 'underbrace': - res = "\\underbrace{" + texify._goInner(buf.p1) + "}_{" + texify._goInner(buf.p2) + "}"; - break; - case 'color': - res = "{\\color{" + buf.color1 + "}{" + texify._goInner(buf.color2) + "}}"; - break; - case 'color0': - res = "\\color{" + buf.color + "}"; - break; - case 'arrow': - var b6 = { - rd: texify._goInner(buf.rd), - rq: texify._goInner(buf.rq) - }; - var arrow = texify._getArrow(buf.r); - if (b6.rq) { arrow += "[{\\rm " + b6.rq + "}]"; } - if (b6.rd) { - arrow += "{\\rm " + b6.rd + "}"; - } else { - arrow += "{}"; - } - res = arrow; - break; - case 'operator': - res = texify._getOperator(buf.kind_); - break; - case '1st-level escape': - res = buf.p1+" "; // &, \\\\, \\hlin - break; - case 'space': - res = " "; - break; - case 'entitySkip': - res = "~"; - break; - case 'pu-space-1': - res = "~"; - break; - case 'pu-space-2': - res = "\\mkern3mu "; - break; - case '1000 separator': - res = "\\mkern2mu "; - break; - case 'commaDecimal': - res = "{,}"; - break; - case 'comma enumeration L': - res = "{"+buf.p1+"}\\mkern6mu "; - break; - case 'comma enumeration M': - res = "{"+buf.p1+"}\\mkern3mu "; - break; - case 'comma enumeration S': - res = "{"+buf.p1+"}\\mkern1mu "; - break; - case 'hyphen': - res = "\\text{-}"; - break; - case 'addition compound': - res = "\\,{\\cdot}\\,"; - break; - case 'electron dot': - res = "\\mkern1mu \\text{\\textbullet}\\mkern1mu "; - break; - case 'KV x': - res = "{\\times}"; - break; - case 'prime': - res = "\\prime "; - break; - case 'cdot': - res = "\\cdot "; - break; - case 'tight cdot': - res = "\\mkern1mu{\\cdot}\\mkern1mu "; - break; - case 'times': - res = "\\times "; - break; - case 'circa': - res = "{\\sim}"; - break; - case '^': - res = "uparrow"; - break; - case 'v': - res = "downarrow"; - break; - case 'ellipsis': - res = "\\ldots "; - break; - case '/': - res = "/"; - break; - case ' / ': - res = "\\,/\\,"; - break; - default: - assertNever(buf); - throw ["MhchemBugT", "mhchem bug T. Please report."]; // Missing texify rule or unknown MhchemParser output - } - assertString(res); - return res; - }, - _getArrow: function (a) { - switch (a) { - case "->": return "\\yields"; - case "\u2192": return "\\yields"; - case "\u27F6": return "\\yields"; - case "<-": return "\\yieldsLeft"; - case "<->": return "\\mesomerism"; - case "<-->": return "\\yieldsLeftRight"; - case "<=>": return "\\equilibrium"; - case "\u21CC": return "\\equilibrium"; - case "<=>>": return "\\equilibriumRight"; - case "<<=>": return "\\equilibriumLeft"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getBond: function (a) { - switch (a) { - case "-": return "{-}"; - case "1": return "{-}"; - case "=": return "{=}"; - case "2": return "{=}"; - case "#": return "{\\equiv}"; - case "3": return "{\\equiv}"; - case "~": return "{\\tripledash}"; - case "~-": return "{\\mathrlap{\\raise{-.1em}{-}}\\raise{.1em}{\\tripledash}}"; - case "~=": return "{\\mathrlap{\\raise{-.2em}{-}}\\mathrlap{\\raise{.2em}{\\tripledash}}{-}}"; - case "~--": return "{\\mathrlap{\\raise{-.2em}{-}}\\mathrlap{\\raise{.2em}{\\tripledash}}{-}}"; - case "-~-": return "{\\mathrlap{\\raise{-.2em}{-}}\\mathrlap{\\raise{.2em}{-}}\\tripledash}"; - case "...": return "{{\\cdot}{\\cdot}{\\cdot}}"; - case "....": return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}"; - case "->": return "{\\rightarrow}"; - case "<-": return "{\\leftarrow}"; - case "<": return "{<}"; - case ">": return "{>}"; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - }, - _getOperator: function (a) { - switch (a) { - case "+": return " {}+{} "; - case "-": return " {}-{} "; - case "=": return " {}={} "; - case "<": return " {}<{} "; - case ">": return " {}>{} "; - case "<<": return " {}\\ll{} "; - case ">>": return " {}\\gg{} "; - case "\\pm": return " {}\\pm{} "; - case "\\approx": return " {}\\approx{} "; - case "$\\approx$": return " {}\\approx{} "; - case "v": return " \\downarrow{} "; - case "(v)": return " \\downarrow{} "; - case "^": return " \\uparrow{} "; - case "(^)": return " \\uparrow{} "; - default: - assertNever(a); - throw ["MhchemBugT", "mhchem bug T. Please report."]; - } - } - }; - - // - // Helpers for code anaylsis - // Will show type error at calling position - // - /** @param {number} a */ - function assertNever(a) {} - /** @param {string} a */ - function assertString(a) {} - -/* eslint-disable no-undef */ - -////////////////////////////////////////////////////////////////////// -// texvc.sty - -// The texvc package contains macros available in mediawiki pages. -// We omit the functions deprecated at -// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax - -// We also omit texvc's \O, which conflicts with \text{\O} - -defineMacro("\\darr", "\\downarrow"); -defineMacro("\\dArr", "\\Downarrow"); -defineMacro("\\Darr", "\\Downarrow"); -defineMacro("\\lang", "\\langle"); -defineMacro("\\rang", "\\rangle"); -defineMacro("\\uarr", "\\uparrow"); -defineMacro("\\uArr", "\\Uparrow"); -defineMacro("\\Uarr", "\\Uparrow"); -defineMacro("\\N", "\\mathbb{N}"); -defineMacro("\\R", "\\mathbb{R}"); -defineMacro("\\Z", "\\mathbb{Z}"); -defineMacro("\\alef", "\\aleph"); -defineMacro("\\alefsym", "\\aleph"); -defineMacro("\\bull", "\\bullet"); -defineMacro("\\clubs", "\\clubsuit"); -defineMacro("\\cnums", "\\mathbb{C}"); -defineMacro("\\Complex", "\\mathbb{C}"); -defineMacro("\\Dagger", "\\ddagger"); -defineMacro("\\diamonds", "\\diamondsuit"); -defineMacro("\\empty", "\\emptyset"); -defineMacro("\\exist", "\\exists"); -defineMacro("\\harr", "\\leftrightarrow"); -defineMacro("\\hArr", "\\Leftrightarrow"); -defineMacro("\\Harr", "\\Leftrightarrow"); -defineMacro("\\hearts", "\\heartsuit"); -defineMacro("\\image", "\\Im"); -defineMacro("\\infin", "\\infty"); -defineMacro("\\isin", "\\in"); -defineMacro("\\larr", "\\leftarrow"); -defineMacro("\\lArr", "\\Leftarrow"); -defineMacro("\\Larr", "\\Leftarrow"); -defineMacro("\\lrarr", "\\leftrightarrow"); -defineMacro("\\lrArr", "\\Leftrightarrow"); -defineMacro("\\Lrarr", "\\Leftrightarrow"); -defineMacro("\\natnums", "\\mathbb{N}"); -defineMacro("\\plusmn", "\\pm"); -defineMacro("\\rarr", "\\rightarrow"); -defineMacro("\\rArr", "\\Rightarrow"); -defineMacro("\\Rarr", "\\Rightarrow"); -defineMacro("\\real", "\\Re"); -defineMacro("\\reals", "\\mathbb{R}"); -defineMacro("\\Reals", "\\mathbb{R}"); -defineMacro("\\sdot", "\\cdot"); -defineMacro("\\sect", "\\S"); -defineMacro("\\spades", "\\spadesuit"); -defineMacro("\\sub", "\\subset"); -defineMacro("\\sube", "\\subseteq"); -defineMacro("\\supe", "\\supseteq"); -defineMacro("\\thetasym", "\\vartheta"); -defineMacro("\\weierp", "\\wp"); - -/* eslint-disable no-undef */ - -/**************************************************** - * - * physics.js - * - * Implements the Physics Package for LaTeX input. - * - * --------------------------------------------------------------------- - * - * The original version of this file is licensed as follows: - * Copyright (c) 2015-2016 Kolen Cheung . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * --------------------------------------------------------------------- - * - * This file has been revised from the original in the following ways: - * 1. The interface is changed so that it can be called from Temml, not MathJax. - * 2. \Re and \Im are not used, to avoid conflict with existing LaTeX letters. - * - * This revision of the file is released under the MIT license. - * https://mit-license.org/ - */ -defineMacro("\\quantity", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\qty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\pqty", "{\\left( #1 \\right)}"); -defineMacro("\\bqty", "{\\left[ #1 \\right]}"); -defineMacro("\\vqty", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\Bqty", "{\\left\\{ #1 \\right\\}}"); -defineMacro("\\absolutevalue", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\abs", "{\\left\\vert #1 \\right\\vert}"); -defineMacro("\\norm", "{\\left\\Vert #1 \\right\\Vert}"); -defineMacro("\\evaluated", "{\\left.#1 \\right\\vert}"); -defineMacro("\\eval", "{\\left.#1 \\right\\vert}"); -defineMacro("\\order", "{\\mathcal{O} \\left( #1 \\right)}"); -defineMacro("\\commutator", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\comm", "{\\left[ #1 , #2 \\right]}"); -defineMacro("\\anticommutator", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\acomm", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\poissonbracket", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\pb", "{\\left\\{ #1 , #2 \\right\\}}"); -defineMacro("\\vectorbold", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vb", "{\\boldsymbol{ #1 }}"); -defineMacro("\\vectorarrow", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\va", "{\\vec{\\boldsymbol{ #1 }}}"); -defineMacro("\\vectorunit", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\vu", "{{\\boldsymbol{\\hat{ #1 }}}}"); -defineMacro("\\dotproduct", "\\mathbin{\\boldsymbol\\cdot}"); -defineMacro("\\vdot", "{\\boldsymbol\\cdot}"); -defineMacro("\\crossproduct", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cross", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\cp", "\\mathbin{\\boldsymbol\\times}"); -defineMacro("\\gradient", "{\\boldsymbol\\nabla}"); -defineMacro("\\grad", "{\\boldsymbol\\nabla}"); -defineMacro("\\divergence", "{\\grad\\vdot}"); -//defineMacro("\\div", "{\\grad\\vdot}"); Not included in Temml. Conflicts w/LaTeX \div -defineMacro("\\curl", "{\\grad\\cross}"); -defineMacro("\\laplacian", "\\nabla^2"); -defineMacro("\\tr", "{\\operatorname{tr}}"); -defineMacro("\\Tr", "{\\operatorname{Tr}}"); -defineMacro("\\rank", "{\\operatorname{rank}}"); -defineMacro("\\erf", "{\\operatorname{erf}}"); -defineMacro("\\Res", "{\\operatorname{Res}}"); -defineMacro("\\principalvalue", "{\\mathcal{P}}"); -defineMacro("\\pv", "{\\mathcal{P}}"); -defineMacro("\\PV", "{\\operatorname{P.V.}}"); -// Temml does not use the next two lines. They conflict with LaTeX letters. -//defineMacro("\\Re", "{\\operatorname{Re} \\left\\{ #1 \\right\\}}"); -//defineMacro("\\Im", "{\\operatorname{Im} \\left\\{ #1 \\right\\}}"); -defineMacro("\\qqtext", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qq", "{\\quad\\text{ #1 }\\quad}"); -defineMacro("\\qcomma", "{\\text{,}\\quad}"); -defineMacro("\\qc", "{\\text{,}\\quad}"); -defineMacro("\\qcc", "{\\quad\\text{c.c.}\\quad}"); -defineMacro("\\qif", "{\\quad\\text{if}\\quad}"); -defineMacro("\\qthen", "{\\quad\\text{then}\\quad}"); -defineMacro("\\qelse", "{\\quad\\text{else}\\quad}"); -defineMacro("\\qotherwise", "{\\quad\\text{otherwise}\\quad}"); -defineMacro("\\qunless", "{\\quad\\text{unless}\\quad}"); -defineMacro("\\qgiven", "{\\quad\\text{given}\\quad}"); -defineMacro("\\qusing", "{\\quad\\text{using}\\quad}"); -defineMacro("\\qassume", "{\\quad\\text{assume}\\quad}"); -defineMacro("\\qsince", "{\\quad\\text{since}\\quad}"); -defineMacro("\\qlet", "{\\quad\\text{let}\\quad}"); -defineMacro("\\qfor", "{\\quad\\text{for}\\quad}"); -defineMacro("\\qall", "{\\quad\\text{all}\\quad}"); -defineMacro("\\qeven", "{\\quad\\text{even}\\quad}"); -defineMacro("\\qodd", "{\\quad\\text{odd}\\quad}"); -defineMacro("\\qinteger", "{\\quad\\text{integer}\\quad}"); -defineMacro("\\qand", "{\\quad\\text{and}\\quad}"); -defineMacro("\\qor", "{\\quad\\text{or}\\quad}"); -defineMacro("\\qas", "{\\quad\\text{as}\\quad}"); -defineMacro("\\qin", "{\\quad\\text{in}\\quad}"); -defineMacro("\\differential", "{\\text{d}}"); -defineMacro("\\dd", "{\\text{d}}"); -defineMacro("\\derivative", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\dv", "{\\frac{\\text{d}{ #1 }}{\\text{d}{ #2 }}}"); -defineMacro("\\partialderivative", "{\\frac{\\partial{ #1 }}{\\partial{ #2 }}}"); -defineMacro("\\variation", "{\\delta}"); -defineMacro("\\var", "{\\delta}"); -defineMacro("\\functionalderivative", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\fdv", "{\\frac{\\delta{ #1 }}{\\delta{ #2 }}}"); -defineMacro("\\innerproduct", "{\\left\\langle {#1} \\mid { #2} \\right\\rangle}"); -defineMacro("\\outerproduct", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\dyad", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\ketbra", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\op", - "{\\left\\vert { #1 } \\right\\rangle\\left\\langle { #2} \\right\\vert}"); -defineMacro("\\expectationvalue", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\expval", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\ev", "{\\left\\langle {#1 } \\right\\rangle}"); -defineMacro("\\matrixelement", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\matrixel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); -defineMacro("\\mel", - "{\\left\\langle{ #1 }\\right\\vert{ #2 }\\left\\vert{#3}\\right\\rangle}"); - -/** - * This file contains the “gullet” where macros are expanded - * until only non-macro tokens remain. - */ - -// List of commands that act like macros but aren't defined as a macro, -// function, or symbol. Used in `isDefined`. -const implicitCommands = { - "^": true, // Parser.js - _: true, // Parser.js - "\\limits": true, // Parser.js - "\\nolimits": true // Parser.js -}; - -class MacroExpander { - constructor(input, settings, mode) { - this.settings = settings; - this.expansionCount = 0; - this.feed(input); - // Make new global namespace - this.macros = new Namespace(macros, settings.macros); - this.mode = mode; - this.stack = []; // contains tokens in REVERSE order - } - - /** - * Feed a new input string to the same MacroExpander - * (with existing macros etc.). - */ - feed(input) { - this.lexer = new Lexer(input, this.settings); - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - } - - /** - * Start a new group nesting within all namespaces. - */ - beginGroup() { - this.macros.beginGroup(); - } - - /** - * End current group nesting within all namespaces. - */ - endGroup() { - this.macros.endGroup(); - } - - /** - * Returns the topmost token on the stack, without expanding it. - * Similar in behavior to TeX's `\futurelet`. - */ - future() { - if (this.stack.length === 0) { - this.pushToken(this.lexer.lex()); - } - return this.stack[this.stack.length - 1] - } - - /** - * Remove and return the next unexpanded token. - */ - popToken() { - this.future(); // ensure non-empty stack - return this.stack.pop(); - } - - /** - * Add a given token to the token stack. In particular, this get be used - * to put back a token returned from one of the other methods. - */ - pushToken(token) { - this.stack.push(token); - } - - /** - * Append an array of tokens to the token stack. - */ - pushTokens(tokens) { - this.stack.push(...tokens); - } - - /** - * Find an macro argument without expanding tokens and append the array of - * tokens to the token stack. Uses Token as a container for the result. - */ - scanArgument(isOptional) { - let start; - let end; - let tokens; - if (isOptional) { - this.consumeSpaces(); // \@ifnextchar gobbles any space following it - if (this.future().text !== "[") { - return null; - } - start = this.popToken(); // don't include [ in tokens - ({ tokens, end } = this.consumeArg(["]"])); - } else { - ({ tokens, start, end } = this.consumeArg()); - } - - // indicate the end of an argument - this.pushToken(new Token("EOF", end.loc)); - - this.pushTokens(tokens); - return start.range(end, ""); - } - - /** - * Consume all following space tokens, without expansion. - */ - consumeSpaces() { - for (;;) { - const token = this.future(); - if (token.text === " ") { - this.stack.pop(); - } else { - break; - } - } - } - - /** - * Consume an argument from the token stream, and return the resulting array - * of tokens and start/end token. - */ - consumeArg(delims) { - // The argument for a delimited parameter is the shortest (possibly - // empty) sequence of tokens with properly nested {...} groups that is - // followed ... by this particular list of non-parameter tokens. - // The argument for an undelimited parameter is the next nonblank - // token, unless that token is ‘{’, when the argument will be the - // entire {...} group that follows. - const tokens = []; - const isDelimited = delims && delims.length > 0; - if (!isDelimited) { - // Ignore spaces between arguments. As the TeXbook says: - // "After you have said ‘\def\row#1#2{...}’, you are allowed to - // put spaces between the arguments (e.g., ‘\row x n’), because - // TeX doesn’t use single spaces as undelimited arguments." - this.consumeSpaces(); - } - const start = this.future(); - let tok; - let depth = 0; - let match = 0; - do { - tok = this.popToken(); - tokens.push(tok); - if (tok.text === "{") { - ++depth; - } else if (tok.text === "}") { - --depth; - if (depth === -1) { - throw new ParseError("Extra }", tok); - } - } else if (tok.text === "EOF") { - throw new ParseError( - "Unexpected end of input in a macro argument" + - ", expected '" + - (delims && isDelimited ? delims[match] : "}") + - "'", - tok - ); - } - if (delims && isDelimited) { - if ((depth === 0 || (depth === 1 && delims[match] === "{")) && tok.text === delims[match]) { - ++match; - if (match === delims.length) { - // don't include delims in tokens - tokens.splice(-match, match); - break; - } - } else { - match = 0; - } - } - } while (depth !== 0 || isDelimited); - // If the argument found ... has the form ‘{}’, - // ... the outermost braces enclosing the argument are removed - if (start.text === "{" && tokens[tokens.length - 1].text === "}") { - tokens.pop(); - tokens.shift(); - } - tokens.reverse(); // to fit in with stack order - return { tokens, start, end: tok }; - } - - /** - * Consume the specified number of (delimited) arguments from the token - * stream and return the resulting array of arguments. - */ - consumeArgs(numArgs, delimiters) { - if (delimiters) { - if (delimiters.length !== numArgs + 1) { - throw new ParseError("The length of delimiters doesn't match the number of args!"); - } - const delims = delimiters[0]; - for (let i = 0; i < delims.length; i++) { - const tok = this.popToken(); - if (delims[i] !== tok.text) { - throw new ParseError("Use of the macro doesn't match its definition", tok); - } - } - } - - const args = []; - for (let i = 0; i < numArgs; i++) { - args.push(this.consumeArg(delimiters && delimiters[i + 1]).tokens); - } - return args; - } - - /** - * Expand the next token only once if possible. - * - * If the token is expanded, the resulting tokens will be pushed onto - * the stack in reverse order and will be returned as an array, - * also in reverse order. - * - * If not, the next token will be returned without removing it - * from the stack. This case can be detected by a `Token` return value - * instead of an `Array` return value. - * - * In either case, the next token will be on the top of the stack, - * or the stack will be empty. - * - * Used to implement `expandAfterFuture` and `expandNextToken`. - * - * If expandableOnly, only expandable tokens are expanded and - * an undefined control sequence results in an error. - */ - expandOnce(expandableOnly) { - const topToken = this.popToken(); - const name = topToken.text; - const expansion = !topToken.noexpand ? this._getExpansion(name) : null; - if (expansion == null || (expandableOnly && expansion.unexpandable)) { - if (expandableOnly && expansion == null && name[0] === "\\" && !this.isDefined(name)) { - throw new ParseError("Undefined control sequence: " + name); - } - this.pushToken(topToken); - return topToken; - } - this.expansionCount++; - if (this.expansionCount > this.settings.maxExpand) { - throw new ParseError( - "Too many expansions: infinite loop or " + "need to increase maxExpand setting" - ); - } - let tokens = expansion.tokens; - const args = this.consumeArgs(expansion.numArgs, expansion.delimiters); - if (expansion.numArgs) { - // paste arguments in place of the placeholders - tokens = tokens.slice(); // make a shallow copy - for (let i = tokens.length - 1; i >= 0; --i) { - let tok = tokens[i]; - if (tok.text === "#") { - if (i === 0) { - throw new ParseError("Incomplete placeholder at end of macro body", tok); - } - tok = tokens[--i]; // next token on stack - if (tok.text === "#") { - // ## → # - tokens.splice(i + 1, 1); // drop first # - } else if (/^[1-9]$/.test(tok.text)) { - // replace the placeholder with the indicated argument - tokens.splice(i, 2, ...args[+tok.text - 1]); - } else { - throw new ParseError("Not a valid argument number", tok); - } - } - } - } - // Concatenate expansion onto top of stack. - this.pushTokens(tokens); - return tokens; - } - - /** - * Expand the next token only once (if possible), and return the resulting - * top token on the stack (without removing anything from the stack). - * Similar in behavior to TeX's `\expandafter\futurelet`. - * Equivalent to expandOnce() followed by future(). - */ - expandAfterFuture() { - this.expandOnce(); - return this.future(); - } - - /** - * Recursively expand first token, then return first non-expandable token. - */ - expandNextToken() { - for (;;) { - const expanded = this.expandOnce(); - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - // The token after \noexpand is interpreted as if its meaning were ‘\relax’ - if (expanded.treatAsRelax) { - expanded.text = "\\relax"; - } - return this.stack.pop(); // === expanded - } - } - - // This pathway is impossible. - throw new Error(); // eslint-disable-line no-unreachable - } - - /** - * Fully expand the given macro name and return the resulting list of - * tokens, or return `undefined` if no such macro is defined. - */ - expandMacro(name) { - return this.macros.has(name) ? this.expandTokens([new Token(name)]) : undefined; - } - - /** - * Fully expand the given token stream and return the resulting list of - * tokens. Note that the input tokens are in reverse order, but the - * output tokens are in forward order. - */ - expandTokens(tokens) { - const output = []; - const oldStackLength = this.stack.length; - this.pushTokens(tokens); - while (this.stack.length > oldStackLength) { - const expanded = this.expandOnce(true); // expand only expandable tokens - // expandOnce returns Token if and only if it's fully expanded. - if (expanded instanceof Token) { - if (expanded.treatAsRelax) { - // the expansion of \noexpand is the token itself - expanded.noexpand = false; - expanded.treatAsRelax = false; - } - output.push(this.stack.pop()); - } - } - return output; - } - - /** - * Fully expand the given macro name and return the result as a string, - * or return `undefined` if no such macro is defined. - */ - expandMacroAsText(name) { - const tokens = this.expandMacro(name); - if (tokens) { - return tokens.map((token) => token.text).join(""); - } else { - return tokens; - } - } - - /** - * Returns the expanded macro as a reversed array of tokens and a macro - * argument count. Or returns `null` if no such macro. - */ - _getExpansion(name) { - const definition = this.macros.get(name); - if (definition == null) { - // mainly checking for undefined here - return definition; - } - // If a single character has an associated catcode other than 13 - // (active character), then don't expand it. - if (name.length === 1) { - const catcode = this.lexer.catcodes[name]; - if (catcode != null && catcode !== 13) { - return - } - } - const expansion = typeof definition === "function" ? definition(this) : definition; - if (typeof expansion === "string") { - let numArgs = 0; - if (expansion.indexOf("#") !== -1) { - const stripped = expansion.replace(/##/g, ""); - while (stripped.indexOf("#" + (numArgs + 1)) !== -1) { - ++numArgs; - } - } - const bodyLexer = new Lexer(expansion, this.settings); - const tokens = []; - let tok = bodyLexer.lex(); - while (tok.text !== "EOF") { - tokens.push(tok); - tok = bodyLexer.lex(); - } - tokens.reverse(); // to fit in with stack using push and pop - const expanded = { tokens, numArgs }; - return expanded; - } - - return expansion; - } - - /** - * Determine whether a command is currently "defined" (has some - * functionality), meaning that it's a macro (in the current group), - * a function, a symbol, or one of the special commands listed in - * `implicitCommands`. - */ - isDefined(name) { - return ( - this.macros.has(name) || - Object.prototype.hasOwnProperty.call(functions, name ) || - Object.prototype.hasOwnProperty.call(symbols.math, name ) || - Object.prototype.hasOwnProperty.call(symbols.text, name ) || - Object.prototype.hasOwnProperty.call(implicitCommands, name ) - ); - } - - /** - * Determine whether a command is expandable. - */ - isExpandable(name) { - const macro = this.macros.get(name); - return macro != null - ? typeof macro === "string" || typeof macro === "function" || !macro.unexpandable - : Object.prototype.hasOwnProperty.call(functions, name ) && !functions[name].primitive; - } -} - -/* - * This file defines the Unicode scripts and script families that we - * support. To add new scripts or families, just add a new entry to the - * scriptData array below. Adding scripts to the scriptData array allows - * characters from that script to appear in \text{} environments. - */ - -/** - * Each script or script family has a name and an array of blocks. - * Each block is an array of two numbers which specify the start and - * end points (inclusive) of a block of Unicode codepoints. - -/** - * Unicode block data for the families of scripts we support in \text{}. - * Scripts only need to appear here if they do not have font metrics. - */ -const scriptData = [ - { - // Latin characters beyond the Latin-1 characters we have metrics for. - // Needed for Czech, Hungarian and Turkish text, for example. - name: "latin", - blocks: [ - [0x0100, 0x024f], // Latin Extended-A and Latin Extended-B - [0x0300, 0x036f] // Combining Diacritical marks - ] - }, - { - // The Cyrillic script used by Russian and related languages. - // A Cyrillic subset used to be supported as explicitly defined - // symbols in symbols.js - name: "cyrillic", - blocks: [[0x0400, 0x04ff]] - }, - { - // Armenian - name: "armenian", - blocks: [[0x0530, 0x058f]] - }, - { - // The Brahmic scripts of South and Southeast Asia - // Devanagari (0900–097F) - // Bengali (0980–09FF) - // Gurmukhi (0A00–0A7F) - // Gujarati (0A80–0AFF) - // Oriya (0B00–0B7F) - // Tamil (0B80–0BFF) - // Telugu (0C00–0C7F) - // Kannada (0C80–0CFF) - // Malayalam (0D00–0D7F) - // Sinhala (0D80–0DFF) - // Thai (0E00–0E7F) - // Lao (0E80–0EFF) - // Tibetan (0F00–0FFF) - // Myanmar (1000–109F) - name: "brahmic", - blocks: [[0x0900, 0x109f]] - }, - { - name: "georgian", - blocks: [[0x10a0, 0x10ff]] - }, - { - // Chinese and Japanese. - // The "k" in cjk is for Korean, but we've separated Korean out - name: "cjk", - blocks: [ - [0x3000, 0x30ff], // CJK symbols and punctuation, Hiragana, Katakana - [0x4e00, 0x9faf], // CJK ideograms - [0xff00, 0xff60] // Fullwidth punctuation - // TODO: add halfwidth Katakana and Romanji glyphs - ] - }, - { - // Korean - name: "hangul", - blocks: [[0xac00, 0xd7af]] - } -]; - -/** - * A flattened version of all the supported blocks in a single array. - * This is an optimization to make supportedCodepoint() fast. - */ -const allBlocks = []; -scriptData.forEach((s) => s.blocks.forEach((b) => allBlocks.push(...b))); - -/** - * Given a codepoint, return true if it falls within one of the - * scripts or script families defined above and false otherwise. - * - * Micro benchmarks shows that this is faster than - * /[\u3000-\u30FF\u4E00-\u9FAF\uFF00-\uFF60\uAC00-\uD7AF\u0900-\u109F]/.test() - * in Firefox, Chrome and Node. - */ -function supportedCodepoint(codepoint) { - for (let i = 0; i < allBlocks.length; i += 2) { - if (codepoint >= allBlocks[i] && codepoint <= allBlocks[i + 1]) { - return true; - } - } - return false; -} - -// Mapping of Unicode accent characters to their LaTeX equivalent in text and -// math mode (when they exist). -var unicodeAccents = { - "\u0301": { text: "\\'", math: "\\acute" }, - "\u0300": { text: "\\`", math: "\\grave" }, - "\u0308": { text: '\\"', math: "\\ddot" }, - "\u0303": { text: "\\~", math: "\\tilde" }, - "\u0304": { text: "\\=", math: "\\bar" }, - "\u0306": { text: "\\u", math: "\\breve" }, - "\u030c": { text: "\\v", math: "\\check" }, - "\u0302": { text: "\\^", math: "\\hat" }, - "\u0307": { text: "\\.", math: "\\dot" }, - "\u030a": { text: "\\r", math: "\\mathring" }, - "\u030b": { text: "\\H" }, - '\u0327': { text: '\\c' } -}; - -var unicodeSymbols = { - "á": "á", - "à": "à", - "ä": "ä", - "ǟ": "ǟ", - "ã": "ã", - "ā": "ā", - "ă": "ă", - "ắ": "ắ", - "ằ": "ằ", - "ẵ": "ẵ", - "ǎ": "ǎ", - "â": "â", - "ấ": "ấ", - "ầ": "ầ", - "ẫ": "ẫ", - "ȧ": "ȧ", - "ǡ": "ǡ", - "å": "å", - "ǻ": "ǻ", - "ḃ": "ḃ", - "ć": "ć", - "č": "č", - "ĉ": "ĉ", - "ċ": "ċ", - "ď": "ď", - "ḋ": "ḋ", - "é": "é", - "è": "è", - "ë": "ë", - "ẽ": "ẽ", - "ē": "ē", - "ḗ": "ḗ", - "ḕ": "ḕ", - "ĕ": "ĕ", - "ě": "ě", - "ê": "ê", - "ế": "ế", - "ề": "ề", - "ễ": "ễ", - "ė": "ė", - "ḟ": "ḟ", - "ǵ": "ǵ", - "ḡ": "ḡ", - "ğ": "ğ", - "ǧ": "ǧ", - "ĝ": "ĝ", - "ġ": "ġ", - "ḧ": "ḧ", - "ȟ": "ȟ", - "ĥ": "ĥ", - "ḣ": "ḣ", - "í": "í", - "ì": "ì", - "ï": "ï", - "ḯ": "ḯ", - "ĩ": "ĩ", - "ī": "ī", - "ĭ": "ĭ", - "ǐ": "ǐ", - "î": "î", - "ǰ": "ǰ", - "ĵ": "ĵ", - "ḱ": "ḱ", - "ǩ": "ǩ", - "ĺ": "ĺ", - "ľ": "ľ", - "ḿ": "ḿ", - "ṁ": "ṁ", - "ń": "ń", - "ǹ": "ǹ", - "ñ": "ñ", - "ň": "ň", - "ṅ": "ṅ", - "ó": "ó", - "ò": "ò", - "ö": "ö", - "ȫ": "ȫ", - "õ": "õ", - "ṍ": "ṍ", - "ṏ": "ṏ", - "ȭ": "ȭ", - "ō": "ō", - "ṓ": "ṓ", - "ṑ": "ṑ", - "ŏ": "ŏ", - "ǒ": "ǒ", - "ô": "ô", - "ố": "ố", - "ồ": "ồ", - "ỗ": "ỗ", - "ȯ": "ȯ", - "ȱ": "ȱ", - "ő": "ő", - "ṕ": "ṕ", - "ṗ": "ṗ", - "ŕ": "ŕ", - "ř": "ř", - "ṙ": "ṙ", - "ś": "ś", - "ṥ": "ṥ", - "š": "š", - "ṧ": "ṧ", - "ŝ": "ŝ", - "ṡ": "ṡ", - "ẗ": "ẗ", - "ť": "ť", - "ṫ": "ṫ", - "ú": "ú", - "ù": "ù", - "ü": "ü", - "ǘ": "ǘ", - "ǜ": "ǜ", - "ǖ": "ǖ", - "ǚ": "ǚ", - "ũ": "ũ", - "ṹ": "ṹ", - "ū": "ū", - "ṻ": "ṻ", - "ŭ": "ŭ", - "ǔ": "ǔ", - "û": "û", - "ů": "ů", - "ű": "ű", - "ṽ": "ṽ", - "ẃ": "ẃ", - "ẁ": "ẁ", - "ẅ": "ẅ", - "ŵ": "ŵ", - "ẇ": "ẇ", - "ẘ": "ẘ", - "ẍ": "ẍ", - "ẋ": "ẋ", - "ý": "ý", - "ỳ": "ỳ", - "ÿ": "ÿ", - "ỹ": "ỹ", - "ȳ": "ȳ", - "ŷ": "ŷ", - "ẏ": "ẏ", - "ẙ": "ẙ", - "ź": "ź", - "ž": "ž", - "ẑ": "ẑ", - "ż": "ż", - "Á": "Á", - "À": "À", - "Ä": "Ä", - "Ǟ": "Ǟ", - "Ã": "Ã", - "Ā": "Ā", - "Ă": "Ă", - "Ắ": "Ắ", - "Ằ": "Ằ", - "Ẵ": "Ẵ", - "Ǎ": "Ǎ", - "Â": "Â", - "Ấ": "Ấ", - "Ầ": "Ầ", - "Ẫ": "Ẫ", - "Ȧ": "Ȧ", - "Ǡ": "Ǡ", - "Å": "Å", - "Ǻ": "Ǻ", - "Ḃ": "Ḃ", - "Ć": "Ć", - "Č": "Č", - "Ĉ": "Ĉ", - "Ċ": "Ċ", - "Ď": "Ď", - "Ḋ": "Ḋ", - "É": "É", - "È": "È", - "Ë": "Ë", - "Ẽ": "Ẽ", - "Ē": "Ē", - "Ḗ": "Ḗ", - "Ḕ": "Ḕ", - "Ĕ": "Ĕ", - "Ě": "Ě", - "Ê": "Ê", - "Ế": "Ế", - "Ề": "Ề", - "Ễ": "Ễ", - "Ė": "Ė", - "Ḟ": "Ḟ", - "Ǵ": "Ǵ", - "Ḡ": "Ḡ", - "Ğ": "Ğ", - "Ǧ": "Ǧ", - "Ĝ": "Ĝ", - "Ġ": "Ġ", - "Ḧ": "Ḧ", - "Ȟ": "Ȟ", - "Ĥ": "Ĥ", - "Ḣ": "Ḣ", - "Í": "Í", - "Ì": "Ì", - "Ï": "Ï", - "Ḯ": "Ḯ", - "Ĩ": "Ĩ", - "Ī": "Ī", - "Ĭ": "Ĭ", - "Ǐ": "Ǐ", - "Î": "Î", - "İ": "İ", - "Ĵ": "Ĵ", - "Ḱ": "Ḱ", - "Ǩ": "Ǩ", - "Ĺ": "Ĺ", - "Ľ": "Ľ", - "Ḿ": "Ḿ", - "Ṁ": "Ṁ", - "Ń": "Ń", - "Ǹ": "Ǹ", - "Ñ": "Ñ", - "Ň": "Ň", - "Ṅ": "Ṅ", - "Ó": "Ó", - "Ò": "Ò", - "Ö": "Ö", - "Ȫ": "Ȫ", - "Õ": "Õ", - "Ṍ": "Ṍ", - "Ṏ": "Ṏ", - "Ȭ": "Ȭ", - "Ō": "Ō", - "Ṓ": "Ṓ", - "Ṑ": "Ṑ", - "Ŏ": "Ŏ", - "Ǒ": "Ǒ", - "Ô": "Ô", - "Ố": "Ố", - "Ồ": "Ồ", - "Ỗ": "Ỗ", - "Ȯ": "Ȯ", - "Ȱ": "Ȱ", - "Ő": "Ő", - "Ṕ": "Ṕ", - "Ṗ": "Ṗ", - "Ŕ": "Ŕ", - "Ř": "Ř", - "Ṙ": "Ṙ", - "Ś": "Ś", - "Ṥ": "Ṥ", - "Š": "Š", - "Ṧ": "Ṧ", - "Ŝ": "Ŝ", - "Ṡ": "Ṡ", - "Ť": "Ť", - "Ṫ": "Ṫ", - "Ú": "Ú", - "Ù": "Ù", - "Ü": "Ü", - "Ǘ": "Ǘ", - "Ǜ": "Ǜ", - "Ǖ": "Ǖ", - "Ǚ": "Ǚ", - "Ũ": "Ũ", - "Ṹ": "Ṹ", - "Ū": "Ū", - "Ṻ": "Ṻ", - "Ŭ": "Ŭ", - "Ǔ": "Ǔ", - "Û": "Û", - "Ů": "Ů", - "Ű": "Ű", - "Ṽ": "Ṽ", - "Ẃ": "Ẃ", - "Ẁ": "Ẁ", - "Ẅ": "Ẅ", - "Ŵ": "Ŵ", - "Ẇ": "Ẇ", - "Ẍ": "Ẍ", - "Ẋ": "Ẋ", - "Ý": "Ý", - "Ỳ": "Ỳ", - "Ÿ": "Ÿ", - "Ỹ": "Ỹ", - "Ȳ": "Ȳ", - "Ŷ": "Ŷ", - "Ẏ": "Ẏ", - "Ź": "Ź", - "Ž": "Ž", - "Ẑ": "Ẑ", - "Ż": "Ż", - "ά": "ά", - "ὰ": "ὰ", - "ᾱ": "ᾱ", - "ᾰ": "ᾰ", - "έ": "έ", - "ὲ": "ὲ", - "ή": "ή", - "ὴ": "ὴ", - "ί": "ί", - "ὶ": "ὶ", - "ϊ": "ϊ", - "ΐ": "ΐ", - "ῒ": "ῒ", - "ῑ": "ῑ", - "ῐ": "ῐ", - "ό": "ό", - "ὸ": "ὸ", - "ύ": "ύ", - "ὺ": "ὺ", - "ϋ": "ϋ", - "ΰ": "ΰ", - "ῢ": "ῢ", - "ῡ": "ῡ", - "ῠ": "ῠ", - "ώ": "ώ", - "ὼ": "ὼ", - "Ύ": "Ύ", - "Ὺ": "Ὺ", - "Ϋ": "Ϋ", - "Ῡ": "Ῡ", - "Ῠ": "Ῠ", - "Ώ": "Ώ", - "Ὼ": "Ὼ" -}; - -/* eslint no-constant-condition:0 */ - -const numberRegEx$1 = /^\d[\d.]*$/; // Keep in sync with numberRegEx in symbolsOrd.js - -/** - * This file contains the parser used to parse out a TeX expression from the - * input. Since TeX isn't context-free, standard parsers don't work particularly - * well. - * - * The strategy of this parser is as such: - * - * The main functions (the `.parse...` ones) take a position in the current - * parse string to parse tokens from. The lexer (found in Lexer.js, stored at - * this.gullet.lexer) also supports pulling out tokens at arbitrary places. When - * individual tokens are needed at a position, the lexer is called to pull out a - * token, which is then used. - * - * The parser has a property called "mode" indicating the mode that - * the parser is currently in. Currently it has to be one of "math" or - * "text", which denotes whether the current environment is a math-y - * one or a text-y one (e.g. inside \text). Currently, this serves to - * limit the functions which can be used in text mode. - * - * The main functions then return an object which contains the useful data that - * was parsed at its given point, and a new position at the end of the parsed - * data. The main functions can call each other and continue the parsing by - * using the returned position as a new starting point. - * - * There are also extra `.handle...` functions, which pull out some reused - * functionality into self-contained functions. - * - * The functions return ParseNodes. - */ - -class Parser { - constructor(input, settings, isPreamble = false) { - // Start in math mode - this.mode = "math"; - // Create a new macro expander (gullet) and (indirectly via that) also a - // new lexer (mouth) for this parser (stomach, in the language of TeX) - this.gullet = new MacroExpander(input, settings, this.mode); - // Store the settings for use in parsing - this.settings = settings; - // Are we defining a preamble? - this.isPreamble = isPreamble; - // Count leftright depth (for \middle errors) - this.leftrightDepth = 0; - this.prevAtomType = ""; - } - - /** - * Checks a result to make sure it has the right type, and throws an - * appropriate error otherwise. - */ - expect(text, consume = true) { - if (this.fetch().text !== text) { - throw new ParseError(`Expected '${text}', got '${this.fetch().text}'`, this.fetch()); - } - if (consume) { - this.consume(); - } - } - - /** - * Discards the current lookahead token, considering it consumed. - */ - consume() { - this.nextToken = null; - } - - /** - * Return the current lookahead token, or if there isn't one (at the - * beginning, or if the previous lookahead token was consume()d), - * fetch the next token as the new lookahead token and return it. - */ - fetch() { - if (this.nextToken == null) { - this.nextToken = this.gullet.expandNextToken(); - } - return this.nextToken; - } - - /** - * Switches between "text" and "math" modes. - */ - switchMode(newMode) { - this.mode = newMode; - this.gullet.switchMode(newMode); - } - - /** - * Main parsing function, which parses an entire input. - */ - parse() { - // Create a group namespace for every $...$, $$...$$, \[...\].) - // A \def is then valid only within that pair of delimiters. - this.gullet.beginGroup(); - - if (this.settings.colorIsTextColor) { - // Use old \color behavior (same as LaTeX's \textcolor) if requested. - // We do this within the group for the math expression, so it doesn't - // pollute settings.macros. - this.gullet.macros.set("\\color", "\\textcolor"); - } - - // Try to parse the input - const parse = this.parseExpression(false); - - // If we succeeded, make sure there's an EOF at the end - this.expect("EOF"); - - if (this.isPreamble) { - const macros = Object.create(null); - Object.entries(this.gullet.macros.current).forEach(([key, value]) => { - macros[key] = value; - }); - this.gullet.endGroup(); - return macros - } - - // The only local macro that we want to save is from \tag. - const tag = this.gullet.macros.get("\\df@tag"); - - // End the group namespace for the expression - this.gullet.endGroup(); - - if (tag) { this.gullet.macros.current["\\df@tag"] = tag; } - - return parse; - } - - static get endOfExpression() { - return ["}", "\\endgroup", "\\end", "\\right", "\\endtoggle", "&"]; - } - - /** - * Parses an "expression", which is a list of atoms. - * - * `breakOnInfix`: Should the parsing stop when we hit infix nodes? This - * happens when functions have higher precendence han infix - * nodes in implicit parses. - * - * `breakOnTokenText`: The text of the token that the expression should end - * with, or `null` if something else should end the - * expression. - */ - parseExpression(breakOnInfix, breakOnTokenText) { - const body = []; - // Keep adding atoms to the body until we can't parse any more atoms (either - // we reached the end, a }, or a \right) - while (true) { - // Ignore spaces in math mode - if (this.mode === "math") { - this.consumeSpaces(); - } - const lex = this.fetch(); - if (Parser.endOfExpression.indexOf(lex.text) !== -1) { - break; - } - if (breakOnTokenText && lex.text === breakOnTokenText) { - break; - } - if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) { - break; - } - const atom = this.parseAtom(breakOnTokenText); - if (!atom) { - break; - } else if (atom.type === "internal") { - continue; - } - body.push(atom); - // Keep a record of the atom type, so that op.js can set correct spacing. - this.prevAtomType = atom.type === "atom" ? atom.family : atom.type; - } - if (this.mode === "text") { - this.formLigatures(body); - } - return this.handleInfixNodes(body); - } - - /** - * Rewrites infix operators such as \over with corresponding commands such - * as \frac. - * - * There can only be one infix operator per group. If there's more than one - * then the expression is ambiguous. This can be resolved by adding {}. - */ - handleInfixNodes(body) { - let overIndex = -1; - let funcName; - - for (let i = 0; i < body.length; i++) { - if (body[i].type === "infix") { - if (overIndex !== -1) { - throw new ParseError("only one infix operator per group", body[i].token); - } - overIndex = i; - funcName = body[i].replaceWith; - } - } - - if (overIndex !== -1 && funcName) { - let numerNode; - let denomNode; - - const numerBody = body.slice(0, overIndex); - const denomBody = body.slice(overIndex + 1); - - if (numerBody.length === 1 && numerBody[0].type === "ordgroup") { - numerNode = numerBody[0]; - } else { - numerNode = { type: "ordgroup", mode: this.mode, body: numerBody }; - } - - if (denomBody.length === 1 && denomBody[0].type === "ordgroup") { - denomNode = denomBody[0]; - } else { - denomNode = { type: "ordgroup", mode: this.mode, body: denomBody }; - } - - let node; - if (funcName === "\\\\abovefrac") { - node = this.callFunction(funcName, [numerNode, body[overIndex], denomNode], []); - } else { - node = this.callFunction(funcName, [numerNode, denomNode], []); - } - return [node]; - } else { - return body; - } - } - - /** - * Handle a subscript or superscript with nice errors. - */ - handleSupSubscript( - name // For error reporting. - ) { - const symbolToken = this.fetch(); - const symbol = symbolToken.text; - this.consume(); - this.consumeSpaces(); // ignore spaces before sup/subscript argument - const group = this.parseGroup(name); - - if (!group) { - throw new ParseError("Expected group after '" + symbol + "'", symbolToken); - } - - return group; - } - - /** - * Converts the textual input of an unsupported command into a text node - * contained within a color node whose color is determined by errorColor - */ - formatUnsupportedCmd(text) { - const textordArray = []; - - for (let i = 0; i < text.length; i++) { - textordArray.push({ type: "textord", mode: "text", text: text[i] }); - } - - const textNode = { - type: "text", - mode: this.mode, - body: textordArray - }; - - const colorNode = { - type: "color", - mode: this.mode, - color: this.settings.errorColor, - body: [textNode] - }; - - return colorNode; - } - - /** - * Parses a group with optional super/subscripts. - */ - parseAtom(breakOnTokenText) { - // The body of an atom is an implicit group, so that things like - // \left(x\right)^2 work correctly. - const base = this.parseGroup("atom", breakOnTokenText); - - // In text mode, we don't have superscripts or subscripts - if (this.mode === "text") { - return base; - } - - // Note that base may be empty (i.e. null) at this point. - - let superscript; - let subscript; - while (true) { - // Guaranteed in math mode, so eat any spaces first. - this.consumeSpaces(); - - // Lex the first token - const lex = this.fetch(); - - if (lex.text === "\\limits" || lex.text === "\\nolimits") { - // We got a limit control - if (base && base.type === "op") { - const limits = lex.text === "\\limits"; - base.limits = limits; - base.alwaysHandleSupSub = true; - } else if (base && base.type === "operatorname") { - if (base.alwaysHandleSupSub) { - base.limits = lex.text === "\\limits"; - } - } else { - throw new ParseError("Limit controls must follow a math operator", lex); - } - this.consume(); - } else if (lex.text === "^") { - // We got a superscript start - if (superscript) { - throw new ParseError("Double superscript", lex); - } - superscript = this.handleSupSubscript("superscript"); - } else if (lex.text === "_") { - // We got a subscript start - if (subscript) { - throw new ParseError("Double subscript", lex); - } - subscript = this.handleSupSubscript("subscript"); - } else if (lex.text === "'") { - // We got a prime - if (superscript) { - throw new ParseError("Double superscript", lex); - } - const prime = { type: "textord", mode: this.mode, text: "\\prime" }; - - // Many primes can be grouped together, so we handle this here - const primes = [prime]; - this.consume(); - // Keep lexing tokens until we get something that's not a prime - while (this.fetch().text === "'") { - // For each one, add another prime to the list - primes.push(prime); - this.consume(); - } - // If there's a superscript following the primes, combine that - // superscript in with the primes. - if (this.fetch().text === "^") { - primes.push(this.handleSupSubscript("superscript")); - } - // Put everything into an ordgroup as the superscript - superscript = { type: "ordgroup", mode: this.mode, body: primes }; - } else { - // If it wasn't ^, _, or ', stop parsing super/subscripts - break; - } - } - - if (superscript || subscript) { - if (base && base.type === "multiscript" && !base.postscripts) { - // base is the result of a \prescript function. - // Write the sub- & superscripts into the multiscript element. - base.postscripts = { sup: superscript, sub: subscript }; - return base - } else { - // We got either a superscript or subscript, create a supsub - return { - type: "supsub", - mode: this.mode, - base: base, - sup: superscript, - sub: subscript - } - } - } else { - // Otherwise return the original body - return base; - } - } - - /** - * Parses an entire function, including its base and all of its arguments. - */ - parseFunction( - breakOnTokenText, - name // For determining its context - ) { - const token = this.fetch(); - const func = token.text; - const funcData = functions[func]; - if (!funcData) { - return null; - } - this.consume(); // consume command token - - if (name && name !== "atom" && !funcData.allowedInArgument) { - throw new ParseError( - "Got function '" + func + "' with no arguments" + (name ? " as " + name : ""), - token - ); - } else if (this.mode === "text" && !funcData.allowedInText) { - throw new ParseError("Can't use function '" + func + "' in text mode", token); - } else if (this.mode === "math" && funcData.allowedInMath === false) { - throw new ParseError("Can't use function '" + func + "' in math mode", token); - } - - const prevAtomType = this.prevAtomType; - const { args, optArgs } = this.parseArguments(func, funcData); - this.prevAtomType = prevAtomType; - return this.callFunction(func, args, optArgs, token, breakOnTokenText); - } - - /** - * Call a function handler with a suitable context and arguments. - */ - callFunction(name, args, optArgs, token, breakOnTokenText) { - const context = { - funcName: name, - parser: this, - token, - breakOnTokenText - }; - const func = functions[name]; - if (func && func.handler) { - return func.handler(context, args, optArgs); - } else { - throw new ParseError(`No function handler for ${name}`); - } - } - - /** - * Parses the arguments of a function or environment - */ - parseArguments( - func, // Should look like "\name" or "\begin{name}". - funcData - ) { - const totalArgs = funcData.numArgs + funcData.numOptionalArgs; - if (totalArgs === 0) { - return { args: [], optArgs: [] }; - } - - const args = []; - const optArgs = []; - - for (let i = 0; i < totalArgs; i++) { - let argType = funcData.argTypes && funcData.argTypes[i]; - const isOptional = i < funcData.numOptionalArgs; - - if ( - (funcData.primitive && argType == null) || - // \sqrt expands into primitive if optional argument doesn't exist - (funcData.type === "sqrt" && i === 1 && optArgs[0] == null) - ) { - argType = "primitive"; - } - - const arg = this.parseGroupOfType(`argument to '${func}'`, argType, isOptional); - if (isOptional) { - optArgs.push(arg); - } else if (arg != null) { - args.push(arg); - } else { - // should be unreachable - throw new ParseError("Null argument, please report this as a bug"); - } - } - - return { args, optArgs }; - } - - /** - * Parses a group when the mode is changing. - */ - parseGroupOfType(name, type, optional) { - switch (type) { - case "size": - return this.parseSizeGroup(optional); - case "url": - return this.parseUrlGroup(optional); - case "math": - case "text": - return this.parseArgumentGroup(optional, type); - case "hbox": { - // hbox argument type wraps the argument in the equivalent of - // \hbox, which is like \text but switching to \textstyle size. - const group = this.parseArgumentGroup(optional, "text"); - return group != null - ? { - type: "styling", - mode: group.mode, - body: [group], - scriptLevel: "text" // simulate \textstyle - } - : null; - } - case "raw": { - const token = this.parseStringGroup("raw", optional); - return token != null - ? { - type: "raw", - mode: "text", - string: token.text - } - : null; - } - case "primitive": { - if (optional) { - throw new ParseError("A primitive argument cannot be optional"); - } - const group = this.parseGroup(name); - if (group == null) { - throw new ParseError("Expected group as " + name, this.fetch()); - } - return group; - } - case "original": - case null: - case undefined: - return this.parseArgumentGroup(optional); - default: - throw new ParseError("Unknown group type as " + name, this.fetch()); - } - } - - /** - * Discard any space tokens, fetching the next non-space token. - */ - consumeSpaces() { - while (this.fetch().text === " ") { - this.consume(); - } - } - - /** - * Parses a group, essentially returning the string formed by the - * brace-enclosed tokens plus some position information. - */ - parseStringGroup( - modeName, // Used to describe the mode in error messages. - optional - ) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF") { - str += nextToken.text; - this.consume(); - } - this.consume(); // consume the end of the argument - argToken.text = str; - return argToken; - } - - /** - * Parses a regex-delimited group: the largest sequence of tokens - * whose concatenated strings match `regex`. Returns the string - * formed by the tokens plus some position information. - */ - parseRegexGroup( - regex, - modeName // Used to describe the mode in error messages. - ) { - const firstToken = this.fetch(); - let lastToken = firstToken; - let str = ""; - let nextToken; - while ((nextToken = this.fetch()).text !== "EOF" && regex.test(str + nextToken.text)) { - lastToken = nextToken; - str += lastToken.text; - this.consume(); - } - if (str === "") { - throw new ParseError("Invalid " + modeName + ": '" + firstToken.text + "'", firstToken); - } - return firstToken.range(lastToken, str); - } - - /** - * Parses a size specification, consisting of magnitude and unit. - */ - parseSizeGroup(optional) { - let res; - let isBlank = false; - // don't expand before parseStringGroup - this.gullet.consumeSpaces(); - if (!optional && this.gullet.future().text !== "{") { - res = this.parseRegexGroup(/^[-+]? *(?:$|\d+|\d+\.\d*|\.\d*) *[a-z]{0,2} *$/, "size"); - } else { - res = this.parseStringGroup("size", optional); - } - if (!res) { - return null; - } - if (!optional && res.text.length === 0) { - // Because we've tested for what is !optional, this block won't - // affect \kern, \hspace, etc. It will capture the mandatory arguments - // to \genfrac and \above. - res.text = "0pt"; // Enable \above{} - isBlank = true; // This is here specifically for \genfrac - } - const match = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(res.text); - if (!match) { - throw new ParseError("Invalid size: '" + res.text + "'", res); - } - const data = { - number: +(match[1] + match[2]), // sign + magnitude, cast to number - unit: match[3] - }; - if (!validUnit(data)) { - throw new ParseError("Invalid unit: '" + data.unit + "'", res); - } - return { - type: "size", - mode: this.mode, - value: data, - isBlank - }; - } - - /** - * Parses an URL, checking escaped letters and allowed protocols, - * and setting the catcode of % as an active character (as in \hyperref). - */ - parseUrlGroup(optional) { - this.gullet.lexer.setCatcode("%", 13); // active character - this.gullet.lexer.setCatcode("~", 12); // other character - const res = this.parseStringGroup("url", optional); - this.gullet.lexer.setCatcode("%", 14); // comment character - this.gullet.lexer.setCatcode("~", 13); // active character - if (res == null) { - return null; - } - // hyperref package allows backslashes alone in href, but doesn't - // generate valid links in such cases; we interpret this as - // "undefined" behaviour, and keep them as-is. Some browser will - // replace backslashes with forward slashes. - let url = res.text.replace(/\\([#$%&~_^{}])/g, "$1"); - url = res.text.replace(/{\u2044}/g, "/"); - return { - type: "url", - mode: this.mode, - url - }; - } - - /** - * Parses an argument with the mode specified. - */ - parseArgumentGroup(optional, mode) { - const argToken = this.gullet.scanArgument(optional); - if (argToken == null) { - return null; - } - const outerMode = this.mode; - if (mode) { - // Switch to specified mode - this.switchMode(mode); - } - - this.gullet.beginGroup(); - const expression = this.parseExpression(false, "EOF"); - // TODO: find an alternative way to denote the end - this.expect("EOF"); // expect the end of the argument - this.gullet.endGroup(); - const result = { - type: "ordgroup", - mode: this.mode, - loc: argToken.loc, - body: expression - }; - - if (mode) { - // Switch mode back - this.switchMode(outerMode); - } - return result; - } - - /** - * Parses an ordinary group, which is either a single nucleus (like "x") - * or an expression in braces (like "{x+y}") or an implicit group, a group - * that starts at the current position, and ends right before a higher explicit - * group ends, or at EOF. - */ - parseGroup( - name, // For error reporting. - breakOnTokenText - ) { - const firstToken = this.fetch(); - const text = firstToken.text; - - let result; - // Try to parse an open brace or \begingroup - if (text === "{" || text === "\\begingroup" || text === "\\toggle") { - this.consume(); - const groupEnd = text === "{" - ? "}" - : text === "\\begingroup" - ? "\\endgroup" - : "\\endtoggle"; - - this.gullet.beginGroup(); - // If we get a brace, parse an expression - const expression = this.parseExpression(false, groupEnd); - const lastToken = this.fetch(); - this.expect(groupEnd); // Check that we got a matching closing brace - this.gullet.endGroup(); - result = { - type: (lastToken.text === "\\endtoggle" ? "toggle" : "ordgroup"), - mode: this.mode, - loc: SourceLocation.range(firstToken, lastToken), - body: expression, - // A group formed by \begingroup...\endgroup is a semi-simple group - // which doesn't affect spacing in math mode, i.e., is transparent. - // https://tex.stackexchange.com/questions/1930/when-should-one- - // use-begingroup-instead-of-bgroup - semisimple: text === "\\begingroup" || undefined - }; - } else { - // If there exists a function with this name, parse the function. - // Otherwise, just return a nucleus - result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol(); - if (result == null && text[0] === "\\" && - !Object.prototype.hasOwnProperty.call(implicitCommands, text )) { - result = this.formatUnsupportedCmd(text); - this.consume(); - } - } - return result; - } - - /** - * Form ligature-like combinations of characters for text mode. - * This includes inputs like "--", "---", "``" and "''". - * The result will simply replace multiple textord nodes with a single - * character in each value by a single textord node having multiple - * characters in its value. The representation is still ASCII source. - * The group will be modified in place. - */ - formLigatures(group) { - let n = group.length - 1; - for (let i = 0; i < n; ++i) { - const a = group[i]; - const v = a.text; - if (v === "-" && group[i + 1].text === "-") { - if (i + 1 < n && group[i + 2].text === "-") { - group.splice(i, 3, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 2]), - text: "---" - }); - n -= 2; - } else { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: "--" - }); - n -= 1; - } - } - if ((v === "'" || v === "`") && group[i + 1].text === v) { - group.splice(i, 2, { - type: "textord", - mode: "text", - loc: SourceLocation.range(a, group[i + 1]), - text: v + v - }); - n -= 1; - } - } - } - - /** - * Parse a single symbol out of the string. Here, we handle single character - * symbols and special functions like \verb. - */ - parseSymbol() { - const nucleus = this.fetch(); - let text = nucleus.text; - - if (/^\\verb[^a-zA-Z]/.test(text)) { - this.consume(); - let arg = text.slice(5); - const star = arg.charAt(0) === "*"; - if (star) { - arg = arg.slice(1); - } - // Lexer's tokenRegex is constructed to always have matching - // first/last characters. - if (arg.length < 2 || arg.charAt(0) !== arg.slice(-1)) { - throw new ParseError(`\\verb assertion failed -- - please report what input caused this bug`); - } - arg = arg.slice(1, -1); // remove first and last char - return { - type: "verb", - mode: "text", - body: arg, - star - }; - } - // At this point, we should have a symbol, possibly with accents. - // First expand any accented base symbol according to unicodeSymbols. - if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0] ) && - !symbols[this.mode][text[0]]) { - // This behavior is not strict (XeTeX-compatible) in math mode. - if (this.settings.strict && this.mode === "math") { - this.settings.reportNonstrict( - "unicodeTextInMathMode", - `Accented Unicode text character "${text[0]}" used in ` + `math mode`, - nucleus - ); - } - text = unicodeSymbols[text[0]] + text.substr(1); - } - // Strip off any combining characters - const match = combiningDiacriticalMarksEndRegex.exec(text); - if (match) { - text = text.substring(0, match.index); - if (text === "i") { - text = "\u0131"; // dotless i, in math and text mode - } else if (text === "j") { - text = "\u0237"; // dotless j, in math and text mode - } - } - // Recognize base symbol - let symbol; - if (symbols[this.mode][text]) { - const group = symbols[this.mode][text].group; - const loc = SourceLocation.range(nucleus); - let s; - if (Object.prototype.hasOwnProperty.call(ATOMS, group )) { - const family = group; - s = { - type: "atom", - mode: this.mode, - family, - loc, - text - }; - } else { - s = { - type: group, - mode: this.mode, - loc, - text - }; - } - symbol = s; - } else if (!this.strict && numberRegEx$1.test(text)) { - // A number. Wrap in a - this.consume(); - return { - type: "textord", - mode: "math", - loc: SourceLocation.range(nucleus), - text - } - } else if (text.charCodeAt(0) >= 0x80) { - // no symbol for e.g. ^ - if (this.settings.strict) { - if (!supportedCodepoint(text.charCodeAt(0))) { - this.settings.reportNonstrict( - "unknownSymbol", - `Unrecognized Unicode character "${text[0]}"` + ` (${text.charCodeAt(0)})`, - nucleus - ); - } else if (this.mode === "math") { - this.settings.reportNonstrict( - "unicodeTextInMathMode", - `Unicode text character "${text[0]}" used in math mode`, - nucleus - ); - } - } - // All nonmathematical Unicode characters are rendered as if they - // are in text mode (wrapped in \text) because that's what it - // takes to render them in LaTeX. - symbol = { - type: "textord", - mode: "text", - loc: SourceLocation.range(nucleus), - text - }; - } else { - return null; // EOF, ^, _, {, }, etc. - } - this.consume(); - // Transform combining characters into accents - if (match) { - for (let i = 0; i < match[0].length; i++) { - const accent = match[0][i]; - if (!unicodeAccents[accent]) { - throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); - } - const command = unicodeAccents[accent][this.mode] || - unicodeAccents[accent].text; - if (!command) { - throw new ParseError(`Accent ${accent} unsupported in ${this.mode} mode`, nucleus); - } - symbol = { - type: "accent", - mode: this.mode, - loc: SourceLocation.range(nucleus), - label: command, - isStretchy: false, - isShifty: true, - base: symbol - }; - } - } - return symbol; - } -} - -/** - * Parses an expression using a Parser, then returns the parsed result. - */ -const parseTree = function(toParse, settings) { - if (!(typeof toParse === "string" || toParse instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(toParse, settings); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - - let tree = parser.parse(); - - // LaTeX ignores a \tag placed outside an AMS environment. - if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) { - // If the input used \tag, it will set the \df@tag macro to the tag. - // In this case, we separately parse the tag and wrap the tree. - if (parser.gullet.macros.get("\\df@tag")) { - if (!settings.displayMode) { - throw new ParseError("\\tag works only in display equations") - } - parser.gullet.feed("\\df@tag"); - tree = [ - { - type: "tag", - mode: "text", - body: tree, - tag: parser.parse() - } - ]; - } - } - - return tree -}; - -/** - * This file contains information about the style that the Parser carries - * around with it while parsing. Data is held in an `Style` object, and when - * recursing, a new `Style` object can be created with the `.with*` functions. - */ - -const subOrSupLevel = [2, 2, 3, 3]; - -/** - * This is the main Style class. It contains the current style.level, color, and font. - * - * Style objects should not be modified. To create a new Style with - * different properties, call a `.with*` method. - */ -class Style { - constructor(data) { - // Style.level can be 0 | 1 | 2 | 3, which correspond to - // displaystyle, textstyle, scriptstyle, and scriptscriptstyle. - // style.level does not directly set MathML's script level. MathML does that itself. - // We use style.level to track, not set, math style so that we can get the - // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em. - this.level = data.level; - this.color = data.color; // string | void - // A font family applies to a group of fonts (i.e. SansSerif), while a font - // represents a specific font (i.e. SansSerif Bold). - // See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm - this.font = data.font || ""; // string - this.fontFamily = data.fontFamily || ""; // string - this.fontWeight = data.fontWeight || ""; - this.fontShape = data.fontShape || ""; - this.maxSize = data.maxSize; // number - } - - /** - * Returns a new style object with the same properties as "this". Properties - * from "extension" will be copied to the new style object. - */ - extend(extension) { - const data = { - level: this.level, - color: this.color, - font: this.font, - fontFamily: this.fontFamily, - fontWeight: this.fontWeight, - fontShape: this.fontShape, - maxSize: this.maxSize - }; - - for (const key in extension) { - if (Object.prototype.hasOwnProperty.call(extension, key)) { - data[key] = extension[key]; - } - } - - return new Style(data); - } - - withLevel(n) { - return this.extend({ - level: n - }); - } - - incrementLevel() { - return this.extend({ - level: Math.min(this.level + 1, 3) - }); - } - - inSubOrSup() { - return this.extend({ - level: subOrSupLevel[this.level] - }) - } - - /** - * Create a new style object with the given color. - */ - withColor(color) { - return this.extend({ - color: color - }); - } - - /** - * Creates a new style object with the given math font or old text font. - * @type {[type]} - */ - withFont(font) { - return this.extend({ - font - }); - } - - /** - * Create a new style objects with the given fontFamily. - */ - withTextFontFamily(fontFamily) { - return this.extend({ - fontFamily, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontWeight(fontWeight) { - return this.extend({ - fontWeight, - font: "" - }); - } - - /** - * Creates a new style object with the given font weight - */ - withTextFontShape(fontShape) { - return this.extend({ - fontShape, - font: "" - }); - } - - /** - * Gets the CSS color of the current style object - */ - getColor() { - return this.color; - } -} - -/* Temml Post Process - * Perform two tasks not done by Temml when it created each individual Temml element. - * Given a block of block, - * 1. At each AMS auto-numbered environment, assign an id. - * 2. Populate the text contents of each \ref & \eqref - * - * As with other Temml code, this file is released under terms of the MIT license. - * https://mit-license.org/ - */ - -const version = "0.4.2"; - -function postProcess(block) { - const labelMap = {}; - let i = 0; - - // Get a collection of the parents of each \tag & auto-numbered equation - const parents = block.getElementsByClassName("tml-tageqn"); - for (const parent of parents) { - const eqns = parent.getElementsByClassName("tml-eqn"); - if (eqns. length > 0 ) { - // AMS automatically numbered equation. - // Assign an id. - i += 1; - eqns[0].id = "tml-eqn-" + i; - // No need to write a number into the text content of the element. - // A CSS counter does that even if this postProcess() function is not used. - } - // If there is a \label, add it to labelMap - const labels = parent.getElementsByClassName("tml-label"); - if (labels.length === 0) { continue } - if (eqns.length > 0) { - labelMap[labels[0].id] = String(i); - } else { - const tags = parent.getElementsByClassName("tml-tag"); - if (tags.length > 0) { - labelMap[labels[0].id] = tags[0].textContent; - } - } - } - - // Populate \ref & \eqref text content - const refs = block.getElementsByClassName("tml-ref"); - [...refs].forEach(ref => { - let str = labelMap[ref.getAttribute("href").slice(1)]; - if (ref.className.indexOf("tml-eqref") === -1) { - // \ref. Omit parens. - str = str.replace(/^\(/, ""); - str = str.replace(/\($/, ""); - } { - // \eqref. Include parens - if (str.charAt(0) !== "(") { str = "(" + str; } - if (str.slice(-1) !== ")") { str = str + ")"; } - } - ref.textContent = str; - }); -} - -/* eslint no-console:0 */ - -/** - * Parse and build an expression, and place that expression in the DOM node - * given. - */ -let render = function(expression, baseNode, options) { - baseNode.textContent = ""; - const math = renderToMathMLTree(expression, options); - if (options.elementIsMath) { - // The element already exists. Populate it. - baseNode.textContent = ""; - math.children.forEach(e => { baseNode.appendChild(e.toNode()); }); - } else { - baseNode.appendChild(math.toNode()); - } -}; - -// Temml's styles don't work properly in quirks mode. Print out an error, and -// disable rendering. -if (typeof document !== "undefined") { - if (document.compatMode !== "CSS1Compat") { - typeof console !== "undefined" && - console.warn( - "Warning: Temml doesn't work in quirks mode. Make sure your " + - "website has a suitable doctype." - ); - - render = function() { - throw new ParseError("Temml doesn't work in quirks mode."); - }; - } -} - -/** - * Parse and build an expression, and return the markup for that. - */ -const renderToString = function(expression, options) { - const markup = renderToMathMLTree(expression, options).toMarkup(); - return markup; -}; - -/** - * Parse an expression and return the parse tree. - */ -const generateParseTree = function(expression, options) { - const settings = new Settings(options); - return parseTree(expression, settings); -}; - -/** - * Take an expression which contains a preamble. - * Parse it and return the macros. - */ -const definePreamble = function(expression, options) { - const settings = new Settings(options); - settings.macros = {}; - if (!(typeof expression === "string" || expression instanceof String)) { - throw new TypeError("Temml can only parse string typed expression") - } - const parser = new Parser(expression, settings, true); - // Blank out any \df@tag to avoid spurious "Duplicate \tag" errors - delete parser.gullet.macros.current["\\df@tag"]; - const macros = parser.parse(); - return macros -}; - -/** - * If the given error is a Temml ParseError, - * renders the invalid LaTeX as a span with hover title giving the Temml - * error message. Otherwise, simply throws the error. - */ -const renderError = function(error, expression, options) { - if (options.throwOnError || !(error instanceof ParseError)) { - throw error; - } - const node = new Span(["temml-error"], [new TextNode(expression)]); - node.setAttribute("title", error.toString()); - node.setAttribute("style", `color:${options.errorColor}`); - return node; -}; - -/** - * Generates and returns the Temml build tree. This is used for advanced - * use cases (like rendering to custom output). - */ -const renderToMathMLTree = function(expression, options) { - const settings = new Settings(options); - try { - const tree = parseTree(expression, settings); - const style = new Style({ - level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT, - maxSize: settings.maxSize - }); - return buildMathML(tree, expression, style, settings); - } catch (error) { - return renderError(error, expression, settings); - } -}; - -var temml = { - /** - * Current Temml version - */ - version: version, - /** - * Renders the given LaTeX into MathML, and adds - * it as a child to the specified DOM node. - */ - render, - /** - * Renders the given LaTeX into MathML string, - * for sending to the client. - */ - renderToString, - /** - * Post-process an entire HTML block. - * Writes AMS auto-numbers and implements \ref{}. - * Typcally called once, after a loop has rendered many individual spans. - */ - postProcess, - /** - * Temml error, usually during parsing. - */ - ParseError, - /** - * Creates a set of macros with document-wide scope. - */ - definePreamble, - /** - * Parses the given LaTeX into Temml's internal parse tree structure, - * without rendering to HTML or MathML. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __parse: generateParseTree, - /** - * Renders the given LaTeX into a MathML internal DOM tree - * representation, without flattening that representation to a string. - * - * NOTE: This method is not currently recommended for public use. - * The internal tree representation is unstable and is very likely - * to change. Use at your own risk. - */ - __renderToMathMLTree: renderToMathMLTree, - /** - * adds a new symbol to builtin symbols table - */ - __defineSymbol: defineSymbol, - /** - * adds a new macro to builtin macro list - */ - __defineMacro: defineMacro -}; - -export default temml; diff --git a/yarn-error.log b/yarn-error.log deleted file mode 100644 index 8c8a0d55..00000000 --- a/yarn-error.log +++ /dev/null @@ -1,5361 +0,0 @@ -Arguments: - C:\Program Files\nodejs\node.exe C:\Program Files (x86)\Yarn\bin\yarn.js build - -PATH: - C:\Python38\Scripts\;C:\Python38\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\ProgramData\chocolatey\bin;C:\Program Files (x86)\Yarn\bin\;C:\Program Files\nodejs\;C:\Users\Ronal\AppData\Local\Microsoft\WindowsApps;C:\Users\Ronal\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\Ronal\AppData\Local\GitHubDesktop\bin;C:\Users\Ronal\AppData\Local\Yarn\bin;C:\Users\Ronal\AppData\Roaming\npm;%USERPROFILE%\AppData\Local\Microsoft\WindowsApps; - -Yarn version: - 1.22.4 - -Node version: - 12.18.0 - -Platform: - win32 x64 - -Trace: - SyntaxError: C:\Users\Ronal\OneDrive\Documents\temml\package.json: Unexpected token } in JSON at position 588 - at JSON.parse () - at C:\Program Files (x86)\Yarn\lib\cli.js:1625:59 - at Generator.next () - at step (C:\Program Files (x86)\Yarn\lib\cli.js:310:30) - at C:\Program Files (x86)\Yarn\lib\cli.js:321:13 - -npm manifest: - { - "name": "temml", - "version": "0.1.0", - "description": "LaTeX to MathML conversion in JavaScript.", - "main": "dist/temml.js", - "homepage": "https://temml.org", - "repository": { - "type": "git", - "url": "git://github.com/temml/temml.git" - }, - "files": [ - "temml.js", - "src/", - "contrib/", - "dist/" - ], - "license": "MIT", - "devDependencies": { - "eslint": "^5.14.1", - "file-loader": "^3.0.1", - "json-stable-stringify": "^1.0.1", - "jspngopt": "^0.2.0", - "mkdirp": "^0.5.1", - "pako": "^1.0.8", - "rimraf": "^2.6.3", - "rollup": "^1.13.0", - }, - "scripts": { - "test": "yarn test:lint && yarn test:jest", - "test:lint": "yarn test:lint:js", - "test:lint:js": "eslint *.js src static test contrib website", - "clean": "rm -rf dist/ node_modules/", - "clean-install": "yarn clean && yarn", - "build": "rollup --config ./rollup.config.js", - "docs": "node docs/buildDocs.js", - "dist": "yarn test && yarn build && yarn dist:zip", - "dist:zip": "rimraf temml/ temml.tar.gz temml.zip && cp -R dist temml && tar czf temml.tar.gz temml && zip -rq temml.zip temml && rimraf temml/" - } - } - -yarn manifest: - No manifest - -Lockfile: - # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. - # yarn lockfile v1 - - - "@babel/code-frame@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" - integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== - dependencies: - "@babel/highlight" "^7.0.0" - - "@babel/core@>=7.1.0", "@babel/core@^7.1.0": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947" - integrity sha512-w445QGI2qd0E0GlSnq6huRZWPMmQGCp5gd5ZWS4hagn0EiwzxD5QMFkpchyusAyVC1n27OKXzQ0/88aVU9n4xQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.3.3" - "@babel/helpers" "^7.2.0" - "@babel/parser" "^7.3.3" - "@babel/template" "^7.2.2" - "@babel/traverse" "^7.2.2" - "@babel/types" "^7.3.3" - convert-source-map "^1.1.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.11" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - - "@babel/generator@^7.2.2", "@babel/generator@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e" - integrity sha512-aEADYwRRZjJyMnKN7llGIlircxTCofm3dtV5pmY6ob18MSIuipHpA2yZWkPlycwu5HJcx/pADS3zssd8eY7/6A== - dependencies: - "@babel/types" "^7.3.3" - jsesc "^2.5.1" - lodash "^4.17.11" - source-map "^0.5.0" - trim-right "^1.0.1" - - "@babel/generator@^7.4.0", "@babel/generator@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a" - integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA== - dependencies: - "@babel/types" "^7.5.0" - jsesc "^2.5.1" - lodash "^4.17.11" - source-map "^0.5.0" - trim-right "^1.0.1" - - "@babel/helper-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== - dependencies: - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - - "@babel/helper-get-function-arity@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== - dependencies: - "@babel/types" "^7.0.0" - - "@babel/helper-plugin-utils@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== - - "@babel/helper-split-export-declaration@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" - integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== - dependencies: - "@babel/types" "^7.0.0" - - "@babel/helper-split-export-declaration@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" - integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== - dependencies: - "@babel/types" "^7.4.4" - - "@babel/helpers@^7.2.0": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.3.1.tgz#949eec9ea4b45d3210feb7dc1c22db664c9e44b9" - integrity sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA== - dependencies: - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.5" - "@babel/types" "^7.3.0" - - "@babel/highlight@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" - integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" - - "@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87" - integrity sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg== - - "@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7" - integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA== - - "@babel/plugin-syntax-object-rest-spread@^7.0.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" - integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - - "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" - integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.2.2" - "@babel/types" "^7.2.2" - - "@babel/template@^7.4.0": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" - integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.4.4" - "@babel/types" "^7.4.4" - - "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2": - version "7.2.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" - integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.2.2" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.2.3" - "@babel/types" "^7.2.2" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.10" - - "@babel/traverse@^7.4.3": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485" - integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.5.0" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.5.0" - "@babel/types" "^7.5.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.11" - - "@babel/types@^7.0.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436" - integrity sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ== - dependencies: - esutils "^2.0.2" - lodash "^4.17.11" - to-fast-properties "^2.0.0" - - "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab" - integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ== - dependencies: - esutils "^2.0.2" - lodash "^4.17.11" - to-fast-properties "^2.0.0" - - "@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - - "@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - - "@rollup/plugin-node-resolve@^8.1.0": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.1.0.tgz#1da5f3d0ccabc8f66f5e3c74462aad76cfd96c47" - integrity sha512-ovq7ZM3JJYUUmEjjO+H8tnUdmQmdQudJB7xruX8LFZ1W2q8jXdPUS6SsIYip8ByOApu4RR7729Am9WhCeCMiHA== - dependencies: - "@rollup/pluginutils" "^3.0.8" - "@types/resolve" "0.0.8" - builtin-modules "^3.1.0" - deep-freeze "^0.0.1" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.14.2" - - "@rollup/pluginutils@^3.0.8": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== - dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" - - "@tootallnate/once@1": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.0.0.tgz#9c13c2574c92d4503b005feca8f2e16cc1611506" - integrity sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA== - - "@types/estree@*": - version "0.0.45" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" - integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== - - "@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - - "@types/node@*": - version "10.5.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.5.tgz#8e84d24e896cd77b0d4f73df274027e3149ec2ba" - integrity sha512-6Qnb1gXbp3g1JX9QVJj3A6ORzc9XCyhokxUKaoonHgNXcQhmk8adhotxfkeK8El9TnFeUuH72yI6jQ5nDJKS6w== - - "@types/resolve@0.0.8": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" - integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ== - dependencies: - "@types/node" "*" - - "@types/unist@*", "@types/unist@^2.0.0": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" - integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== - - "@types/vfile-message@*": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/vfile-message/-/vfile-message-1.0.1.tgz#e1e9895cc6b36c462d4244e64e6d0b6eaf65355a" - integrity sha512-mlGER3Aqmq7bqR1tTTIVHq8KSAFFRyGbrxuM8C/H82g6k7r2fS+IMEkIu3D7JHzG10NvPdR8DNx0jr0pwpp4dA== - dependencies: - "@types/node" "*" - "@types/unist" "*" - - "@types/vfile@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/vfile/-/vfile-3.0.2.tgz#19c18cd232df11ce6fa6ad80259bc86c366b09b9" - integrity sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw== - dependencies: - "@types/node" "*" - "@types/unist" "*" - "@types/vfile-message" "*" - - abab@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" - integrity sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4= - - abab@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" - integrity sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w== - - abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - - acorn-globals@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" - integrity sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ== - dependencies: - acorn "^5.0.0" - - acorn-jsx@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" - integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== - - acorn@^5.0.0, acorn@^5.5.3: - version "5.7.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" - integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== - - acorn@^6.0.7: - version "6.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.0.tgz#b0a3be31752c97a0f7013c5f4903b71a05db6818" - integrity sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw== - - acorn@^7.1.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" - integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== - - agent-base@5: - version "5.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" - integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== - - agent-base@6: - version "6.0.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a" - integrity sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw== - dependencies: - debug "4" - - ajv-errors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" - integrity sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk= - - ajv-keywords@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" - integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= - - ajv@^5.1.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - - ajv@^6.1.0, ajv@^6.9.1: - version "6.9.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1" - integrity sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - - ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - - ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - - ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - - ansi-regex@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" - integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== - - ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - - anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - - append-transform@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" - integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== - dependencies: - default-require-extensions "^2.0.0" - - aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - - are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - - argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - - argv@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" - integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= - - arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - - arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - - arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - - array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - - array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - - array-iterate@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/array-iterate/-/array-iterate-1.1.2.tgz#f66a57e84426f8097f4197fbb6c051b8e5cdf7d8" - integrity sha512-1hWSHTIlG/8wtYD+PPX5AOBtKWngpDFjrsrHgZpe+JdgNGz0udYu6ZIkAa/xuenIUEqFv7DvE2Yr60jxweJSrQ== - - array-union@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - - array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - - array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - - arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - - asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y= - - assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - - assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - - astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - - async-limiter@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== - - async@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" - integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== - dependencies: - lodash "^4.17.11" - - asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - - atob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" - integrity sha1-ri1acpR38onWDdf5amMUoi3Wwio= - - autoprefixer@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.0.1.tgz#b5b74aba3fa60b4f1403729e46a6a1246f16818f" - integrity sha512-ytUcgSKu1mZh8pCJq54BkaK7ijigK+nhqVmu8PYOR00letCkrU71qTfKnzhQgn7by/QJvlJGUAofMt+jyXJTxA== - dependencies: - browserslist "^4.0.1" - caniuse-lite "^1.0.30000865" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.1" - postcss-value-parser "^3.2.3" - - aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - - aws4@^1.6.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" - integrity sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w== - - babel-jest@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.1.0.tgz#441e23ef75ded3bd547e300ac3194cef87b55190" - integrity sha512-MLcagnVrO9ybQGLEfZUqnOzv36iQzU7Bj4elm39vCukumLVSfoX+tRy3/jW7lUKc7XdpRmB/jech6L/UCsSZjw== - dependencies: - babel-plugin-istanbul "^5.1.0" - babel-preset-jest "^24.1.0" - chalk "^2.4.2" - slash "^2.0.0" - - babel-plugin-istanbul@^5.1.0: - version "5.1.4" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.4.tgz#841d16b9a58eeb407a0ddce622ba02fe87a752ba" - integrity sha512-dySz4VJMH+dpndj0wjJ8JPs/7i1TdSPb1nRrn56/92pKOF9VKC1FMFJmMXjzlGGusnCAqujP6PBCiKq0sVA+YQ== - dependencies: - find-up "^3.0.0" - istanbul-lib-instrument "^3.3.0" - test-exclude "^5.2.3" - - babel-plugin-jest-hoist@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.1.0.tgz#dfecc491fb15e2668abbd690a697a8fd1411a7f8" - integrity sha512-gljYrZz8w1b6fJzKcsfKsipSru2DU2DmQ39aB6nV3xQ0DDv3zpIzKGortA5gknrhNnPN8DweaEgrnZdmbGmhnw== - - babel-preset-jest@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.1.0.tgz#83bc564fdcd4903641af65ec63f2f5de6b04132e" - integrity sha512-FfNLDxFWsNX9lUmtwY7NheGlANnagvxq8LZdl5PKnVG3umP+S/g0XbVBfwtA4Ai3Ri/IMkWabBz3Tyk9wdspcw== - dependencies: - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^24.1.0" - - babylon@^6.15.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - - bail@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.3.tgz#63cfb9ddbac829b02a3128cd53224be78e6c21a3" - integrity sha512-1X8CnjFVQ+a+KW36uBNMTU5s8+v5FzeqrP7hTG5aTb4aPreSbZJlhwPon9VKMuEVgV++JM+SQrALY3kr7eswdg== - - balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - - base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - - bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - - big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - - brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - - braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - - browser-process-hrtime@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" - integrity sha1-Ql1opY00R/AqBKqJQYf86K+Le44= - - browser-resolve@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - - browserslist@^4.0.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.1.tgz#bd400d1aea56538580e8c4d5f1c54ac11b5ab468" - integrity sha512-QtULFqKIAtiyNx7NhZ/p4rB8m3xDozVo/pi5VgTlADLF2tNigz/QH+v0m5qhn7XfHT7u+607NcCNOnC0HZAlMg== - dependencies: - caniuse-lite "^1.0.30000999" - electron-to-chromium "^1.3.284" - node-releases "^1.1.36" - - bser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" - integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk= - dependencies: - node-int64 "^0.4.0" - - buffer-crc32@^0.2.5: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - - buffer-from@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" - integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== - - builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - - builtin-modules@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" - integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== - - cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - - call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - - caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - - caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - - callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - - callsites@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" - integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== - - camelcase-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" - integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= - dependencies: - camelcase "^4.1.0" - map-obj "^2.0.0" - quick-lru "^1.0.0" - - camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - - camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - - caniuse-lite@^1.0.30000865, caniuse-lite@^1.0.30000999: - version "1.0.30001002" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001002.tgz#ba999a737b1abd5bf0fd47efe43a09b9cadbe9b0" - integrity sha512-pRuxPE8wdrWmVPKcDmJJiGBxr6lFJq4ivdSeo9FTmGj5Rb8NX3Mby2pARG57MXF15hYAhZ0nHV5XxT2ig4bz3g== - - capture-exit@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" - integrity sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28= - dependencies: - rsvp "^3.3.3" - - caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - - ccount@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.3.tgz#f1cec43f332e2ea5a569fd46f9f5bde4e6102aff" - integrity sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw== - - chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - - character-entities-html4@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.2.tgz#c44fdde3ce66b52e8d321d6c1bf46101f0150610" - integrity sha512-sIrXwyna2+5b0eB9W149izTPJk/KkJTg6mEzDGibwBUkyH1SbDa+nf515Ppdi3MaH35lW0JFJDWeq9Luzes1Iw== - - character-entities-legacy@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.2.tgz#7c6defb81648498222c9855309953d05f4d63a9c" - integrity sha512-9NB2VbXtXYWdXzqrvAHykE/f0QJxzaKIpZ5QzNZrrgQ7Iyxr2vnfS8fCBNVW9nUEZE0lo57nxKRqnzY/dKrwlA== - - character-entities@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.2.tgz#58c8f371c0774ef0ba9b2aca5f00d8f100e6e363" - integrity sha512-sMoHX6/nBiy3KKfC78dnEalnpn0Az0oSNvqUWYTtYrhRI5iUIYsROU48G+E+kMFQzqXaJ8kHJZ85n7y6/PHgwQ== - - character-reference-invalid@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz#21e421ad3d84055952dab4a43a04e73cd425d3ed" - integrity sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ== - - chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - - chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= - - ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - - class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - - cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - - cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - - cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - - clone-regexp@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.1.tgz#051805cd33173375d82118fc0918606da39fd60f" - integrity sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw== - dependencies: - is-regexp "^1.0.0" - is-supported-regexp-flag "^1.0.0" - - co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - - code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - - codecov@^3.2.0: - version "3.6.5" - resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.6.5.tgz#d73ce62e8a021f5249f54b073e6f2d6a513f172a" - integrity sha512-v48WuDMUug6JXwmmfsMzhCHRnhUf8O3duqXvltaYJKrO1OekZWpB/eH6iIoaxMl8Qli0+u3OxptdsBOYiD7VAQ== - dependencies: - argv "0.0.2" - ignore-walk "3.0.3" - js-yaml "3.13.1" - teeny-request "6.0.1" - urlgrey "0.4.4" - - collapse-white-space@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.4.tgz#ce05cf49e54c3277ae573036a26851ba430a0091" - integrity sha512-YfQ1tAUZm561vpYD+5eyWN8+UsceQbSrqqlc/6zDY2gtAE+uZLSdkkovhnGpmCThsvKBFakq4EdY/FF93E8XIw== - - collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - - color-convert@^1.9.0: - version "1.9.2" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" - integrity sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg== - dependencies: - color-name "1.1.1" - - color-name@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" - integrity sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok= - - combined-stream@1.0.6, combined-stream@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - integrity sha1-cj599ugBrFYTETp+RFqbactjKBg= - dependencies: - delayed-stream "~1.0.0" - - commander@~2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - - compare-versions@^3.2.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.3.1.tgz#1ede3172b713c15f7c7beb98cb74d2d82576dad3" - integrity sha512-GkIcfJ9sDt4+gS+RWH3X+kR7ezuKdu3fg2oA9nRA8HZoqZwAKv3ml3TyfB9OyV2iFXxCw7q5XfV6SyPbSCT2pw== - - component-emitter@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= - - concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - - console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - - convert-source-map@^1.1.0, convert-source-map@^1.4.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= - - copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - - core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - - cosmiconfig@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" - integrity sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ== - dependencies: - is-directory "^0.3.1" - js-yaml "^3.9.0" - parse-json "^4.0.0" - require-from-string "^2.0.1" - - cosmiconfig@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.1.0.tgz#6c5c35e97f37f985061cdf653f114784231185cf" - integrity sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.9.0" - lodash.get "^4.4.2" - parse-json "^4.0.0" - - cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - - cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797" - integrity sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog== - - cssstyle@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.0.0.tgz#79b16d51ec5591faec60e688891f15d2a5705129" - integrity sha512-Bpuh47j2mRMY60X90mXaJAEtJwxvA2roZzbgwAXYhMbmwmakdRr4Cq9L5SkleKJNLOKqHIa2YWyOXDX3VgggSQ== - dependencies: - cssom "0.3.x" - - currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - - dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - - data-urls@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.0.0.tgz#24802de4e81c298ea8a9388bb0d8e461c774684f" - integrity sha512-ai40PPQR0Fn1lD2PPie79CibnlMN2AYiDhwFX/rZHVsxbs5kNJSjegqXIprhouGXlRdEnfybva7kqRGnB6mypA== - dependencies: - abab "^1.0.4" - whatwg-mimetype "^2.0.0" - whatwg-url "^6.4.0" - - debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - - debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - - decamelize-keys@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - - decamelize@^1.1.0, decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - - decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - - deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - - deep-freeze@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" - integrity sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ= - - deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - - deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - - default-require-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" - integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= - dependencies: - strip-bom "^3.0.0" - - define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" - integrity sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ= - dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" - - define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - - define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - - define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - - delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - - delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - - detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - - detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= - - diff-sequences@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.0.0.tgz#cdf8e27ed20d8b8d3caccb4e0c0d8fe31a173013" - integrity sha512-46OkIuVGBBnrC0soO/4LHu5LHGHx0uhP65OVz8XOrAJpqiCB2aVIuESvjI1F9oqebuvY8lekS1pt6TN7vt7qsw== - - diffable-html@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/diffable-html/-/diffable-html-4.0.0.tgz#eb44a189785115bacd04829f31658fcd3c0ce590" - integrity sha512-keJdgy2qBkdrrnwP1YE6e834d4Y+mV0aRFzk8w7WzyAJVbQVfcJltSmUWB3r/NOoO/0jt7RdJlvy5ioyqvmQcw== - dependencies: - htmlparser2 "^3.9.2" - - dir-glob@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - - doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - - dom-serializer@0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" - integrity sha1-BzxpdUbOB4DOI75KKOKT5AvDDII= - dependencies: - domelementtype "~1.1.1" - entities "~1.1.1" - - domelementtype@1, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - - domelementtype@~1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" - integrity sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs= - - domexception@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== - dependencies: - webidl-conversions "^4.0.2" - - domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - - domutils@^1.5.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - - dot-prop@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" - integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== - dependencies: - is-obj "^1.0.0" - - ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - integrity sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU= - dependencies: - jsbn "~0.1.0" - - electron-to-chromium@^1.3.284: - version "1.3.293" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.293.tgz#e52a30026b89276e211be36083a4d7136fd480ea" - integrity sha512-DQSBRuU2Z1vG+CEWUIfCEVMHtuaGlhVojzg39mX5dx7PLSFDJ7DSrGUWzaPFFgWR1jo26hj1nXXRQZvFwk7F8w== - - emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - - emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - - end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== - dependencies: - once "^1.4.0" - - entities@^1.1.1, entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= - - error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - - es-abstract@^1.5.1: - version "1.13.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" - integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== - dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" - has "^1.0.3" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-keys "^1.0.12" - - es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - - escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - - escodegen@^1.9.1: - version "1.11.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589" - integrity sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw== - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - - eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - - eslint-utils@^1.3.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" - integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== - dependencies: - eslint-visitor-keys "^1.0.0" - - eslint-visitor-keys@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" - integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== - - eslint@^5.14.1: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.2.3" - text-table "^0.2.0" - - espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== - dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - - esprima@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= - - esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - - esquery@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== - dependencies: - estraverse "^4.0.0" - - esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - dependencies: - estraverse "^4.1.0" - - estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - - estree-walker@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.2.1.tgz#bdafe8095383d8414d5dc2ecf4c9173b6db9412e" - integrity sha1-va/oCVOD2EFNXcLs9MkXO225QS4= - - estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== - - esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - - exec-sh@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== - dependencies: - merge "^1.2.0" - - execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - - execall@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execall/-/execall-1.0.0.tgz#73d0904e395b3cab0658b08d09ec25307f29bb73" - integrity sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M= - dependencies: - clone-regexp "^1.0.0" - - exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - - expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - expect@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.1.0.tgz#88e73301c4c785cde5f16da130ab407bdaf8c0f2" - integrity sha512-lVcAPhaYkQcIyMS+F8RVwzbm1jro20IG8OkvxQ6f1JfqhVZyyudCwYogQ7wnktlf14iF3ii7ArIUO/mqvrW9Gw== - dependencies: - ansi-styles "^3.2.0" - jest-get-type "^24.0.0" - jest-matcher-utils "^24.0.0" - jest-message-util "^24.0.0" - jest-regex-util "^24.0.0" - - extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - - extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - - extend@^3.0.0, extend@~3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - - external-editor@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" - integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - - extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - - extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - - fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= - - fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - - fast-glob@^2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.6.tgz#a5d5b697ec8deda468d85a74035290a025a95295" - integrity sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - - fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - - fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - - fb-watchman@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" - integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= - dependencies: - bser "^2.0.0" - - figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - - file-entry-cache@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-4.0.0.tgz#633567d15364aefe0b299e1e217735e8f3a9f6e8" - integrity sha512-AVSwsnbV8vH/UVbvgEhf3saVQXORNv0ZzSkvkhQIaia5Tia+JhGTaa/ePUSVoPHQyGayQNmYfkzFi3WZV5zcpA== - dependencies: - flat-cache "^2.0.1" - - file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - - file-loader@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" - integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== - dependencies: - loader-utils "^1.0.2" - schema-utils "^1.0.0" - - fileset@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" - integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= - dependencies: - glob "^7.0.3" - minimatch "^3.0.3" - - fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - - find-up@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - - find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - - flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - - flatted@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" - integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== - - flow-bin@^0.102.0: - version "0.102.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.102.0.tgz#3d5de44bcc26d26585e932b3201988b766f9b380" - integrity sha512-mYon6noeLO0Q5SbiWULLQeM1L96iuXnRtYMd47j3bEWXAwUW9EnwNWcn+cZg/jC/Dg4Wj/jnkdTDEuFtbeu1ww== - - flow-parser@^0.132.0: - version "0.132.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.132.0.tgz#68c9aea4cfd84577337559a6f121ef3ab687a251" - integrity sha512-y1P37zDCPSdphlk+w+roCqcOar6iQdNaAJldJ6xx5/2r4ZRv4KHO+qL+AXwPWp+34eN+oPxPjWnU7GybJnyISQ== - - flow-remove-types@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/flow-remove-types/-/flow-remove-types-1.2.3.tgz#6131aefc7da43364bb8b479758c9dec7735d1a18" - integrity sha512-ypq/U3V+t9atYiOuSJd40tekCra03EHKoRsiK/wXGrsZimuum0kdwVY7Yv0HTaoXgHW1WiayomYd+Q3kkvPl9Q== - dependencies: - babylon "^6.15.0" - vlq "^0.2.1" - - flow-remove-types@^2.132.0: - version "2.132.0" - resolved "https://registry.yarnpkg.com/flow-remove-types/-/flow-remove-types-2.132.0.tgz#7adc416336f96eb00a8603df4aef919e8b648e28" - integrity sha512-J1EfutfdC68xEZ8i44Hdlaa3MnONuQQB4/+wtnw/ontdcwuz/yGAVQ/O35dFIqNaQoCUWNDN1mHHagbRYLfihQ== - dependencies: - flow-parser "^0.132.0" - pirates "^3.0.2" - vlq "^0.2.1" - - for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - - foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - - forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - - form-data@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" - integrity sha1-SXBJi+YEwgwAXU9cI67NIda0kJk= - dependencies: - asynckit "^0.4.0" - combined-stream "1.0.6" - mime-types "^2.1.12" - - fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - - fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - - fs-minipass@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" - integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== - dependencies: - minipass "^2.2.1" - - fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - - fsevents@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== - dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" - - function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - - functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - - gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - - get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - - get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - - get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - - get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - - getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - - glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - - glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - - glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - - global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - - global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - - globals@^11.1.0, globals@^11.7.0: - version "11.7.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" - integrity sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg== - - globby@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-9.0.0.tgz#3800df736dc711266df39b4ce33fe0d481f94c23" - integrity sha512-q0qiO/p1w/yJ0hk8V9x1UXlgsXUxlGd0AHUOXZVXBO6aznDtpx7M8D1kBrCAItoPm+4l8r6ATXV1JpjY2SBQOw== - dependencies: - array-union "^1.0.2" - dir-glob "^2.2.1" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - - globjoin@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" - integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= - - gonzales-pe@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.3.tgz#41091703625433285e0aee3aa47829fc1fbeb6f2" - integrity sha512-Kjhohco0esHQnOiqqdJeNz/5fyPkOMD/d6XVjwTAoPGUFh0mCollPUTUTa2OZy4dYNAqlPIQdTiNzJTWdd9Htw== - dependencies: - minimist "1.1.x" - - graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.15" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" - integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== - - growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - - handlebars@^4.1.0: - version "4.5.3" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482" - integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA== - dependencies: - neo-async "^2.6.0" - optimist "^0.6.1" - source-map "^0.6.1" - optionalDependencies: - uglify-js "^3.1.4" - - har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - - har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - integrity sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0= - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - - has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - - has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - - has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - - has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - - has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - - has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - - has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - - has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - - hosted-git-info@^2.1.4: - version "2.7.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" - integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== - - html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== - dependencies: - whatwg-encoding "^1.0.1" - - html-tags@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" - integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= - - htmlparser2@^3.10.0, htmlparser2@^3.9.2: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - - http-proxy-agent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - - http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - - https-proxy-agent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" - integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== - dependencies: - agent-base "5" - debug "4" - - iconv-lite@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== - - iconv-lite@^0.4.24, iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - - ignore-walk@3.0.3, ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - - ignore@^4.0.3, ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - - ignore@^5.0.4: - version "5.0.5" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.0.5.tgz#c663c548d6ce186fb33616a8ccb5d46e56bdbbf9" - integrity sha512-kOC8IUb8HSDMVcYrDVezCxpJkzSQWTAzf3olpKM6o9rM5zpojx23O0Fl8Wr4+qJ6ZbPEHqf1fdwev/DS7v7pmA== - - import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - - import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - - import-fresh@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" - integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - - import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - - import-lazy@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" - integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== - - import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - - imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - - indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= - - indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - - inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - - inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - - ini@^1.3.5, ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - - inquirer@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406" - integrity sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.11" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.0.0" - through "^2.3.6" - - invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - - invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - - is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - - is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - - is-alphabetical@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.2.tgz#1fa6e49213cb7885b75d15862fb3f3d96c884f41" - integrity sha512-V0xN4BYezDHcBSKb1QHUFMlR4as/XEuCZBzMJUU4n7+Cbt33SmUnSol+pnXFvLxSHNq2CemUXNdaXV6Flg7+xg== - - is-alphanumeric@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4" - integrity sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ= - - is-alphanumerical@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.2.tgz#1138e9ae5040158dc6ff76b820acd6b7a181fd40" - integrity sha512-pyfU/0kHdISIgslFfZN9nfY1Gk3MquQgUm1mJTjdkEPpkAKNWuBTSqFwewOpR7N351VkErCiyV71zX7mlQQqsg== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - - is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - - is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - - is-buffer@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" - integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== - - is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= - dependencies: - builtin-modules "^1.0.0" - - is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== - - is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - - is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - - is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - - is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= - - is-decimal@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.2.tgz#894662d6a8709d307f3a276ca4339c8fa5dff0ff" - integrity sha512-TRzl7mOCchnhchN+f3ICUCzYvL9ul7R+TYOsZ8xia++knyZAJfv/uA1FvQXsAnYIl1T3B2X5E/J7Wb1QXiIBXg== - - is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - - is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - - is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - - is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - - is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - - is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - - is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - - is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - - is-generator-fn@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.0.0.tgz#038c31b774709641bda678b1f06a4e3227c10b3e" - integrity sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g== - - is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - - is-glob@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= - dependencies: - is-extglob "^2.1.1" - - is-hexadecimal@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz#b6e710d7d07bb66b98cb8cece5c9b4921deeb835" - integrity sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A== - - is-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" - integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= - - is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - - is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - - is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - - is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - - is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - - is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" - - is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= - - is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - - is-supported-regexp-flag@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz#21ee16518d2c1dd3edd3e9a0d57e50207ac364ca" - integrity sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ== - - is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== - dependencies: - has-symbols "^1.0.0" - - is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - - is-whitespace-character@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz#ede53b4c6f6fb3874533751ec9280d01928d03ed" - integrity sha512-SzM+T5GKUCtLhlHFKt2SDAX2RFzfS6joT91F2/WSi9LxgFdsnhfPK/UIA+JhRR2xuyLdrCys2PiFDrtn1fU5hQ== - - is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - - is-word-character@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.2.tgz#46a5dac3f2a1840898b91e576cd40d493f3ae553" - integrity sha512-T3FlsX8rCHAH8e7RE7PfOPZVFQlcV3XRF9eOOBQ1uf70OxO7CjjSOjeImMPCADBdYWcStAbVbYvJ1m2D3tb+EA== - - isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - - isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - - isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - - isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - - isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - - istanbul-api@^2.0.8: - version "2.1.1" - resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.1.1.tgz#194b773f6d9cbc99a9258446848b0f988951c4d0" - integrity sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw== - dependencies: - async "^2.6.1" - compare-versions "^3.2.1" - fileset "^2.0.3" - istanbul-lib-coverage "^2.0.3" - istanbul-lib-hook "^2.0.3" - istanbul-lib-instrument "^3.1.0" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.2" - istanbul-reports "^2.1.1" - js-yaml "^3.12.0" - make-dir "^1.3.0" - minimatch "^3.0.4" - once "^1.4.0" - - istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.3, istanbul-lib-coverage@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== - - istanbul-lib-hook@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz#e0e581e461c611be5d0e5ef31c5f0109759916fb" - integrity sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA== - dependencies: - append-transform "^1.0.0" - - istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.1.0, istanbul-lib-instrument@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" - integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== - dependencies: - "@babel/generator" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" - istanbul-lib-coverage "^2.0.5" - semver "^6.0.0" - - istanbul-lib-report@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz#bfd324ee0c04f59119cb4f07dab157d09f24d7e4" - integrity sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA== - dependencies: - istanbul-lib-coverage "^2.0.3" - make-dir "^1.3.0" - supports-color "^6.0.0" - - istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz#f1e817229a9146e8424a28e5d69ba220fda34156" - integrity sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^2.0.3" - make-dir "^1.3.0" - rimraf "^2.6.2" - source-map "^0.6.1" - - istanbul-reports@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.1.1.tgz#72ef16b4ecb9a4a7bd0e2001e00f95d1eec8afa9" - integrity sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw== - dependencies: - handlebars "^4.1.0" - - jest-changed-files@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.0.0.tgz#c02c09a8cc9ca93f513166bc773741bd39898ff7" - integrity sha512-nnuU510R9U+UX0WNb5XFEcsrMqriSiRLeO9KWDFgPrpToaQm60prfQYpxsXigdClpvNot5bekDY440x9dNGnsQ== - dependencies: - execa "^1.0.0" - throat "^4.0.0" - - jest-cli@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.1.0.tgz#f7cc98995f36e7210cce3cbb12974cbf60940843" - integrity sha512-U/iyWPwOI0T1CIxVLtk/2uviOTJ/OiSWJSe8qt6X1VkbbgP+nrtLJlmT9lPBe4lK78VNFJtrJ7pttcNv/s7yCw== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.1.15" - import-local "^2.0.0" - is-ci "^2.0.0" - istanbul-api "^2.0.8" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-source-maps "^3.0.1" - jest-changed-files "^24.0.0" - jest-config "^24.1.0" - jest-environment-jsdom "^24.0.0" - jest-get-type "^24.0.0" - jest-haste-map "^24.0.0" - jest-message-util "^24.0.0" - jest-regex-util "^24.0.0" - jest-resolve-dependencies "^24.1.0" - jest-runner "^24.1.0" - jest-runtime "^24.1.0" - jest-snapshot "^24.1.0" - jest-util "^24.0.0" - jest-validate "^24.0.0" - jest-watcher "^24.0.0" - jest-worker "^24.0.0" - micromatch "^3.1.10" - node-notifier "^5.2.1" - p-each-series "^1.0.0" - pirates "^4.0.0" - prompts "^2.0.1" - realpath-native "^1.0.0" - rimraf "^2.5.4" - slash "^2.0.0" - string-length "^2.0.0" - strip-ansi "^5.0.0" - which "^1.2.12" - yargs "^12.0.2" - - jest-config@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.1.0.tgz#6ea6881cfdd299bc86cc144ee36d937c97c3850c" - integrity sha512-FbbRzRqtFC6eGjG5VwsbW4E5dW3zqJKLWYiZWhB0/4E5fgsMw8GODLbGSrY5t17kKOtCWb/Z7nsIThRoDpuVyg== - dependencies: - "@babel/core" "^7.1.0" - babel-jest "^24.1.0" - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^24.0.0" - jest-environment-node "^24.0.0" - jest-get-type "^24.0.0" - jest-jasmine2 "^24.1.0" - jest-regex-util "^24.0.0" - jest-resolve "^24.1.0" - jest-util "^24.0.0" - jest-validate "^24.0.0" - micromatch "^3.1.10" - pretty-format "^24.0.0" - realpath-native "^1.0.2" - - jest-diff@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.0.0.tgz#a3e5f573dbac482f7d9513ac9cfa21644d3d6b34" - integrity sha512-XY5wMpRaTsuMoU+1/B2zQSKQ9RdE9gsLkGydx3nvApeyPijLA8GtEvIcPwISRCer+VDf9W1mStTYYq6fPt8ryA== - dependencies: - chalk "^2.0.1" - diff-sequences "^24.0.0" - jest-get-type "^24.0.0" - pretty-format "^24.0.0" - - jest-docblock@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.0.0.tgz#54d77a188743e37f62181a91a01eb9222289f94e" - integrity sha512-KfAKZ4SN7CFOZpWg4i7g7MSlY0M+mq7K0aMqENaG2vHuhC9fc3vkpU/iNN9sOus7v3h3Y48uEjqz3+Gdn2iptA== - dependencies: - detect-newline "^2.1.0" - - jest-each@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.0.0.tgz#10987a06b21c7ffbfb7706c89d24c52ed864be55" - integrity sha512-gFcbY4Cu55yxExXMkjrnLXov3bWO3dbPAW7HXb31h/DNWdNc/6X8MtxGff8nh3/MjkF9DpVqnj0KsPKuPK0cpA== - dependencies: - chalk "^2.0.1" - jest-get-type "^24.0.0" - jest-util "^24.0.0" - pretty-format "^24.0.0" - - jest-environment-jsdom@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.0.0.tgz#5affa0654d6e44cd798003daa1a8701dbd6e4d11" - integrity sha512-1YNp7xtxajTRaxbylDc2pWvFnfDTH5BJJGyVzyGAKNt/lEULohwEV9zFqTgG4bXRcq7xzdd+sGFws+LxThXXOw== - dependencies: - jest-mock "^24.0.0" - jest-util "^24.0.0" - jsdom "^11.5.1" - - jest-environment-node@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.0.0.tgz#330948980656ed8773ce2e04eb597ed91e3c7190" - integrity sha512-62fOFcaEdU0VLaq8JL90TqwI7hLn0cOKOl8vY2n477vRkCJRojiRRtJVRzzCcgFvs6gqU97DNqX5R0BrBP6Rxg== - dependencies: - jest-mock "^24.0.0" - jest-util "^24.0.0" - - jest-get-type@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.0.0.tgz#36e72930b78e33da59a4f63d44d332188278940b" - integrity sha512-z6/Eyf6s9ZDGz7eOvl+fzpuJmN9i0KyTt1no37/dHu8galssxz5ZEgnc1KaV8R31q1khxyhB4ui/X5ZjjPk77w== - - jest-haste-map@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.0.0.tgz#e9ef51b2c9257384b4d6beb83bd48c65b37b5e6e" - integrity sha512-CcViJyUo41IQqttLxXVdI41YErkzBKbE6cS6dRAploCeutePYfUimWd3C9rQEWhX0YBOQzvNsC0O9nYxK2nnxQ== - dependencies: - fb-watchman "^2.0.0" - graceful-fs "^4.1.15" - invariant "^2.2.4" - jest-serializer "^24.0.0" - jest-util "^24.0.0" - jest-worker "^24.0.0" - micromatch "^3.1.10" - sane "^3.0.0" - - jest-jasmine2@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.1.0.tgz#8377324b967037c440f0a549ee0bbd9912055db6" - integrity sha512-H+o76SdSNyCh9fM5K8upK45YTo/DiFx5w2YAzblQebSQmukDcoVBVeXynyr7DDnxh+0NTHYRCLwJVf3tC518wg== - dependencies: - "@babel/traverse" "^7.1.0" - chalk "^2.0.1" - co "^4.6.0" - expect "^24.1.0" - is-generator-fn "^2.0.0" - jest-each "^24.0.0" - jest-matcher-utils "^24.0.0" - jest-message-util "^24.0.0" - jest-snapshot "^24.1.0" - jest-util "^24.0.0" - pretty-format "^24.0.0" - throat "^4.0.0" - - jest-leak-detector@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.0.0.tgz#78280119fd05ee98317daee62cddb3aa537a31c6" - integrity sha512-ZYHJYFeibxfsDSKowjDP332pStuiFT2xfc5R67Rjm/l+HFJWJgNIOCOlQGeXLCtyUn3A23+VVDdiCcnB6dTTrg== - dependencies: - pretty-format "^24.0.0" - - jest-matcher-utils@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.0.0.tgz#fc9c41cfc49b2c3ec14e576f53d519c37729d579" - integrity sha512-LQTDmO+aWRz1Tf9HJg+HlPHhDh1E1c65kVwRFo5mwCVp5aQDzlkz4+vCvXhOKFjitV2f0kMdHxnODrXVoi+rlA== - dependencies: - chalk "^2.0.1" - jest-diff "^24.0.0" - jest-get-type "^24.0.0" - pretty-format "^24.0.0" - - jest-message-util@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.0.0.tgz#a07a141433b2c992dbaec68d4cbfe470ba289619" - integrity sha512-J9ROJIwz/IeC+eV1XSwnRK4oAwPuhmxEyYx1+K5UI+pIYwFZDSrfZaiWTdq0d2xYFw4Xiu+0KQWsdsQpgJMf3Q== - dependencies: - "@babel/code-frame" "^7.0.0" - chalk "^2.0.1" - micromatch "^3.1.10" - slash "^2.0.0" - stack-utils "^1.0.1" - - jest-mock@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.0.0.tgz#9a4b53e01d66a0e780f7d857462d063e024c617d" - integrity sha512-sQp0Hu5fcf5NZEh1U9eIW2qD0BwJZjb63Yqd98PQJFvf/zzUTBoUAwv/Dc/HFeNHIw1f3hl/48vNn+j3STaI7A== - - jest-regex-util@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.0.0.tgz#4feee8ec4a358f5bee0a654e94eb26163cb9089a" - integrity sha512-Jv/uOTCuC+PY7WpJl2mpoI+WbY2ut73qwwO9ByJJNwOCwr1qWhEW2Lyi2S9ZewUdJqeVpEBisdEVZSI+Zxo58Q== - - jest-resolve-dependencies@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.1.0.tgz#78f738a2ec59ff4d00751d9da56f176e3f589f6c" - integrity sha512-2VwPsjd3kRPu7qe2cpytAgowCObk5AKeizfXuuiwgm1a9sijJDZe8Kh1sFj6FKvSaNEfCPlBVkZEJa2482m/Uw== - dependencies: - jest-regex-util "^24.0.0" - jest-snapshot "^24.1.0" - - jest-resolve@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.1.0.tgz#42ff0169b0ea47bfdbd0c52a0067ca7d022c7688" - integrity sha512-TPiAIVp3TG6zAxH28u/6eogbwrvZjBMWroSLBDkwkHKrqxB/RIdwkWDye4uqPlZIXWIaHtifY3L0/eO5Z0f2wg== - dependencies: - browser-resolve "^1.11.3" - chalk "^2.0.1" - realpath-native "^1.0.0" - - jest-runner@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.1.0.tgz#3686a2bb89ce62800da23d7fdc3da2c32792943b" - integrity sha512-CDGOkT3AIFl16BLL/OdbtYgYvbAprwJ+ExKuLZmGSCSldwsuU2dEGauqkpvd9nphVdAnJUcP12e/EIlnTX0QXg== - dependencies: - chalk "^2.4.2" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-config "^24.1.0" - jest-docblock "^24.0.0" - jest-haste-map "^24.0.0" - jest-jasmine2 "^24.1.0" - jest-leak-detector "^24.0.0" - jest-message-util "^24.0.0" - jest-runtime "^24.1.0" - jest-util "^24.0.0" - jest-worker "^24.0.0" - source-map-support "^0.5.6" - throat "^4.0.0" - - jest-runtime@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.1.0.tgz#7c157a2e776609e8cf552f956a5a19ec9c985214" - integrity sha512-59/BY6OCuTXxGeDhEMU7+N33dpMQyXq7MLK07cNSIY/QYt2QZgJ7Tjx+rykBI0skAoigFl0A5tmT8UdwX92YuQ== - dependencies: - "@babel/core" "^7.1.0" - babel-plugin-istanbul "^5.1.0" - chalk "^2.0.1" - convert-source-map "^1.4.0" - exit "^0.1.2" - fast-json-stable-stringify "^2.0.0" - glob "^7.1.3" - graceful-fs "^4.1.15" - jest-config "^24.1.0" - jest-haste-map "^24.0.0" - jest-message-util "^24.0.0" - jest-regex-util "^24.0.0" - jest-resolve "^24.1.0" - jest-snapshot "^24.1.0" - jest-util "^24.0.0" - jest-validate "^24.0.0" - micromatch "^3.1.10" - realpath-native "^1.0.0" - slash "^2.0.0" - strip-bom "^3.0.0" - write-file-atomic "2.4.1" - yargs "^12.0.2" - - jest-serializer-html@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/jest-serializer-html/-/jest-serializer-html-6.0.0.tgz#39ce49a42b3937d1687f93923814d21b47ae9a85" - integrity sha512-S855oT9Yt1T07I45+uRaLsH22TR5lAvgqBxKreqDKs6QmcaxzapGgKamc4J2KxMrPc2uDdWcuOaprcjIuVUxvQ== - dependencies: - diffable-html "^4.0.0" - - jest-serializer@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.0.0.tgz#522c44a332cdd194d8c0531eb06a1ee5afb4256b" - integrity sha512-9FKxQyrFgHtx3ozU+1a8v938ILBE7S8Ko3uiAVjT8Yfi2o91j/fj81jacCQZ/Ihjiff/VsUCXVgQ+iF1XdImOw== - - jest-snapshot@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.1.0.tgz#85e22f810357aa5994ab61f236617dc2205f2f5b" - integrity sha512-th6TDfFqEmXvuViacU1ikD7xFb7lQsPn2rJl7OEmnfIVpnrx3QNY2t3PE88meeg0u/mQ0nkyvmC05PBqO4USFA== - dependencies: - "@babel/types" "^7.0.0" - chalk "^2.0.1" - jest-diff "^24.0.0" - jest-matcher-utils "^24.0.0" - jest-message-util "^24.0.0" - jest-resolve "^24.1.0" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - pretty-format "^24.0.0" - semver "^5.5.0" - - jest-util@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.0.0.tgz#fd38fcafd6dedbd0af2944d7a227c0d91b68f7d6" - integrity sha512-QxsALc4wguYS7cfjdQSOr5HTkmjzkHgmZvIDkcmPfl1ib8PNV8QUWLwbKefCudWS0PRKioV+VbQ0oCUPC691fQ== - dependencies: - callsites "^3.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.15" - is-ci "^2.0.0" - jest-message-util "^24.0.0" - mkdirp "^0.5.1" - slash "^2.0.0" - source-map "^0.6.0" - - jest-validate@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.0.0.tgz#aa8571a46983a6538328fef20406b4a496b6c020" - integrity sha512-vMrKrTOP4BBFIeOWsjpsDgVXATxCspC9S1gqvbJ3Tnn/b9ACsJmteYeVx9830UMV28Cob1RX55x96Qq3Tfad4g== - dependencies: - camelcase "^5.0.0" - chalk "^2.0.1" - jest-get-type "^24.0.0" - leven "^2.1.0" - pretty-format "^24.0.0" - - jest-watcher@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.0.0.tgz#20d44244d10b0b7312410aefd256c1c1eef68890" - integrity sha512-GxkW2QrZ4YxmW1GUWER05McjVDunBlKMFfExu+VsGmXJmpej1saTEKvONdx5RJBlVdpPI5x6E3+EDQSIGgl53g== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.1" - jest-util "^24.0.0" - string-length "^2.0.0" - - jest-worker@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d" - integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg== - dependencies: - merge-stream "^1.0.1" - supports-color "^6.1.0" - - jest@^24.1.0: - version "24.1.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-24.1.0.tgz#b1e1135caefcf2397950ecf7f90e395fde866fd2" - integrity sha512-+q91L65kypqklvlRFfXfdzUKyngQLOcwGhXQaLmVHv+d09LkNXuBuGxlofTFW42XMzu3giIcChchTsCNUjQ78A== - dependencies: - import-local "^2.0.0" - jest-cli "^24.1.0" - - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - - js-yaml@3.13.1, js-yaml@^3.12.0, js-yaml@^3.12.1, js-yaml@^3.13.0, js-yaml@^3.9.0: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - - jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - - jsdom@^11.5.1: - version "11.12.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" - integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== - dependencies: - abab "^2.0.0" - acorn "^5.5.3" - acorn-globals "^4.1.0" - array-equal "^1.0.0" - cssom ">= 0.3.2 < 0.4.0" - cssstyle "^1.0.0" - data-urls "^1.0.0" - domexception "^1.0.1" - escodegen "^1.9.1" - html-encoding-sniffer "^1.0.2" - left-pad "^1.3.0" - nwsapi "^2.0.7" - parse5 "4.0.0" - pn "^1.1.0" - request "^2.87.0" - request-promise-native "^1.0.5" - sax "^1.2.4" - symbol-tree "^3.2.2" - tough-cookie "^2.3.4" - w3c-hr-time "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.3" - whatwg-mimetype "^2.1.0" - whatwg-url "^6.4.1" - ws "^5.2.0" - xml-name-validator "^3.0.0" - - jsesc@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" - integrity sha1-5CGiqOINawgZ3yiQj3glJrlt0f4= - - json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - - json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= - - json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - - json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - - json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - - json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - - json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - - json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - - json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== - dependencies: - minimist "^1.2.0" - - jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - - jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - - jspngopt@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/jspngopt/-/jspngopt-0.2.0.tgz#a05e4625bc64ef06a54f11763bc90b75a2dcf815" - integrity sha1-oF5GJbxk7walTxF2O8kLdaLc+BU= - dependencies: - buffer-crc32 "^0.2.5" - - jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - - kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - - kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - - kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - - kleur@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.2.tgz#83c7ec858a41098b613d5998a7b653962b504f68" - integrity sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q== - - known-css-properties@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.11.0.tgz#0da784f115ea77c76b81536d7052e90ee6c86a8a" - integrity sha512-bEZlJzXo5V/ApNNa5z375mJC6Nrz4vG43UgcSCrg2OHC+yuB6j0iDSrY7RQ/+PRofFB03wNIIt9iXIVLr4wc7w== - - lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - - left-pad@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" - integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== - - leven@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= - - levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - - load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - - loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" - integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== - dependencies: - big.js "^5.2.2" - emojis-list "^2.0.0" - json5 "^1.0.1" - - locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - - locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - - lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= - - lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - - lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4: - version "4.17.14" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" - integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== - - log-symbols@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - - longest-streak@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e" - integrity sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA== - - loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - - loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - - make-dir@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - - makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= - dependencies: - tmpl "1.0.x" - - map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== - dependencies: - p-defer "^1.0.0" - - map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - - map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - - map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= - - map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - - markdown-escapes@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.2.tgz#e639cbde7b99c841c0bacc8a07982873b46d2122" - integrity sha512-lbRZ2mE3Q9RtLjxZBZ9+IMl68DKIXaVAhwvwn9pmjnPLS0h/6kyBMgNhqi1xFJ/2yv6cSyv0jbiZavZv93JkkA== - - markdown-table@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.2.tgz#c78db948fa879903a41bce522e3b96f801c63786" - integrity sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw== - - mathml-tag-names@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.0.tgz#490b70e062ee24636536e3d9481e333733d00f2c" - integrity sha512-3Zs9P/0zzwTob2pdgT0CHZuMbnSUSp8MB1bddfm+HDmnFWHGT4jvEZRf+2RuPoa+cjdn/z25SEt5gFTqdhvJAg== - - mdast-util-compact@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.1.tgz#cdb5f84e2b6a2d3114df33bd05d9cb32e3c4083a" - integrity sha1-zbX4TitqLTEU3zO9BdnLMuPECDo= - dependencies: - unist-util-modify-children "^1.0.0" - unist-util-visit "^1.1.0" - - mem@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.1.0.tgz#aeb9be2d21f47e78af29e4ac5978e8afa2ca5b8a" - integrity sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^1.0.0" - p-is-promise "^2.0.0" - - meow@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" - - merge-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= - dependencies: - readable-stream "^2.0.1" - - merge2@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5" - integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA== - - merge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" - integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== - - micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - - mime-db@~1.35.0: - version "1.35.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" - integrity sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg== - - mime-types@^2.1.12, mime-types@~2.1.17: - version "2.1.19" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" - integrity sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw== - dependencies: - mime-db "~1.35.0" - - mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - - minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - - minimist-options@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" - integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - - minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - - minimist@1.1.x: - version "1.1.3" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" - integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= - - minimist@^1.1.1, minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - - minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= - - minipass@^2.2.1, minipass@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" - integrity sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - - minizlib@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" - integrity sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA== - dependencies: - minipass "^2.2.1" - - mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - - mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - - ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - - ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - - mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - - nan@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== - - nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - - needle@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" - integrity sha512-t/ZswCM9JTWjAdXS9VpvqhI2Ct2sL2MdY4fUXqGJaGBk13ge99ObqRksRTbBE56K+wxUXwwfZYOuZHifFW9q+Q== - dependencies: - debug "^2.1.2" - iconv-lite "^0.4.4" - sax "^1.2.4" - - neo-async@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" - integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== - - nice-try@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" - integrity sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA== - - node-fetch@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" - integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== - - node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - - node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - - node-notifier@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" - integrity sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg== - dependencies: - growly "^1.3.0" - semver "^5.4.1" - shellwords "^0.1.1" - which "^1.3.0" - - node-pre-gyp@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - - node-releases@^1.1.36: - version "1.1.38" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.38.tgz#d81b365df2936654ba37f509ba2fbe91eff2578b" - integrity sha512-/5NZAaOyTj134Oy5Cp/J8mso8OD/D9CSuL+6TOXXsTKO8yjc5e4up75SRPCganCjwFKMj2jbp5tR0dViVdox7g== - dependencies: - semver "^6.3.0" - - nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - - normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - - normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - - normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - - normalize-selector@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" - integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM= - - npm-bundled@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" - integrity sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow== - - npm-packlist@^1.1.6: - version "1.1.11" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" - integrity sha512-CxKlZ24urLkJk+9kCm48RTQ7L4hsmgSVzEk0TLGPzzyuFxD7VNgy5Sl24tOLMzQv773a/NeJ1ce1DKeacqffEA== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - - npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - - npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - - num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - - number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - - nwsapi@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.7.tgz#6fc54c254621f10cac5225b76e81c74120139b78" - integrity sha512-VZXniaaaORAXGCNsvUNefsKRQYk8zCzQZ57jalgrpHcU70OrAzKAiN/3plYtH/VPRmZeYyUzQiYfKzcMXC1g5Q== - - oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - - object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - - object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - - object-keys@^1.0.12, object-keys@^1.0.8: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" - integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg== - - object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - - object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" - - object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - - once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - - onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - - optimist@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - - optionator@^0.8.1, optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - - os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - - os-locale@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== - dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - - os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - - osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - - p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - - p-each-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= - dependencies: - p-reduce "^1.0.0" - - p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - - p-is-promise@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" - integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg== - - p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - - p-limit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" - integrity sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A== - dependencies: - p-try "^2.0.0" - - p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - - p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - - p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= - - p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - - p-try@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" - integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== - - pako@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4" - integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA== - - parent-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.0.tgz#df250bdc5391f4a085fb589dad761f5ad6b865b5" - integrity sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA== - dependencies: - callsites "^3.0.0" - - parse-entities@^1.0.2, parse-entities@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.1.2.tgz#9eaf719b29dc3bd62246b4332009072e01527777" - integrity sha512-5N9lmQ7tmxfXf+hO3X6KRG6w7uYO/HL9fHalSySTdyn63C3WNvTM/1R8tn1u1larNcEbo3Slcy2bsVDQqvEpUg== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - - parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - - parse5@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" - integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== - - pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - - path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - - path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - - path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - - path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - - path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - - path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - - path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - - performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - - picomatch@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - - pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - - pify@^4.0.0, pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - - pirates@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-3.0.2.tgz#7e6f85413fd9161ab4e12b539b06010d85954bb9" - integrity sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q== - dependencies: - node-modules-regexp "^1.0.0" - - pirates@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.0.tgz#850b18781b4ac6ec58a43c9ed9ec5fe6796addbd" - integrity sha512-8t5BsXy1LUIjn3WWOlOuFDuKswhQb/tkak641lvBgmPOBUQHXveORtlMCp6OdPV1dtuTaEahKA8VNz6uLfKBtA== - dependencies: - node-modules-regexp "^1.0.0" - - pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - - pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - - posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - - postcss-html@^0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204" - integrity sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw== - dependencies: - htmlparser2 "^3.10.0" - - postcss-jsx@^0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/postcss-jsx/-/postcss-jsx-0.36.0.tgz#b7685ed3d070a175ef0aa48f83d9015bd772c82d" - integrity sha512-/lWOSXSX5jlITCKFkuYU2WLFdrncZmjSVyNpHAunEgirZXLwI8RjU556e3Uz4mv0WVHnJA9d3JWb36lK9Yx99g== - dependencies: - "@babel/core" ">=7.1.0" - - postcss-less@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-3.1.2.tgz#fb67e7ba351dbdf69de3c52eebd1184c52bfaea6" - integrity sha512-66ZBVo1JGkQ7r13M97xcHcyarWpgg21RaqIZWZXHE3XOtb5+ywK1uZWeY1DYkYRkIX/l8Hvxnx9iSKB68nFr+w== - dependencies: - postcss "^7.0.14" - - postcss-load-config@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484" - integrity sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ== - dependencies: - cosmiconfig "^4.0.0" - import-cwd "^2.0.0" - - postcss-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" - integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== - dependencies: - loader-utils "^1.1.0" - postcss "^7.0.0" - postcss-load-config "^2.0.0" - schema-utils "^1.0.0" - - postcss-markdown@^0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/postcss-markdown/-/postcss-markdown-0.36.0.tgz#7f22849ae0e3db18820b7b0d5e7833f13a447560" - integrity sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ== - dependencies: - remark "^10.0.1" - unist-util-find-all-after "^1.0.2" - - postcss-media-query-parser@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" - integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= - - postcss-reporter@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-6.0.0.tgz#44c873129d8c029a430b6d2186210d79c8de88b8" - integrity sha512-5xQXm1UPWuFObjbtyQzWvQaupru8yFcFi4HUlm6OPo1o2bUszYASuqRJ7bVArb3svGCdbYtqdMBKrqR1Aoy+tw== - dependencies: - chalk "^2.0.1" - lodash "^4.17.4" - log-symbols "^2.0.0" - postcss "^7.0.2" - - postcss-resolve-nested-selector@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= - - postcss-safe-parser@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz#8756d9e4c36fdce2c72b091bbc8ca176ab1fcdea" - integrity sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ== - dependencies: - postcss "^7.0.0" - - postcss-sass@^0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.3.5.tgz#6d3e39f101a53d2efa091f953493116d32beb68c" - integrity sha512-B5z2Kob4xBxFjcufFnhQ2HqJQ2y/Zs/ic5EZbCywCkxKd756Q40cIQ/veRDwSrw1BF6+4wUgmpm0sBASqVi65A== - dependencies: - gonzales-pe "^4.2.3" - postcss "^7.0.1" - - postcss-scss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.0.0.tgz#248b0a28af77ea7b32b1011aba0f738bda27dea1" - integrity sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug== - dependencies: - postcss "^7.0.0" - - postcss-selector-parser@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" - integrity sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU= - dependencies: - dot-prop "^4.1.1" - indexes-of "^1.0.1" - uniq "^1.0.1" - - postcss-syntax@^0.36.2: - version "0.36.2" - resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c" - integrity sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w== - - postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - - postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.2: - version "7.0.17" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" - integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - - prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - - pretty-format@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0.tgz#cb6599fd73ac088e37ed682f61291e4678f48591" - integrity sha512-LszZaKG665djUcqg5ZQq+XzezHLKrxsA86ZABTozp+oNhkdqa+tG2dX4qa6ERl5c/sRDrAa3lHmwnvKoP+OG/g== - dependencies: - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - - process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== - - progress@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" - integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8= - - prompts@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.0.3.tgz#c5ccb324010b2e8f74752aadceeb57134c1d2522" - integrity sha512-H8oWEoRZpybm6NV4to9/1limhttEo13xK62pNvn2JzY0MA03p7s0OjtmhXyon3uJmxiJJVSuUwEJFFssI3eBiQ== - dependencies: - kleur "^3.0.2" - sisteransi "^1.0.0" - - psl@^1.1.24: - version "1.1.28" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" - integrity sha512-+AqO1Ae+N/4r7Rvchrdm432afjT9hqJRyBN3DQv9At0tPz4hIFSGKbq64fN9dVoCow4oggIIax5/iONx0r9hZw== - - pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - - punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - - punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - - qs@~6.5.1: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - - query-string@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.2.0.tgz#468edeb542b7e0538f9f9b1aeb26f034f19c86e1" - integrity sha512-5wupExkIt8RYL4h/FE+WTg3JHk62e6fFPWtAZA9J5IWK1PfTfKkMS93HBUHcFpeYi9KsY5pFbh+ldvEyaz5MyA== - dependencies: - decode-uri-component "^0.2.0" - strict-uri-encode "^2.0.0" - - quick-lru@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" - integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= - - rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - - read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - - read-pkg-up@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" - integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== - dependencies: - find-up "^3.0.0" - read-pkg "^3.0.0" - - read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - - readable-stream@^2.0.1, readable-stream@^2.0.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - - readable-stream@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" - integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - - realpath-native@^1.0.0, realpath-native@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" - integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== - dependencies: - util.promisify "^1.0.0" - - redent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" - integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= - dependencies: - indent-string "^3.0.0" - strip-indent "^2.0.0" - - regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - - regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - - remark-parse@^6.0.0: - version "6.0.3" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-6.0.3.tgz#c99131052809da482108413f87b0ee7f52180a3a" - integrity sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg== - dependencies: - collapse-white-space "^1.0.2" - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - is-word-character "^1.0.0" - markdown-escapes "^1.0.0" - parse-entities "^1.1.0" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - trim "0.0.1" - trim-trailing-lines "^1.0.0" - unherit "^1.0.4" - unist-util-remove-position "^1.0.0" - vfile-location "^2.0.0" - xtend "^4.0.1" - - remark-stringify@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-6.0.4.tgz#16ac229d4d1593249018663c7bddf28aafc4e088" - integrity sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg== - dependencies: - ccount "^1.0.0" - is-alphanumeric "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - longest-streak "^2.0.1" - markdown-escapes "^1.0.0" - markdown-table "^1.1.0" - mdast-util-compact "^1.0.0" - parse-entities "^1.0.2" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - stringify-entities "^1.0.1" - unherit "^1.0.4" - xtend "^4.0.1" - - remark@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/remark/-/remark-10.0.1.tgz#3058076dc41781bf505d8978c291485fe47667df" - integrity sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ== - dependencies: - remark-parse "^6.0.0" - remark-stringify "^6.0.0" - unified "^7.0.0" - - remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - - repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= - - repeat-string@^1.5.4, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - - replace-ext@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" - integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= - - request-promise-core@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" - integrity sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY= - dependencies: - lodash "^4.13.1" - - request-promise-native@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" - integrity sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU= - dependencies: - request-promise-core "1.1.1" - stealthy-require "^1.1.0" - tough-cookie ">=2.3.3" - - request@^2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - - require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - - require-from-string@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - - require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - - require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - - resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - - resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - - resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - - resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - - resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - - resolve@^1.14.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - - resolve@^1.3.2: - version "1.10.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" - integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== - dependencies: - path-parse "^1.0.6" - - restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - - ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - - rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - - rollup-plugin-flow@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-flow/-/rollup-plugin-flow-1.1.1.tgz#6ce568f1dd559666b77ab76b4bae251407528db6" - integrity sha1-bOVo8d1Vlma3erdrS64lFAdSjbY= - dependencies: - flow-remove-types "^1.1.0" - rollup-pluginutils "^1.5.1" - - rollup-pluginutils@^1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408" - integrity sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg= - dependencies: - estree-walker "^0.2.1" - minimatch "^3.0.2" - - rollup@^1.13.0: - version "1.32.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4" - integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A== - dependencies: - "@types/estree" "*" - "@types/node" "*" - acorn "^7.1.0" - - rsvp@^3.3.3: - version "3.6.2" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" - integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== - - run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" - - rxjs@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" - integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== - dependencies: - tslib "^1.9.0" - - safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - - safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - - "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - - sane@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" - integrity sha512-G5GClRRxT1cELXfdAq7UKtUsv8q/ZC5k8lQGmjEm4HcAl3HzBy68iglyNCmw4+0tiXPCBZntslHlRhbnsSws+Q== - dependencies: - anymatch "^2.0.0" - capture-exit "^1.2.0" - exec-sh "^0.2.0" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - watch "~0.18.0" - optionalDependencies: - fsevents "^1.2.3" - - sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - - schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - - "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== - - semver@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" - integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== - - semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - - set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - - set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" - - set-value@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - - shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - - shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - - shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - - signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - - sisteransi@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" - integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ== - - slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - - slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - - snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - - snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - - snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - - source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - - source-map-support@^0.5.6: - version "0.5.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" - integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - - source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - - source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - - spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" - integrity sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - - spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" - integrity sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg== - - spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - - spdx-license-ids@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== - - specificity@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" - integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== - - split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - - sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - - sshpk@^1.7.0: - version "1.14.2" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" - integrity sha1-xvxhZIo9nE52T9P8306hBeSSupg= - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - safer-buffer "^2.0.2" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - - stack-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" - integrity sha1-1PM6tU6OOHeLDKXP07OvsS22hiA= - - state-toggle@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.1.tgz#c3cb0974f40a6a0f8e905b96789eb41afa1cde3a" - integrity sha512-Qe8QntFrrpWTnHwvwj2FZTgv+PKIsp0B9VxLzLLbSpPXWOgRgc5LVj/aTiSfK1RqIeF9jeC1UeOH8Q8y60A7og== - - static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - - stealthy-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - - stream-events@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" - integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== - dependencies: - stubs "^3.0.0" - - strict-uri-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - - string-length@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" - integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= - dependencies: - astral-regex "^1.0.0" - strip-ansi "^4.0.0" - - string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - - "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - - string-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.0.0.tgz#5a1690a57cc78211fffd9bf24bbe24d090604eb1" - integrity sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.0.0" - - string_decoder@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" - integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== - dependencies: - safe-buffer "~5.1.0" - - string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - - stringify-entities@^1.0.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.2.tgz#a98417e5471fd227b3e45d3db1861c11caf668f7" - integrity sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A== - dependencies: - character-entities-html4 "^1.0.0" - character-entities-legacy "^1.0.0" - is-alphanumerical "^1.0.0" - is-hexadecimal "^1.0.0" - - strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - - strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - - strip-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" - integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== - dependencies: - ansi-regex "^4.0.0" - - strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - - strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - - strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= - - strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - - stubs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" - integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= - - style-loader@^0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" - integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== - dependencies: - loader-utils "^1.1.0" - schema-utils "^1.0.0" - - style-search@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" - integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= - - stylelint-config-recommended@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-2.1.0.tgz#f526d5c771c6811186d9eaedbed02195fee30858" - integrity sha512-ajMbivOD7JxdsnlS5945KYhvt7L/HwN6YeYF2BH6kE4UCLJR0YvXMf+2j7nQpJyYLZx9uZzU5G1ZOSBiWAc6yA== - - stylelint-config-standard@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-18.2.0.tgz#6283149aba7f64f18731aef8f0abfb35cf619e06" - integrity sha512-07x0TaSIzvXlbOioUU4ORkCIM07kyIuojkbSVCyFWNVgXMXYHfhnQSCkqu+oHWJf3YADAnPGWzdJ53NxkoJ7RA== - dependencies: - stylelint-config-recommended "^2.1.0" - - stylelint@^9.10.1: - version "9.10.1" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.10.1.tgz#5f0ee3701461dff1d68284e1386efe8f0677a75d" - integrity sha512-9UiHxZhOAHEgeQ7oLGwrwoDR8vclBKlSX7r4fH0iuu0SfPwFaLkb1c7Q2j1cqg9P7IDXeAV2TvQML/fRQzGBBQ== - dependencies: - autoprefixer "^9.0.0" - balanced-match "^1.0.0" - chalk "^2.4.1" - cosmiconfig "^5.0.0" - debug "^4.0.0" - execall "^1.0.0" - file-entry-cache "^4.0.0" - get-stdin "^6.0.0" - global-modules "^2.0.0" - globby "^9.0.0" - globjoin "^0.1.4" - html-tags "^2.0.0" - ignore "^5.0.4" - import-lazy "^3.1.0" - imurmurhash "^0.1.4" - known-css-properties "^0.11.0" - leven "^2.1.0" - lodash "^4.17.4" - log-symbols "^2.0.0" - mathml-tag-names "^2.0.1" - meow "^5.0.0" - micromatch "^3.1.10" - normalize-selector "^0.2.0" - pify "^4.0.0" - postcss "^7.0.13" - postcss-html "^0.36.0" - postcss-jsx "^0.36.0" - postcss-less "^3.1.0" - postcss-markdown "^0.36.0" - postcss-media-query-parser "^0.2.3" - postcss-reporter "^6.0.0" - postcss-resolve-nested-selector "^0.1.1" - postcss-safe-parser "^4.0.0" - postcss-sass "^0.3.5" - postcss-scss "^2.0.0" - postcss-selector-parser "^3.1.0" - postcss-syntax "^0.36.2" - postcss-value-parser "^3.3.0" - resolve-from "^4.0.0" - signal-exit "^3.0.2" - slash "^2.0.0" - specificity "^0.4.1" - string-width "^3.0.0" - style-search "^0.1.0" - sugarss "^2.0.0" - svg-tags "^1.0.0" - table "^5.0.0" - - sugarss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" - integrity sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ== - dependencies: - postcss "^7.0.2" - - supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - - supports-color@^6.0.0, supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - - svg-tags@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" - integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= - - symbol-tree@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" - integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY= - - table@^5.0.0, table@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2" - integrity sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ== - dependencies: - ajv "^6.9.1" - lodash "^4.17.11" - slice-ansi "^2.1.0" - string-width "^3.0.0" - - tar@^4: - version "4.4.4" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" - integrity sha512-mq9ixIYfNF9SK0IS/h2HKMu8Q2iaCuhDDsZhdEag/FHv8fOaYld4vN7ouMgcSSt5WKZzPs8atclTcJm36OTh4w== - dependencies: - chownr "^1.0.1" - fs-minipass "^1.2.5" - minipass "^2.3.3" - minizlib "^1.1.0" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.2" - - teeny-request@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-6.0.1.tgz#9b1f512cef152945827ba7e34f62523a4ce2c5b0" - integrity sha512-TAK0c9a00ELOqLrZ49cFxvPVogMUFaWY8dUsQc/0CuQPGF+BOxOQzXfE413BAk2kLomwNplvdtMpeaeGWmoc2g== - dependencies: - http-proxy-agent "^4.0.0" - https-proxy-agent "^4.0.0" - node-fetch "^2.2.0" - stream-events "^1.0.5" - uuid "^3.3.2" - - test-exclude@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" - integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== - dependencies: - glob "^7.1.3" - minimatch "^3.0.4" - read-pkg-up "^4.0.0" - require-main-filename "^2.0.0" - - text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - - throat@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= - - through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - - tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - - tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= - - to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - - to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - - to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - - to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - - tough-cookie@>=2.3.3, tough-cookie@^2.3.4: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - - tough-cookie@~2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA== - dependencies: - punycode "^1.4.1" - - tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - - trim-newlines@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" - integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= - - trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - - trim-trailing-lines@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.1.tgz#e0ec0810fd3c3f1730516b45f49083caaf2774d9" - integrity sha512-bWLv9BbWbbd7mlqqs2oQYnLD/U/ZqeJeJwbO0FG2zA1aTq+HTvxfHNKFa/HGCVyJpDiioUYaBhfiT6rgk+l4mg== - - trim@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= - - trough@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.2.tgz#7f1663ec55c480139e2de5e486c6aef6cc24a535" - integrity sha512-FHkoUZvG6Egrv9XZAyYGKEyb1JMsFphgPjoczkZC2y6W93U1jswcVURB8MUvtsahEPEVACyxD47JAL63vF4JsQ== - - tslib@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== - - tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - - tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - - type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - - uglify-js@^3.1.4: - version "3.7.2" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.2.tgz#cb1a601e67536e9ed094a92dd1e333459643d3f9" - integrity sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA== - dependencies: - commander "~2.20.3" - source-map "~0.6.1" - - unherit@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.1.tgz#132748da3e88eab767e08fabfbb89c5e9d28628c" - integrity sha512-+XZuV691Cn4zHsK0vkKYwBEwB74T3IZIcxrgn2E4rKwTfFyI1zCh7X7grwh9Re08fdPlarIdyWgI8aVB3F5A5g== - dependencies: - inherits "^2.0.1" - xtend "^4.0.1" - - unified@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-7.1.0.tgz#5032f1c1ee3364bd09da12e27fdd4a7553c7be13" - integrity sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw== - dependencies: - "@types/unist" "^2.0.0" - "@types/vfile" "^3.0.0" - bail "^1.0.0" - extend "^3.0.0" - is-plain-obj "^1.1.0" - trough "^1.0.0" - vfile "^3.0.0" - x-is-string "^0.1.0" - - union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^0.4.3" - - uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - - unist-util-find-all-after@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-1.0.2.tgz#9be49cfbae5ca1566b27536670a92836bf2f8d6d" - integrity sha512-nDl79mKpffXojLpCimVXnxhlH/jjaTnDuScznU9J4jjsaUtBdDbxmlc109XtcqxY4SDO0SwzngsxxW8DIISt1w== - dependencies: - unist-util-is "^2.0.0" - - unist-util-is@^2.0.0, unist-util-is@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-2.1.2.tgz#1193fa8f2bfbbb82150633f3a8d2eb9a1c1d55db" - integrity sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw== - - unist-util-modify-children@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-modify-children/-/unist-util-modify-children-1.1.2.tgz#c7f1b91712554ee59c47a05b551ed3e052a4e2d1" - integrity sha512-GRi04yhng1WqBf5RBzPkOtWAadcZS2gvuOgNn/cyJBYNxtTuyYqTKN0eg4rC1YJwGnzrqfRB3dSKm8cNCjNirg== - dependencies: - array-iterate "^1.0.0" - - unist-util-remove-position@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.2.tgz#86b5dad104d0bbfbeb1db5f5c92f3570575c12cb" - integrity sha512-XxoNOBvq1WXRKXxgnSYbtCF76TJrRoe5++pD4cCBsssSiWSnPEktyFrFLE8LTk3JW5mt9hB0Sk5zn4x/JeWY7Q== - dependencies: - unist-util-visit "^1.1.0" - - unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" - integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== - - unist-util-visit-parents@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.0.1.tgz#63fffc8929027bee04bfef7d2cce474f71cb6217" - integrity sha512-6B0UTiMfdWql4cQ03gDTCSns+64Zkfo2OCbK31Ov0uMizEz+CJeAp0cgZVb5Fhmcd7Bct2iRNywejT0orpbqUA== - dependencies: - unist-util-is "^2.1.2" - - unist-util-visit@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.0.tgz#1cb763647186dc26f5e1df5db6bd1e48b3cc2fb1" - integrity sha512-FiGu34ziNsZA3ZUteZxSFaczIjGmksfSgdKqBfOejrrfzyUy5b7YrlzT1Bcvi+djkYDituJDy2XB7tGTeBieKw== - dependencies: - unist-util-visit-parents "^2.0.0" - - universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - - unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - - uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - - urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - - urlgrey@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" - integrity sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8= - - use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - - util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - - util.promisify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - - uuid@^3.1.0, uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - - validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" - integrity sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - - verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - - vfile-location@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.3.tgz#083ba80e50968e8d420be49dd1ea9a992131df77" - integrity sha512-zM5/l4lfw1CBoPx3Jimxoc5RNDAHHpk6AM6LM0pTIkm5SUSsx8ZekZ0PVdf0WEZ7kjlhSt7ZlqbRL6Cd6dBs6A== - - vfile-message@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.0.1.tgz#51a2ccd8a6b97a7980bb34efb9ebde9632e93677" - integrity sha512-vSGCkhNvJzO6VcWC6AlJW4NtYOVtS+RgCaqFIYUjoGIlHnFL+i0LbtYvonDWOMcB97uTPT4PRsyYY7REWC9vug== - dependencies: - unist-util-stringify-position "^1.1.1" - - vfile@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-3.0.1.tgz#47331d2abe3282424f4a4bb6acd20a44c4121803" - integrity sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ== - dependencies: - is-buffer "^2.0.0" - replace-ext "1.0.0" - unist-util-stringify-position "^1.0.0" - vfile-message "^1.0.0" - - vlq@^0.2.1: - version "0.2.3" - resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" - integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow== - - w3c-hr-time@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" - integrity sha1-gqwr/2PZUOqeMYmlimViX+3xkEU= - dependencies: - browser-process-hrtime "^0.1.2" - - walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= - dependencies: - makeerror "1.0.x" - - watch@~0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" - integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= - dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" - - webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - - whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" - integrity sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw== - dependencies: - iconv-lite "0.4.19" - - whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4" - integrity sha512-FKxhYLytBQiUKjkYteN71fAUA3g6KpNXoho1isLiLSB3N1G4F35Q5vUxWfKFhBwi5IWF27VE6WxhrnnC+m0Mew== - - whatwg-url@^6.4.0, whatwg-url@^6.4.1: - version "6.5.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" - integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - - which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - - which@^1.2.12, which@^1.2.9, which@^1.3.0, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - - wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - - wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= - - wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - - wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - - wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - - write-file-atomic@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" - integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - - write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - - ws@^5.2.0: - version "5.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" - integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== - dependencies: - async-limiter "~1.0.0" - - x-is-string@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" - integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= - - xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - - xtend@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= - - "y18n@^3.2.1 || ^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== - - yallist@^3.0.0, yallist@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" - integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k= - - yargs-parser@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - - yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - - yargs@^12.0.2: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index af5f274b..00000000 --- a/yarn.lock +++ /dev/null @@ -1,648 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@eslint/eslintrc@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" - integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.2.0" - globals "^13.9.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - -"@humanwhocodes/config-array@^0.9.2": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.3.tgz#f2564c744b387775b436418491f15fce6601f63e" - integrity sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" - integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -callsites@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" - integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== - -chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -debug@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-scope@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" - integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" - integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== - -eslint@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.7.0.tgz#22e036842ee5b7cf87b03fe237731675b4d3633c" - integrity sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w== - dependencies: - "@eslint/eslintrc" "^1.0.5" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.1.0" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.2.0" - espree "^9.3.0" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.6.0" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -esm@^3.2.25: - version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" - integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== - -espree@^9.2.0, espree@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.0.tgz#c1240d79183b72aaee6ccfa5a90bc9111df085a8" - integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== - dependencies: - acorn "^8.7.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.1.0" - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -glob-parent@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^13.6.0, globals@^13.9.0: - version "13.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" - integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== - dependencies: - type-fest "^0.20.2" - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -import-fresh@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" - integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-fresh@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-glob@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= - dependencies: - is-extglob "^2.1.1" - -is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -ms@2.1.2, ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -parent-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.0.tgz#df250bdc5391f4a085fb589dad761f5ad6b865b5" - integrity sha512-8Mf5juOMmiE4FcmzYc4IaiS9L3+9paz2KOiXzkRviCP6aDmN49Hz6EMWz0lGNp9pX80GvvAuLADtyGfW/Em3TA== - dependencies: - callsites "^3.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -rollup@^2.66.1: - version "2.66.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.66.1.tgz#366b0404de353c4331d538c3ad2963934fcb4937" - integrity sha512-crSgLhSkLMnKr4s9iZ/1qJCplgAgrRY+igWv8KhG/AjKOJ0YX/WpmANyn8oxrw+zenF3BXWDLa7Xl/QZISH+7w== - optionalDependencies: - fsevents "~2.3.2" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -terser@^5.10.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" - integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.20" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -v8-compile-cache@^2.0.3: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" - integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -xml-formatter@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/xml-formatter/-/xml-formatter-2.4.0.tgz#c956ea6c5345240c0829da86a5e81d44ed4cb9c7" - integrity sha512-xTQ2IfbkCQKn0DGN5SD5KUgTgVohWiolyOXTLUHKJczIuSeGonN0BPduB9VQR5HOEuT1KOHQsOHSmTpU76zpUA== - dependencies: - xml-parser-xo "^3.1.1" - -xml-parser-xo@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/xml-parser-xo/-/xml-parser-xo-3.1.1.tgz#a87d92e44fa8ad3ba7242517df96e6b0893f1f47" - integrity sha512-gq1nDlJxjKQpPPZUhLbJ52pghtlB4Rz6LAQULm3SF6xzOYVnUloBglNhJR9vtZB3vIxMN/R3nZTf3qmun+6GCg==